diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/bin/unshuffle_list.txt jdk18u-jdk-18.0.2.1-ga/bin/unshuffle_list.txt
--- jdk18u-jdk-18.0.2.1-ga.orig/bin/unshuffle_list.txt	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/bin/unshuffle_list.txt	2024-08-17 18:29:44.439929494 +0200
@@ -100,6 +100,7 @@
 src/langtools/sample : langtools/src/sample
 src/linux : jdk/src/linux
 src/sample : jdk/src/sample
+src/solaris : jdk/src/solaris
 src/hotspot/share : hotspot/src/share/vm
 src/hotspot/cpu/aarch64 : hotspot/src/cpu/aarch64/vm
 src/hotspot/cpu/arm : hotspot/src/cpu/arm/vm
@@ -112,6 +113,7 @@
 src/hotspot/os/linux : hotspot/src/os/linux/vm
 src/hotspot/os/posix/dtrace : hotspot/src/os/posix/dtrace
 src/hotspot/os/posix : hotspot/src/os/posix/vm
+src/hotspot/os/solaris : hotspot/src/os/solaris/vm
 src/hotspot/os/windows : hotspot/src/os/windows/vm
 src/hotspot/os_cpu/aix_ppc : hotspot/src/os_cpu/aix_ppc/vm
 src/hotspot/os_cpu/bsd_x86 : hotspot/src/os_cpu/bsd_x86/vm
@@ -122,6 +124,7 @@
 src/hotspot/os_cpu/linux_s390 : hotspot/src/os_cpu/linux_s390/vm
 src/hotspot/os_cpu/linux_x86 : hotspot/src/os_cpu/linux_x86/vm
 src/hotspot/os_cpu/linux_zero : hotspot/src/os_cpu/linux_zero/vm
+src/hotspot/os_cpu/solaris_x86 : hotspot/src/os_cpu/solaris_x86/vm
 src/hotspot/os_cpu/windows_x86 : hotspot/src/os_cpu/windows_x86/vm
 src/hotspot : hotspot/src
 src/utils/IdealGraphVisualizer : hotspot/src/share/tools/IdealGraphVisualizer
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/basic_tools.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/basic_tools.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/basic_tools.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/basic_tools.m4	2024-08-17 18:29:44.442520187 +0200
@@ -270,15 +270,23 @@
     TAR_TYPE="bsd"
   elif test "x$($TAR -v | $GREP "bsdtar")" != "x"; then
     TAR_TYPE="bsd"
+  elif test "x$OPENJDK_BUILD_OS" = "xsolaris"; then
+    TAR_TYPE="solaris"
   elif test "x$OPENJDK_BUILD_OS" = "xaix"; then
     TAR_TYPE="aix"
   fi
   AC_MSG_CHECKING([what type of tar was found])
   AC_MSG_RESULT([$TAR_TYPE])
 
+  TAR_CREATE_FILE_PARAM=""
+
   if test "x$TAR_TYPE" = "xgnu"; then
     TAR_INCLUDE_PARAM="T"
     TAR_SUPPORTS_TRANSFORM="true"
+    if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
+      # When using gnu tar for Solaris targets, need to use compatibility mode
+      TAR_CREATE_EXTRA_PARAM="--format=ustar"
+    fi
   elif test "x$TAR_TYPE" = "aix"; then
     # -L InputList of aix tar: name of file listing the files and directories
     # that need to be   archived or extracted
@@ -289,6 +297,7 @@
     TAR_SUPPORTS_TRANSFORM="false"
   fi
   AC_SUBST(TAR_TYPE)
+  AC_SUBST(TAR_CREATE_EXTRA_PARAM)
   AC_SUBST(TAR_INCLUDE_PARAM)
   AC_SUBST(TAR_SUPPORTS_TRANSFORM)
 ])
@@ -407,6 +416,8 @@
       fi
     fi
     UTIL_REQUIRE_PROGS(SETFILE, SetFile)
+  elif test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
+    UTIL_REQUIRE_PROGS(ELFEDIT, elfedit)
   fi
   if ! test "x$OPENJDK_TARGET_OS" = "xwindows"; then
     UTIL_REQUIRE_PROGS(ULIMIT, ulimit)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/build-aux/config.guess jdk18u-jdk-18.0.2.1-ga/make/autoconf/build-aux/config.guess
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/build-aux/config.guess	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/build-aux/config.guess	2024-08-17 18:29:44.442986322 +0200
@@ -42,6 +42,14 @@
   fi
 fi
 
+# Test and fix solaris on x86_64
+echo $OUT | grep i386-pc-solaris > /dev/null 2> /dev/null
+if test $? = 0; then
+  # isainfo -n returns either i386 or amd64
+  REAL_CPU=`isainfo -n`
+  OUT=$REAL_CPU`echo $OUT | sed -e 's/[^-]*//'`
+fi
+
 # Test and fix cygwin on x86_64
 echo $OUT | grep 86-pc-cygwin > /dev/null 2> /dev/null
 if test $? != 0; then
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/build-performance.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/build-performance.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/build-performance.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/build-performance.m4	2024-08-17 18:29:44.443522006 +0200
@@ -38,6 +38,10 @@
     if test "$NUM_CORES" -ne "0"; then
       FOUND_CORES=yes
     fi
+  elif test -x /usr/sbin/psrinfo; then
+    # Looks like a Solaris system
+    NUM_CORES=`/usr/sbin/psrinfo -v | grep -c on-line`
+    FOUND_CORES=yes
   elif test -x /usr/sbin/sysctl; then
     # Looks like a MacOSX system
     NUM_CORES=`/usr/sbin/sysctl -n hw.ncpu`
@@ -75,7 +79,7 @@
     MEMORY_SIZE=`expr $MEMORY_SIZE / 1024`
     FOUND_MEM=yes
   elif test -x /usr/sbin/prtconf; then
-    # Looks like an AIX system
+    # Looks like a Solaris or AIX system
     MEMORY_SIZE=`/usr/sbin/prtconf 2> /dev/null | grep "^Memory [[Ss]]ize" | awk '{ print [$]3 }'`
     FOUND_MEM=yes
   elif test -x /usr/sbin/sysctl; then
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/flags-cflags.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/flags-cflags.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/flags-cflags.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/flags-cflags.m4	2024-08-17 18:29:44.444186663 +0200
@@ -376,6 +376,9 @@
   if test "x$OPENJDK_TARGET_OS" = xlinux; then
     CFLAGS_OS_DEF_JVM="-DLINUX"
     CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_LARGEFILE64_SOURCE"
+  elif test "x$OPENJDK_TARGET_OS" = xsolaris; then
+    CFLAGS_OS_DEF_JVM="-DSOLARIS"
+    CFLAGS_OS_DEF_JDK="-D__solaris__"
   elif test "x$OPENJDK_TARGET_OS" = xmacosx; then
     CFLAGS_OS_DEF_JVM="-D_ALLBSD_SOURCE -D_DARWIN_C_SOURCE -D_XOPEN_SOURCE"
     CFLAGS_OS_DEF_JDK="-D_ALLBSD_SOURCE -D_DARWIN_UNLIMITED_SELECT"
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/flags-other.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/flags-other.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/flags-other.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/flags-other.m4	2024-08-17 18:29:44.444617050 +0200
@@ -51,6 +51,8 @@
   # FIXME: we should really only export STRIPFLAGS from here, not POST_STRIP_CMD.
   if test "x$OPENJDK_TARGET_OS" = xlinux; then
     STRIPFLAGS="-g"
+  elif test "x$OPENJDK_TARGET_OS" = xsolaris; then
+    STRIPFLAGS="-x"
   elif test "x$OPENJDK_TARGET_OS" = xmacosx; then
     STRIPFLAGS="-S"
   elif test "x$OPENJDK_TARGET_OS" = xaix; then
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/jdk-options.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/jdk-options.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/jdk-options.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/jdk-options.m4	2024-08-17 18:29:44.445274956 +0200
@@ -288,7 +288,7 @@
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
   elif test "x$with_native_debug_symbols" = xexternal; then
 
-    if test "x$OPENJDK_TARGET_OS" = xlinux; then
+    if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
       if test "x$OBJCOPY" = x; then
         # enabling of enable-debug-symbols and can't find objcopy
         # this is an error
@@ -301,7 +301,7 @@
     ZIP_EXTERNAL_DEBUG_SYMBOLS=false
   elif test "x$with_native_debug_symbols" = xzipped; then
 
-    if test "x$OPENJDK_TARGET_OS" = xlinux; then
+    if test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xlinux; then
       if test "x$OBJCOPY" = x; then
         # enabling of enable-debug-symbols and can't find objcopy
         # this is an error
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/lib-freetype.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/lib-freetype.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/lib-freetype.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/lib-freetype.m4	2024-08-17 18:29:44.445816402 +0200
@@ -53,6 +53,13 @@
     if ! test -s "$POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME"; then
       AC_MSG_NOTICE([Could not find $POTENTIAL_FREETYPE_LIB_PATH/$FREETYPE_LIB_NAME. Ignoring location.])
       FOUND_FREETYPE=no
+    else
+      if test "x$OPENJDK_TARGET_OS" = "xsolaris" \
+          && test -s "$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR/$FREETYPE_LIB_NAME"; then
+        # Found lib in isa dir, use that instead.
+        POTENTIAL_FREETYPE_LIB_PATH="$POTENTIAL_FREETYPE_LIB_PATH$OPENJDK_TARGET_CPU_ISADIR"
+        AC_MSG_NOTICE([Rewriting to use $POTENTIAL_FREETYPE_LIB_PATH instead])
+      fi
     fi
   fi
 
@@ -160,6 +167,15 @@
           if test "x$PKG_CONFIG" != "x" ; then
             PKG_CHECK_MODULES(FREETYPE, freetype2, [FOUND_FREETYPE=yes], [FOUND_FREETYPE=no])
             if test "x$FOUND_FREETYPE" = "xyes" ; then
+              # On solaris, pkg_check adds -lz to freetype libs, which isn't
+              # necessary for us.
+              FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's/-lz//g'`
+              # 64-bit libs for Solaris x86 are installed in the amd64
+              # subdirectory, change lib to lib/amd64
+              if test "x$OPENJDK_TARGET_OS" = "xsolaris" && \
+                  test "x$OPENJDK_TARGET_CPU" = "xx86_64" ; then
+                FREETYPE_LIBS=`$ECHO $FREETYPE_LIBS | $SED 's?/lib?/lib/amd64?g'`
+              fi
               AC_MSG_CHECKING([for freetype])
               AC_MSG_RESULT([yes (using pkg-config)])
             fi
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/libraries.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/libraries.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/libraries.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/libraries.m4	2024-08-17 18:29:44.446313096 +0200
@@ -112,13 +112,15 @@
   BASIC_JVM_LIBS="$LIBM"
 
   # Dynamic loading library
-  if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xaix; then
+  if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xsolaris || test "x$OPENJDK_TARGET_OS" = xaix; then
     BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBDL"
   fi
 
   # Threading library
   if test "x$OPENJDK_TARGET_OS" = xlinux || test "x$OPENJDK_TARGET_OS" = xaix; then
     BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lpthread"
+  elif test "x$OPENJDK_TARGET_OS" = xsolaris; then
+    BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lthread"
   fi
 
   # librt for legacy clock_gettime
@@ -149,6 +151,12 @@
     BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lperfstat"
   fi
 
+  if test "x$OPENJDK_TARGET_OS" = xsolaris; then
+    BASIC_JVM_LIBS="$BASIC_JVM_LIBS -lsocket -lsched -ldoor -lnsl \
+        -lrt -lkstat"
+    BASIC_JVM_LIBS="$BASIC_JVM_LIBS $LIBCXX_JVM"
+  fi
+
   if test "x$OPENJDK_TARGET_OS" = xwindows; then
     BASIC_JVM_LIBS="$BASIC_JVM_LIBS kernel32.lib user32.lib gdi32.lib winspool.lib \
         comdlg32.lib advapi32.lib shell32.lib ole32.lib oleaut32.lib uuid.lib \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/platform.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/platform.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/platform.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/platform.m4	2024-08-17 18:29:44.447025048 +0200
@@ -196,6 +196,10 @@
       VAR_OS=linux
       VAR_OS_TYPE=unix
       ;;
+    *solaris*)
+      VAR_OS=solaris
+      VAR_OS_TYPE=unix
+      ;;
     *darwin*)
       VAR_OS=macosx
       VAR_OS_TYPE=unix
@@ -466,6 +470,17 @@
   fi
   AC_SUBST(OPENJDK_$1_CPU_LEGACY_LIB)
 
+  # OPENJDK_$1_CPU_ISADIR is normally empty. On 64-bit Solaris systems, it is set to
+  # /amd64 or /sparcv9. This string is appended to some library paths, like this:
+  # /usr/lib${OPENJDK_$1_CPU_ISADIR}/libexample.so
+  OPENJDK_$1_CPU_ISADIR=""
+  if test "x$OPENJDK_$1_OS" = xsolaris; then
+    if test "x$OPENJDK_$1_CPU" = xx86_64; then
+      OPENJDK_$1_CPU_ISADIR="/amd64"
+    fi
+  fi
+  AC_SUBST(OPENJDK_$1_CPU_ISADIR)
+
   # Setup OPENJDK_$1_CPU_OSARCH, which is used to set the os.arch Java system property
   OPENJDK_$1_CPU_OSARCH="$OPENJDK_$1_CPU"
   if test "x$OPENJDK_$1_OS" = xlinux && test "x$OPENJDK_$1_CPU" = xx86; then
@@ -593,6 +608,9 @@
 
 AC_DEFUN([PLATFORM_SET_RELEASE_FILE_OS_VALUES],
 [
+  if test "x$OPENJDK_TARGET_OS" = "xsolaris"; then
+    RELEASE_FILE_OS_NAME=SunOS
+  fi
   if test "x$OPENJDK_TARGET_OS" = "xlinux"; then
     RELEASE_FILE_OS_NAME=Linux
   fi
@@ -648,9 +666,25 @@
   PLATFORM_SET_MODULE_TARGET_OS_VALUES
   PLATFORM_SET_RELEASE_FILE_OS_VALUES
   PLATFORM_SETUP_LEGACY_VARS
+  PLATFORM_CHECK_DEPRECATION
+])
 
-  # Deprecated in JDK 15
-  UTIL_DEPRECATED_ARG_ENABLE(deprecated-ports)
+AC_DEFUN([PLATFORM_CHECK_DEPRECATION],
+[
+  UTIL_ARG_ENABLE(NAME: deprecated-ports, DEFAULT: false,
+      RESULT: ENABLE_DEPRECATED_PORTS,
+      DESC: [suppress the error when configuring for a deprecated port])
+
+  if test "x$OPENJDK_TARGET_OS" = xsolaris || \
+      (test "x$OPENJDK_TARGET_CPU_ARCH" = xsparc && \
+      test "x$with_jvm_variants" != xzero); then
+    if test "x$ENABLE_DEPRECATED_PORTS" = "xtrue"; then
+      AC_MSG_WARN([The Solaris and SPARC ports are deprecated and may be removed in a future release.])
+    else
+      AC_MSG_ERROR(m4_normalize([The Solaris and SPARC ports are deprecated and may be removed in a
+        future release. Use --enable-deprecated-ports=yes to suppress this error.]))
+    fi
+  fi
 ])
 
 AC_DEFUN_ONCE([PLATFORM_SETUP_OPENJDK_BUILD_OS_VERSION],
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/spec.gmk.in jdk18u-jdk-18.0.2.1-ga/make/autoconf/spec.gmk.in
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/spec.gmk.in	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/spec.gmk.in	2024-08-17 18:29:44.447708361 +0200
@@ -88,6 +88,7 @@
 COMPILE_TYPE:=@COMPILE_TYPE@
 
 # Legacy support
+OPENJDK_TARGET_CPU_ISADIR:=@OPENJDK_TARGET_CPU_ISADIR@
 OPENJDK_TARGET_CPU_LEGACY:=@OPENJDK_TARGET_CPU_LEGACY@
 OPENJDK_TARGET_CPU_LEGACY_LIB:=@OPENJDK_TARGET_CPU_LEGACY_LIB@
 OPENJDK_TARGET_CPU_OSARCH:=@OPENJDK_TARGET_CPU_OSARCH@
@@ -753,6 +754,7 @@
 LDD:=@LDD@
 OTOOL:=@OTOOL@
 READELF:=@READELF@
+ELFEDIT:=@ELFEDIT@
 EXPR:=@EXPR@
 FILE:=@FILE@
 DOT:=@DOT@
@@ -770,6 +772,7 @@
 ULIMIT:=@ULIMIT@
 
 TAR_TYPE:=@TAR_TYPE@
+TAR_CREATE_EXTRA_PARAM:=@TAR_CREATE_EXTRA_PARAM@
 TAR_INCLUDE_PARAM:=@TAR_INCLUDE_PARAM@
 TAR_SUPPORTS_TRANSFORM:=@TAR_SUPPORTS_TRANSFORM@
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/toolchain.m4 jdk18u-jdk-18.0.2.1-ga/make/autoconf/toolchain.m4
--- jdk18u-jdk-18.0.2.1-ga.orig/make/autoconf/toolchain.m4	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/autoconf/toolchain.m4	2024-08-17 18:29:44.448401737 +0200
@@ -39,6 +39,7 @@
 
 # These toolchains are valid on different platforms
 VALID_TOOLCHAINS_linux="gcc clang"
+VALID_TOOLCHAINS_solaris="gcc"
 VALID_TOOLCHAINS_macosx="gcc clang"
 VALID_TOOLCHAINS_aix="xlc"
 VALID_TOOLCHAINS_windows="microsoft"
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/Bundles.gmk jdk18u-jdk-18.0.2.1-ga/make/Bundles.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/Bundles.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/Bundles.gmk	2024-08-17 18:29:44.440819644 +0200
@@ -101,7 +101,7 @@
           # If no subdir is specified and only one BASE_DIR, tar.gz can be done
           # directly from BASE_DIR.
 	  $(CD) $$($1_BASE_DIRS) \
-	      && ( $(TAR) cf - \
+	      && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
 	          -$(TAR_INCLUDE_PARAM) $$($1_$$($1_BASE_DIRS)_LIST_FILE) \
 	          $(TAR_IGNORE_EXIT_VALUE) ) \
 	      | $(GZIP) > $$@
@@ -110,7 +110,7 @@
           # If only one BASE_DIR, but with a SUBDIR set, tar.gz can use the
           # transform option to create bundle directly from the BASE_DIR.
 	  $(CD) $$($1_BASE_DIRS) \
-	      && ( $(TAR) cf - \
+	      && ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
 	          -$(TAR_INCLUDE_PARAM) $$($1_$$($1_BASE_DIRS)_LIST_FILE) \
 	          $$(if $$($1_SUBDIR), --transform 's|^|$$($1_SUBDIR)/|S') \
 	          $(TAR_IGNORE_EXIT_VALUE) ) \
@@ -140,7 +140,7 @@
           endif
           ifeq ($$($1_TYPE), tar.gz)
 	    $(CD) $(SUPPORT_OUTPUTDIR)/bundles/$1 && \
-	    ( $(TAR) cf - \
+	    ( $(TAR) cf - $(TAR_CREATE_EXTRA_PARAM) \
 	        $$(if $$($1_SUBDIR), $$($1_SUBDIR), .) $(TAR_IGNORE_EXIT_VALUE) ) \
 	    | $(GZIP) > $$@
           else ifeq ($$($1_TYPE), zip)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/common/MakeBase.gmk jdk18u-jdk-18.0.2.1-ga/make/common/MakeBase.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/common/MakeBase.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/common/MakeBase.gmk	2024-08-17 18:29:44.449004782 +0200
@@ -264,7 +264,33 @@
 ################################################################################
 # All install-file and related macros automatically call DecodeSpace when needed.
 
-ifeq ($(call isTargetOs, macosx), true)
+ifeq ($(call isTargetOs, solaris), true)
+  # On Solaris, if the target is a symlink and exists, cp won't overwrite.
+  # Cp has to operate in recursive mode to allow for -P flag, to preserve soft links. If the
+  # name of the target file differs from the source file, rename after copy.
+  # If the source and target parent directories are the same, recursive copy doesn't work
+  # so we fall back on regular copy, which isn't preserving symlinks.
+  define install-file
+	$(call MakeTargetDir)
+	$(RM) '$(call DecodeSpace, $@)'
+	if [ '$(call DecodeSpace, $(dir $(call EncodeSpace, $@)))' != \
+	    '$(call DecodeSpace, $(dir $(call EncodeSpace, $<)))' ]; then \
+	  $(CP) -f -r -P '$(call DecodeSpace, $<)' \
+	      '$(call DecodeSpace, $(dir $(call EncodeSpace, $@)))'; \
+	  if [ '$(call DecodeSpace, $(notdir $(call EncodeSpace, $@)))' != \
+	      '$(call DecodeSpace, $(notdir $(call EncodeSpace, $(<))))' ]; then \
+	    $(MV) '$(call DecodeSpace, $(dir $(call EncodeSpace, $@))/$(notdir $(call EncodeSpace, $<)))' \
+	        '$(call DecodeSpace, $@)'; \
+	  fi; \
+	else \
+	  if [ -L '$(call DecodeSpace, $<)' ]; then \
+	    $(ECHO) "Source file is a symlink and target is in the same directory: $< $@" ; \
+	    exit 1; \
+	  fi; \
+	  $(CP) -f '$(call DecodeSpace, $<)' '$(call DecodeSpace, $@)'; \
+	fi
+  endef
+else ifeq ($(call isTargetOs, macosx), true)
   # On mac, extended attributes sometimes creep into the source files, which may later
   # cause the creation of ._* files which confuses testing. Clear these with xattr if
   # set. Some files get their write permissions removed after being copied to the
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/common/modules/LauncherCommon.gmk jdk18u-jdk-18.0.2.1-ga/make/common/modules/LauncherCommon.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/common/modules/LauncherCommon.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/common/modules/LauncherCommon.gmk	2024-08-17 18:29:44.450299599 +0200
@@ -150,6 +150,7 @@
           -DLAUNCHER_NAME='"$$(LAUNCHER_NAME)"' \
           -DPROGNAME='"$1"' \
           $$($1_CFLAGS), \
+      CFLAGS_solaris := -fPIC, \
       CFLAGS_windows := $$($1_CFLAGS_windows), \
       DISABLED_WARNINGS_gcc := unused-function, \
       LDFLAGS := $$(LDFLAGS_JDKEXE) \
@@ -159,11 +160,14 @@
           -L$(call FindLibDirForModule, java.base), \
       LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \
           -L$(call FindLibDirForModule, java.base), \
+      LDFLAGS_solaris := $$(call SET_EXECUTABLE_ORIGIN,/../lib) \
+          -L$(call FindLibDirForModule, java.base), \
       LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
       LIBS := $(JDKEXE_LIBS) $$($1_LIBS), \
       LIBS_linux := -ljli -lpthread $(LIBDL), \
       LIBS_macosx := -ljli -framework Cocoa -framework Security \
           -framework ApplicationServices, \
+      LIBS_solaris := -ljli -lthread $(LIBDL), \
       LIBS_aix := -ljli_static, \
       LIBS_windows := $$($1_WINDOWS_JLI_LIB) \
           $(SUPPORT_OUTPUTDIR)/native/java.base/libjava/java.lib, \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/common/NativeCompilation.gmk jdk18u-jdk-18.0.2.1-ga/make/common/NativeCompilation.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/common/NativeCompilation.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/common/NativeCompilation.gmk	2024-08-17 18:29:44.449763061 +0200
@@ -969,7 +969,7 @@
           $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).pdb \
               $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).map
 
-        else ifeq ($(call isTargetOs, linux), true)
+        else ifeq ($(call isTargetOs, linux solaris), true)
           $1_DEBUGINFO_FILES := $$($1_SYMBOLS_DIR)/$$($1_NOSUFFIX).debuginfo
           # Setup the command line creating debuginfo files, to be run after linking.
           # It cannot be run separately since it updates the original target file
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/data/fontconfig/solaris.fontconfig.properties jdk18u-jdk-18.0.2.1-ga/make/data/fontconfig/solaris.fontconfig.properties
--- jdk18u-jdk-18.0.2.1-ga.orig/make/data/fontconfig/solaris.fontconfig.properties	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/data/fontconfig/solaris.fontconfig.properties	2024-08-17 18:29:44.534312043 +0200
@@ -0,0 +1,516 @@
+#
+#
+# Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+# Version
+
+version=1
+
+# Component Font Mappings
+
+allfonts.chinese-gb2312=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-gbk=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-gb18030-0=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-gb18030-1=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-cns11643-1=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-cns11643-2=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-cns11643-3=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-big5=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.chinese-hkscs=-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.dingbats=-microsoft-wingdings-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific
+allfonts.japanese-x0212=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.korean=-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.korean-johab=-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+allfonts.symbol=-monotype-symbol-medium-r-normal--*-%d-*-*-p-*-adobe-symbol
+allfonts.bengali=-misc-lohit bengali-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.gujarati=-misc-lohit gujarati-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.hindi=-misc-lohit hindi-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.kannada=-misc-lohit kannada-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.malayalam=-misc-lohit malayalam-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.marathi=-misc-lohit marathi-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.tamil=-misc-lohit tamil-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.telugu=-misc-lohit telugu-medium-r-normal--0-0-0-0-p-0-iso10646-1
+allfonts.dejavusans=-misc-dejavu sans-medium-r-normal--0-0-0-0-p-0-iso10646-1
+
+serif.plain.arabic=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.cyrillic-iso8859-5=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.cyrillic-cp1251=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.cyrillic-koi8-r=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.greek=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.hebrew=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.plain.latin-1=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.latin-2=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.latin-5=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.latin-7=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.latin-9=-monotype-times new roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.plain.thai=-monotype-angsana new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+
+serif.bold.arabic=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.cyrillic-iso8859-5=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.cyrillic-cp1251=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.cyrillic-koi8-r=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.greek=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.hebrew=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.bold.latin-1=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.latin-2=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.latin-5=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.latin-7=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.latin-9=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bold.thai=-monotype-angsana new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+
+serif.italic.arabic=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.cyrillic-iso8859-5=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.cyrillic-cp1251=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.cyrillic-koi8-r=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.greek=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.hebrew=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.italic.latin-1=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.latin-2=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.latin-5=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.latin-7=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.latin-9=-monotype-times new roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.italic.thai=-monotype-angsana new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+
+serif.bolditalic.arabic=-monotype-times new roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.cyrillic-iso8859-5=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.cyrillic-cp1251=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.cyrillic-koi8-r=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.greek=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.hebrew=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+serif.bolditalic.latin-1=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.latin-2=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.latin-5=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.latin-7=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.latin-9=-monotype-times new roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+serif.bolditalic.thai=-monotype-angsana new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+
+sansserif.plain.arabic=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.cyrillic-iso8859-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.cyrillic-cp1251=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.cyrillic-koi8-r=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.greek=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.hebrew=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.plain.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.plain.latin-1=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.latin-2=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.latin-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.latin-7=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.latin-9=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.plain.thai=-monotype-browallia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+
+sansserif.bold.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.cyrillic-iso8859-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.cyrillic-cp1251=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.cyrillic-koi8-r=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.greek=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.hebrew=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.bold.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.bold.latin-1=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.latin-2=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.latin-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.latin-7=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.latin-9=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bold.thai=-monotype-browallia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+
+sansserif.italic.arabic=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.cyrillic-iso8859-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.cyrillic-cp1251=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.cyrillic-koi8-r=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.greek=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.hebrew=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.italic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.italic.latin-1=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.latin-2=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.latin-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.latin-7=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.latin-9=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.italic.thai=-monotype-browallia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+
+sansserif.bolditalic.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.cyrillic-iso8859-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.cyrillic-cp1251=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.cyrillic-koi8-r=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.greek=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.hebrew=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.bolditalic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+sansserif.bolditalic.latin-1=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.latin-2=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.latin-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.latin-7=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.latin-9=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+sansserif.bolditalic.thai=-monotype-browallia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+
+monospaced.plain.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.cyrillic-iso8859-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.cyrillic-cp1251=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.cyrillic-koi8-r=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.greek=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.hebrew=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.plain.latin-1=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.latin-2=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.latin-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.latin-7=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.latin-9=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.plain.thai=-monotype-cordia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+
+monospaced.bold.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.cyrillic-iso8859-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.cyrillic-cp1251=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.cyrillic-koi8-r=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.greek=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.hebrew=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.bold.latin-1=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.latin-2=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.latin-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.latin-7=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.latin-9=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bold.thai=-monotype-cordia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+
+monospaced.italic.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.cyrillic-iso8859-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.cyrillic-cp1251=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.cyrillic-koi8-r=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.greek=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.hebrew=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.italic.latin-1=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.latin-2=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.latin-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.latin-7=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.latin-9=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.italic.thai=-monotype-cordia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+
+monospaced.bolditalic.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.cyrillic-iso8859-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.cyrillic-cp1251=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.cyrillic-koi8-r=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.greek=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.hebrew=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+monospaced.bolditalic.latin-1=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.latin-2=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.latin-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.latin-7=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.latin-9=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+monospaced.bolditalic.thai=-monotype-cordia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+
+dialog.plain.arabic=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.cyrillic-iso8859-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.cyrillic-cp1251=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.cyrillic-koi8-r=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.greek=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.hebrew=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.plain.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.plain.latin-1=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.latin-2=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.latin-5=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.latin-7=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.latin-9=-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.plain.thai=-monotype-browallia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+
+dialog.bold.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.cyrillic-iso8859-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.cyrillic-cp1251=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.cyrillic-koi8-r=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.greek=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.hebrew=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.bold.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.bold.latin-1=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.latin-2=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.latin-5=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.latin-7=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.latin-9=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bold.thai=-monotype-browallia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+
+dialog.italic.arabic=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.cyrillic-iso8859-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.cyrillic-cp1251=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.cyrillic-koi8-r=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.greek=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.hebrew=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.italic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.italic.latin-1=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.latin-2=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.latin-5=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.latin-7=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.latin-9=-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.italic.thai=-monotype-browallia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+
+dialog.bolditalic.arabic=-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.cyrillic-iso8859-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.cyrillic-cp1251=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.cyrillic-koi8-r=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.greek=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.hebrew=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.japanese-x0201=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.bolditalic.japanese-x0208=-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialog.bolditalic.latin-1=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.latin-2=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.latin-5=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.latin-7=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.latin-9=-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialog.bolditalic.thai=-monotype-browallia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+
+dialoginput.plain.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.cyrillic-iso8859-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.cyrillic-cp1251=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.cyrillic-koi8-r=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.greek=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.hebrew=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.plain.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.plain.latin-1=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.latin-2=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.latin-5=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.latin-7=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.latin-9=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.plain.thai=-monotype-cordia new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+
+dialoginput.bold.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.cyrillic-iso8859-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.cyrillic-cp1251=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.cyrillic-koi8-r=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.greek=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.hebrew=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.bold.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.bold.latin-1=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.latin-2=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.latin-5=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.latin-7=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.latin-9=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bold.thai=-monotype-cordia new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+
+dialoginput.italic.arabic=-monotype-courier new-medium-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.cyrillic-iso8859-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.cyrillic-cp1251=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.cyrillic-koi8-r=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.greek=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.hebrew=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.italic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.italic.latin-1=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.latin-2=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.latin-5=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.latin-7=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.latin-9=-monotype-courier new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.italic.thai=-monotype-cordia new-medium-i-normal--*-%d-*-*-p-*-iso10646-1
+
+dialoginput.bolditalic.arabic=-monotype-courier new-bold-r-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.cyrillic-iso8859-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.cyrillic-cp1251=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.cyrillic-koi8-r=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.greek=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.hebrew=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.japanese-x0201=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.bolditalic.japanese-x0208=-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1
+dialoginput.bolditalic.latin-1=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.latin-2=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.latin-5=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.latin-7=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.latin-9=-monotype-courier new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+dialoginput.bolditalic.thai=-monotype-cordia new-bold-i-normal--*-%d-*-*-p-*-iso10646-1
+
+# Search Sequences
+
+sequence.allfonts=latin-1
+
+sequence.allfonts.Big5=latin-1,chinese-big5
+
+sequence.allfonts.Big5-HKSCS-2001=latin-1,chinese-big5,chinese-hkscs
+
+sequence.allfonts.windows-1251=cyrillic-cp1251,latin-1
+
+sequence.allfonts.GB2312=latin-1,chinese-gb2312
+
+sequence.allfonts.x-eucJP-Open=latin-1,japanese-x0201,japanese-x0208,japanese-x0212
+
+sequence.allfonts.EUC-KR=latin-1,korean
+
+sequence.allfonts.x-EUC-TW=latin-1,chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3
+
+sequence.allfonts.GBK=latin-1,chinese-gbk
+
+sequence.allfonts.GB18030=latin-1,chinese-gb18030-0,chinese-gb18030-1
+
+sequence.allfonts.ISO-8859-2=latin-2,latin-1
+
+sequence.allfonts.ISO-8859-5=cyrillic-iso8859-5,latin-1
+
+sequence.allfonts.ISO-8859-6=arabic,latin-1
+
+sequence.allfonts.ISO-8859-7=latin-1,greek
+
+sequence.allfonts.ISO-8859-8=latin-1,hebrew
+
+sequence.allfonts.ISO-8859-9=latin-5,latin-1
+
+sequence.allfonts.ISO-8859-13=latin-7,latin-1
+
+sequence.allfonts.ISO-8859-15=latin-9
+
+sequence.allfonts.KOI8-R=cyrillic-koi8-r,latin-1
+
+sequence.allfonts.x-PCK=latin-1,japanese-x0201,japanese-x0208,japanese-x0212
+
+sequence.allfonts.TIS-620=latin-1,thai
+
+sequence.allfonts.UTF-8=latin-1
+sequence.allfonts.UTF-8.en=latin-1
+sequence.allfonts.UTF-8.hi=latin-1,hindi
+sequence.allfonts.UTF-8.be=latin-1,bengali
+sequence.allfonts.UTF-8.te=latin-1,telugu
+sequence.allfonts.UTF-8.mr=latin-1,marathi
+sequence.allfonts.UTF-8.ta=latin-1,tamil
+sequence.allfonts.UTF-8.gu=latin-1,gujarati
+sequence.allfonts.UTF-8.kn=latin-1,kannada
+sequence.allfonts.UTF-8.ma=latin-1,malayalam
+
+sequence.allfonts.UTF-8.ko=latin-1,korean-johab,japanese-x0201,japanese-x0208,japanese-x0212
+
+sequence.allfonts.UTF-8.th=latin-1,thai
+
+sequence.allfonts.UTF-8.zh.CN=latin-1,chinese-gb18030-0,chinese-gb18030-1,chinese-big5,chinese-hkscs
+
+sequence.allfonts.UTF-8.zh.HK=latin-1,chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1
+
+sequence.allfonts.UTF-8.zh.TW=latin-1,chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1
+
+# the fallback sequence omits the following character subsets:
+# - chinese: all same file : just use chinese-gb18030-0
+# - japanese-x0208: same files as japanese-x0201
+# - japanese-x0212: same files as japanese-x0201
+# - korean: same file as korean-johab
+sequence.fallback=latin-1,latin-2,latin-7,cyrillic-iso8859-5,greek,latin-5,latin-9,\
+        arabic,hebrew,thai,\
+        chinese-gb18030-0,\
+        japanese-x0201,korean-johab,\
+        hindi,bengali,telugu,marathi,tamil,gujarati,kannada,malayalam,\
+        dejavusans,dingbats,symbol
+
+# Font File Names
+
+filename.-monotype-arial-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arial.ttf
+filename.-monotype-arial-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/ariali.ttf
+filename.-monotype-arial-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbd.ttf
+filename.-monotype-arial-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/arialbi.ttf
+filename.-monotype-courier_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cour.ttf
+filename.-monotype-courier_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/couri.ttf
+filename.-monotype-courier_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbd.ttf
+filename.-monotype-courier_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/courbi.ttf
+filename.-monotype-times_new_roman-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/times.ttf
+filename.-monotype-times_new_roman-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesi.ttf
+filename.-monotype-times_new_roman-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbd.ttf
+filename.-monotype-times_new_roman-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/timesbi.ttf
+
+filename.-monotype-angsana_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsa.ttf
+filename.-monotype-angsana_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsai.ttf
+filename.-monotype-angsana_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsab.ttf
+filename.-monotype-angsana_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/angsaz.ttf
+filename.-monotype-browallia_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browa.ttf
+filename.-monotype-browallia_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browai.ttf
+filename.-monotype-browallia_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browab.ttf
+filename.-monotype-browallia_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/browaz.ttf
+filename.-monotype-cordia_new-medium-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordia.ttf
+filename.-monotype-cordia_new-medium-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiai.ttf
+filename.-monotype-cordia_new-bold-r-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiab.ttf
+filename.-monotype-cordia_new-bold-i-normal--*-%d-*-*-p-*-iso10646-1=/usr/share/fonts/TrueType/core/cordiaz.ttf
+
+filename.-misc-ipagothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/ipafont/ipag.otf
+filename.-misc-ipamincho-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/ipafont/ipam.otf
+filename.-hanyang-gothic-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/hanyang/h2gtrm.ttf
+filename.-arphic-uming-medium-r-normal--*-%d-*-*-m-*-iso10646-1=/usr/share/fonts/TrueType/arphic/uming.ttf
+filename.-monotype-symbol-medium-r-normal--*-%d-*-*-p-*-adobe-symbol=/usr/share/fonts/TrueType/core/symbol.ttf
+filename.-microsoft-wingdings-medium-r-normal--*-%d-*-*-p-*-adobe-fontspecific=/usr/share/fonts/TrueType/core/wingdings.ttf
+filename.-misc-lohit_bengali-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Bengali.ttf
+filename.-misc-lohit_gujarati-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Gujarati.ttf
+filename.-misc-lohit_hindi-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Hindi.ttf
+filename.-misc-lohit_kannada-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Kannada.ttf
+filename.-misc-lohit_malayalam-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Malayalam.ttf
+filename.-misc-lohit_marathi-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Marathi.ttf
+filename.-misc-lohit_tamil-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Tamil.ttf
+filename.-misc-lohit_telugu-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/lohit/Lohit-Telugu.ttf
+filename.-misc-dejavu_sans-medium-r-normal--0-0-0-0-p-0-iso10646-1=/usr/share/fonts/TrueType/dejavu/DejaVuSans.ttf
+
+# AWT X11 font paths
+awtfontpath.latin-1=/usr/share/fonts/TrueType/core
+awtfontpath.latin-2=/usr/share/fonts/TrueType/core
+awtfontpath.latin-5=/usr/share/fonts/TrueType/core
+awtfontpath.latin-7=/usr/share/fonts/TrueType/core
+awtfontpath.latin-9=/usr/share/fonts/TrueType/core
+awtfontpath.hebrew=/usr/share/fonts/TrueType/core
+awtfontpath.arabic=/usr/share/fonts/TrueType/core
+awtfontpath.thai=/usr/share/fonts/TrueType/core
+awtfontpath.greek=/usr/share/fonts/TrueType/core
+awtfontpath.cyrillic-iso8859-5=/usr/share/fonts/TrueType/core
+awtfontpath.cyrillic-cp1251=/usr/share/fonts/TrueType/core
+awtfontpath.cyrillic-koi8-r=/usr/share/fonts/TrueType/core
+awtfontpath.korean=/usr/share/fonts/TrueType/hanyang
+awtfontpath.korean-johab=/usr/share/fonts/TrueType/hanyang
+awtfontpath.japanese-x0201=/usr/share/fonts/TrueType/ipafont
+awtfontpath.japanese-x0208=/usr/share/fonts/TrueType/ipafont
+awtfontpath.japanese-x0212=/usr/share/fonts/TrueType/ipafont
+awtfontpath.chinese-gbk=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-cns11643-1=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-cns11643-2=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-cns11643-3=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-big5=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-gb2312=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-gb18030-0=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-gb18030-1=/usr/share/fonts/TrueType/arphic
+awtfontpath.chinese-hkscs=/usr/share/fonts/TrueType/arphic
+awtfontpath.bengali=/usr/share/fonts/TrueType/lohit
+awtfontpath.gujarati=/usr/share/fonts/TrueType/lohit
+awtfontpath.hindi=/usr/share/fonts/TrueType/lohit
+awtfontpath.kannada=/usr/share/fonts/TrueType/lohit
+awtfontpath.malayalam=/usr/share/fonts/TrueType/lohit
+awtfontpath.marathi=/usr/share/fonts/TrueType/lohit
+awtfontpath.tamil=/usr/share/fonts/TrueType/lohit
+awtfontpath.telugu=/usr/share/fonts/TrueType/lohit
+awtfontpath.dejavusans=/usr/share/fonts/TrueType/dejavu
+
+# Appended Font Path
+
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/gensrc/GensrcAdlc.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/gensrc/GensrcAdlc.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/gensrc/GensrcAdlc.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/gensrc/GensrcAdlc.gmk	2024-08-17 18:29:44.450878483 +0200
@@ -36,6 +36,9 @@
   # NOTE: No optimization or debug flags set here
   ifeq ($(call isBuildOs, linux), true)
     ADLC_CFLAGS := -fno-exceptions -DLINUX
+  else ifeq ($(call isBuildOs, solaris), true)
+    ADLC_LDFLAGS := -m64
+    ADLC_CFLAGS := -m64 -fpermissive
   else ifeq ($(call isBuildOs, aix), true)
     ADLC_LDFLAGS += -q64
     ADLC_CFLAGS := -qnortti -qeh -q64 -DAIX
@@ -84,6 +87,8 @@
   # ADLC flags depending on target OS
   ifeq ($(call isTargetOs, linux), true)
     ADLCFLAGS += -DLINUX=1 -D_GNU_SOURCE=1
+  else ifeq ($(call isTargetOs, solaris), true)
+    ADLCFLAGS += -DSOLARIS=1
   else ifeq ($(call isTargetOs, aix), true)
     ADLCFLAGS += -DAIX=1
   else ifeq ($(call isTargetOs, macosx), true)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/gensrc/GensrcDtrace.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/gensrc/GensrcDtrace.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/gensrc/GensrcDtrace.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/gensrc/GensrcDtrace.gmk	2024-08-17 18:29:44.451377066 +0200
@@ -28,7 +28,10 @@
 
 ifeq ($(call check-jvm-feature, dtrace), true)
 
-  ifeq ($(call isTargetOs, macosx), true)
+  ifeq ($(call isTargetOs, solaris), true)
+    DTRACE_FLAGS := -64
+    DTRACE_CPP_FLAGS := -D_LP64 -x c
+  else ifeq ($(call isTargetOs, macosx), true)
     DTRACE_CPP_FLAGS := -D_LP64 -x c
   else ifeq ($(call isTargetOs, linux), true)
     DTRACE_CPP_FLAGS := -x c
@@ -51,4 +54,59 @@
   TARGETS += $(patsubst $(DTRACE_SOURCE_DIR)/%.d, \
       $(DTRACE_GENSRC_DIR)/%.h, $(wildcard $(DTRACE_SOURCE_DIR)/*.d))
 
+  ifeq ($(call isTargetOs, solaris), true)
+    ############################################################################
+    # First we need to generate the dtraceGenOffsets tool. When run, this will
+    # produce two header files and a C++ file. Note that generateJvmOffsets.cpp
+    # is using the same JVM_CFLAGS as libjvm.so.
+
+    # Include support files that will setup JVM compiler flags.
+    include lib/JvmFeatures.gmk
+    include lib/JvmFlags.gmk
+
+    # We cannot compile until the JVMTI and JFR gensrc has finished.
+    # JFR_FILES is defined in GensrcJfr.gmk.
+    JVMTI_H := $(JVM_VARIANT_OUTPUTDIR)/gensrc/jvmtifiles/jvmti.h
+
+    $(eval $(call SetupNativeCompilation, BUILD_DTRACE_GEN_OFFSETS, \
+        NAME := dtraceGenOffsets, \
+        TYPE := EXECUTABLE, \
+        SRC := $(TOPDIR)/make/hotspot/src/native/dtrace, \
+        TOOLCHAIN := $(TOOLCHAIN_BUILD), \
+        LDFLAGS := -m64, \
+        CFLAGS := -m64 $(JVM_CFLAGS), \
+        EXTRA_DEPS := $(JVMTI_H) $(JFR_FILES), \
+        OBJECT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets/objs, \
+        OUTPUT_DIR := $(JVM_VARIANT_OUTPUTDIR)/tools/dtrace-gen-offsets, \
+    ))
+
+    DTRACE_GEN_OFFSETS_TOOL := $(BUILD_DTRACE_GEN_OFFSETS_TARGET)
+
+    # Argument 1: Output filename
+    # Argument 2: dtrace-gen-offset tool command line option
+    define SetupDtraceOffsetsGeneration
+      $$(eval $$(call SetupExecute, dtrace_offset_$$(strip $2), \
+          INFO := Generating dtrace $2 file, \
+          DEPS := $$(BUILD_DTRACE_GEN_OFFSETS), \
+          OUTPUT_FILE := $1, \
+          COMMAND := ( $$(DTRACE_GEN_OFFSETS_TOOL) -$$(strip $2) > $1 ), \
+      ))
+
+      TARGETS += $$(dtrace_offset_$$(strip $2)_TARGET)
+    endef
+
+    JVM_OFFSETS_H := $(DTRACE_GENSRC_DIR)/JvmOffsets.h
+    JVM_OFFSETS_CPP := $(DTRACE_GENSRC_DIR)/JvmOffsets.cpp
+    JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
+
+    ############################################################################
+    # Run the dtrace-gen-offset tool to generate these three files.
+    # The generated JvmOffsets.cpp is compiled with the rest of libjvm.
+    # The header files are used by libjvm_db and jhelper.d, respectively.
+
+    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_H), header))
+    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_INDEX_H), index))
+    $(eval $(call SetupDtraceOffsetsGeneration, $(JVM_OFFSETS_CPP), table))
+  endif
+
 endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/CompileDtraceLibraries.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/CompileDtraceLibraries.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/CompileDtraceLibraries.gmk	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/CompileDtraceLibraries.gmk	2024-08-17 18:29:44.534657118 +0200
@@ -0,0 +1,62 @@
+#
+# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+ifeq ($(call check-jvm-feature, dtrace), true)
+  ifeq ($(call isTargetOs, solaris), true)
+    JNI_INCLUDE_FLAGS := \
+        -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base \
+        -I$(SUPPORT_OUTPUTDIR)/modules_include/java.base/$(OPENJDK_TARGET_OS_INCLUDE_SUBDIR) \
+        #
+
+    ############################################################################
+    # Build the stand-alone dtrace libraries.
+
+    LIBJVM_DTRACE_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_dtrace
+    $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DTRACE, \
+        NAME := jvm_dtrace, \
+        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
+        SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_dtrace, \
+        CFLAGS := $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \
+        LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
+        LIBS := $(LIBDL) -lthread -ldoor, \
+        OBJECT_DIR := $(LIBJVM_DTRACE_OUTPUTDIR)/objs, \
+    ))
+
+    # Note that libjvm_db.c has tests for COMPILER2, but this was never set by
+    # the old build.
+    LIBJVM_DB_OUTPUTDIR := $(JVM_VARIANT_OUTPUTDIR)/libjvm_db
+    $(eval $(call SetupNativeCompilation, BUILD_LIBJVM_DB, \
+        NAME := jvm_db, \
+        OUTPUT_DIR := $(JVM_LIB_OUTPUTDIR), \
+        SRC := $(TOPDIR)/src/java.base/solaris/native/libjvm_db, \
+        CFLAGS := -I$(DTRACE_GENSRC_DIR) $(JNI_INCLUDE_FLAGS) -m64 -G -mt -KPIC -xldscope=hidden, \
+        LDFLAGS := -m64 -mt -xnolib $(SHARED_LIBRARY_FLAGS), \
+        OBJECT_DIR := $(LIBJVM_DB_OUTPUTDIR)/objs, \
+    ))
+
+    TARGETS += $(BUILD_LIBJVM_DTRACE) $(BUILD_LIBJVM_DB)
+
+  endif
+endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/CompileJvm.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/CompileJvm.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/CompileJvm.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/CompileJvm.gmk	2024-08-17 18:29:44.451945614 +0200
@@ -29,6 +29,9 @@
 include lib/JvmOverrideFiles.gmk
 include lib/JvmFlags.gmk
 
+# Include support files that will setup DTRACE_EXTRA_OBJECT_FILES.
+include lib/JvmDtraceObjects.gmk
+
 ################################################################################
 # Setup compilation of the main Hotspot native library (libjvm).
 
@@ -146,6 +149,7 @@
     EXCLUDES := $(JVM_EXCLUDES), \
     EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \
     EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \
+    EXTRA_OBJECT_FILES := $(DTRACE_EXTRA_OBJECT_FILES), \
     CFLAGS := $(JVM_CFLAGS), \
     abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
     arguments.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/CompileLibraries.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/CompileLibraries.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/CompileLibraries.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/CompileLibraries.gmk	2024-08-17 18:29:44.452320275 +0200
@@ -32,6 +32,7 @@
 include HotspotCommon.gmk
 
 include lib/CompileJvm.gmk
+include lib/CompileDtraceLibraries.gmk
 
 ifneq ($(GTEST_FRAMEWORK_SRC), )
   include lib/CompileGtest.gmk
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/JvmDtraceObjects.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/JvmDtraceObjects.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/JvmDtraceObjects.gmk	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/JvmDtraceObjects.gmk	2024-08-17 18:29:44.535002964 +0200
@@ -0,0 +1,132 @@
+#
+# Copyright (c) 2013, 2019, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+ifeq ($(call check-jvm-feature, dtrace), true)
+  ifeq ($(call isTargetOs, solaris), true)
+
+    ############################################################################
+    # Integrate with libjvm. Here we generate two object files which are
+    # linked with libjvm.so. This step is complicated from a dependency
+    # perspective. We add these two files to the linking of libjvm using
+    # EXTRA_OBJECT_FILES, but they need to be created outside the call to
+    # SetupNativeCompilation. Also, one of the files is dependent on compiled
+    # object files from the libjvm compilation, so this generation must happen
+    # as a part of the libjvm compilation.
+
+    DTRACE_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace.o
+    DTRACE_JHELPER_OBJ := $(JVM_OUTPUTDIR)/objs/dtrace_jhelper.o
+
+    DTRACE_EXTRA_OBJECT_FILES := $(DTRACE_OBJ) $(DTRACE_JHELPER_OBJ)
+
+    ############################################################################
+    # Generate DTRACE_OBJ which is linked with libjvm.so. It depends on a set of
+    # object files from the compilation.
+
+    # Concatenate all *.d files into a single file
+    DTRACE_SOURCE_FILES := $(addprefix $(TOPDIR)/src/hotspot/os/posix/dtrace/, \
+        hotspot_jni.d \
+        hotspot.d \
+        hs_private.d \
+    )
+
+    # *.d in the objs dir is used for generated make dependency files, so use
+    # *.dt for dtrace files to avoid clashes.
+    $(JVM_OUTPUTDIR)/objs/dtrace.dt: $(DTRACE_SOURCE_FILES)
+	$(call LogInfo, Generating $(@F))
+	$(call MakeDir, $(@D))
+	$(CAT) $^ > $@
+
+    DTRACE_INSTRUMENTED_OBJS := $(addprefix $(JVM_OUTPUTDIR)/objs/, \
+        ciEnv.o \
+        classLoadingService.o \
+        compileBroker.o \
+        gcVMOperations.o \
+        hashtable.o \
+        instanceKlass.o \
+        java.o \
+        jni.o \
+        jvm.o \
+        memoryManager.o \
+        nmethod.o \
+        objectMonitor.o \
+        runtimeService.o \
+        sharedRuntime.o \
+        synchronizer.o \
+        thread.o \
+        unsafe.o \
+        vmThread.o \
+    )
+
+    ifeq ($(call check-jvm-feature, parallelgc), true)
+      DTRACE_INSTRUMENTED_OBJS += $(addprefix $(JVM_OUTPUTDIR)/objs/, \
+          psVMOperations.o \
+      )
+    endif
+
+    DTRACE_FLAGS := -64 -G
+    DTRACE_CPP_FLAGS := -D_LP64
+
+    # Make sure we run our selected compiler for preprocessing instead of letting
+    # the dtrace tool pick it on it's own.
+    $(DTRACE_OBJ): $(JVM_OUTPUTDIR)/objs/dtrace.dt $(DTRACE_INSTRUMENTED_OBJS)
+	$(call LogInfo, Generating $(@F) from $(<F) and object files)
+	$(call MakeDir, $(DTRACE_SUPPORT_DIR))
+	$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).dt, \
+	    ($(CPP) $(DTRACE_CPP_FLAGS) $< > $(DTRACE_SUPPORT_DIR)/$(@F).dt))
+	$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -xlazyload -o $@ \
+	    -s $(DTRACE_SUPPORT_DIR)/$(@F).dt $(sort $(DTRACE_INSTRUMENTED_OBJS)))
+
+    ############################################################################
+    # Generate DTRACE_JHELPER_OBJ which is linked with libjvm.so.
+
+    JHELPER_DTRACE_SRC := $(TOPDIR)/src/hotspot/os/solaris/dtrace/jhelper.d
+
+    # jhelper.d includes JvmOffsetsIndex.h which was created by the gensrc step.
+    DTRACE_GENSRC_DIR := $(JVM_VARIANT_OUTPUTDIR)/gensrc/dtracefiles
+    JVM_OFFSETS_INDEX_H := $(DTRACE_GENSRC_DIR)/JvmOffsetsIndex.h
+
+    # Unfortunately dtrace generates incorrect types for some symbols in
+    # dtrace_jhelper.o, resulting in "warning: symbol X has differing types"
+    # See JDK-6890703 for details.
+    # We work around this by fixing the types for these symbols using elfedit,
+    # after dtrace has generated the .o file.
+    GetElfeditCommands = \
+      $(foreach symbol, \
+          $(shell $(GREP) ^extern $(JHELPER_DTRACE_SRC) | $(AWK) '{ gsub(";","") ; print $$3 }'), \
+          -e 'sym:st_type $(symbol) 1')
+
+    # Make sure we run our selected compiler for preprocessing instead of letting
+    # the dtrace tool pick it on it's own.
+    $(DTRACE_JHELPER_OBJ): $(JHELPER_DTRACE_SRC) $(JVM_OFFSETS_INDEX_H)
+	$(call LogInfo, Running dtrace for $(<F))
+	$(call MakeDir, $(DTRACE_SUPPORT_DIR))
+	$(call ExecuteWithLog, $(DTRACE_SUPPORT_DIR)/$(@F).dt, \
+	    ($(CPP) $(DTRACE_CPP_FLAGS) -I$(DTRACE_GENSRC_DIR) $^ \
+	    > $(DTRACE_SUPPORT_DIR)/$(@F).dt))
+	$(call ExecuteWithLog, $@, $(DTRACE) $(DTRACE_FLAGS) -o $@ \
+	    -s $(DTRACE_SUPPORT_DIR)/$(@F).dt)
+
+  endif
+endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/JvmMapfile.gmk jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/JvmMapfile.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/lib/JvmMapfile.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/lib/JvmMapfile.gmk	2024-08-17 18:29:44.452824436 +0200
@@ -48,6 +48,18 @@
   endif
 endif
 
+ifeq ($(call isTargetOs, solaris), true)
+  ifeq ($(call check-jvm-feature, dtrace), true)
+    # Additional mapfiles that are only used when dtrace is enabled
+    ifeq ($(call check-jvm-feature, compiler2), true)
+      # This also covers the case of compiler1+compiler2.
+      SYMBOLS_SRC += $(TOPDIR)/make/hotspot/symbols/symbols-solaris-dtrace-compiler2
+    else ifeq ($(call check-jvm-feature, compiler1), true)
+      SYMBOLS_SRC += $(TOPDIR)/make/hotspot/symbols/symbols-solaris-dtrace-compiler1
+    endif
+  endif
+endif
+
 ################################################################################
 # Create a dynamic list of symbols from the built object files. This is highly
 # platform dependent.
@@ -64,6 +76,20 @@
         if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \
       }'
 
+else ifeq ($(call isTargetOs, solaris), true)
+  DUMP_SYMBOLS_CMD := $(NM) -p *.o
+  ifneq ($(FILTER_SYMBOLS_PATTERN), )
+    FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|
+  endif
+  FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)^__1c.*__vtbl_$$|^gHotSpotVM
+  FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^UseSharedSpaces$$
+  FILTER_SYMBOLS_PATTERN := $(FILTER_SYMBOLS_PATTERN)|^__1cJArgumentsRSharedArchivePath_$$
+  FILTER_SYMBOLS_AWK_SCRIPT := \
+      '{ \
+        if ($$2 == "U") next; \
+        if ($$3 ~ /$(FILTER_SYMBOLS_PATTERN)/) print $$3; \
+      }'
+
 else ifeq ($(call isTargetOs, macosx), true)
   # nm on macosx prints out "warning: nm: no name list" to stderr for
   # files without symbols. Hide this, even at the expense of hiding real errors.
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp jdk18u-jdk-18.0.2.1-ga/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp	2024-08-17 18:29:44.535593995 +0200
@@ -0,0 +1,316 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * This is to provide sanity check in jhelper.d which compares SCCS
+ * versions of generateJvmOffsets.cpp used to create and extract
+ * contents of __JvmOffsets[] table.
+ * The __JvmOffsets[] table is located in generated JvmOffsets.cpp.
+ *
+ * GENOFFS_SCCS_VER 34
+ */
+
+#include <stdio.h>
+#include <strings.h>
+
+/* A workaround for private and protected fields */
+#define private   public
+#define protected public
+
+#include <proc_service.h>
+#include "gc/shared/collectedHeap.hpp"
+#include "memory/heap.hpp"
+#include "oops/compressedOops.hpp"
+#include "runtime/vmStructs.hpp"
+
+typedef enum GEN_variant {
+        GEN_OFFSET = 0,
+        GEN_INDEX  = 1,
+        GEN_TABLE  = 2
+} GEN_variant;
+
+#ifdef COMPILER1
+#ifdef ASSERT
+
+/*
+ * To avoid the most part of potential link errors
+ * we link this program with -z nodefs .
+ *
+ * But for 'debug1' and 'fastdebug1' we still have to provide
+ * a particular workaround for the following symbols below.
+ * It will be good to find out a generic way in the future.
+ */
+
+#pragma weak tty
+
+#if defined(i386) || defined(__i386) || defined(__amd64)
+#pragma weak noreg
+#endif /* i386 */
+
+LIR_Opr LIR_OprFact::illegalOpr = (LIR_Opr) 0;
+
+address StubRoutines::_call_stub_return_address = NULL;
+
+StubQueue* AbstractInterpreter::_code = NULL;
+
+#endif /* ASSERT */
+#endif /* COMPILER1 */
+
+#define GEN_OFFS_NAME(Type,Name,OutputType)             \
+  switch(gen_variant) {                                 \
+  case GEN_OFFSET:                                      \
+    printf("#define OFFSET_%-33s %ld\n",                \
+            #OutputType #Name, offset_of(Type, Name));  \
+    break;                                              \
+  case GEN_INDEX:                                       \
+    printf("#define IDX_OFFSET_%-33s %d\n",             \
+            #OutputType #Name, index++);                \
+    break;                                              \
+  case GEN_TABLE:                                       \
+    printf("\tOFFSET_%s,\n", #OutputType #Name);        \
+    break;                                              \
+  }
+
+#define GEN_OFFS(Type,Name)                             \
+  GEN_OFFS_NAME(Type,Name,Type)
+
+#define GEN_SIZE(Type)                                  \
+  switch(gen_variant) {                                 \
+  case GEN_OFFSET:                                      \
+    printf("#define SIZE_%-35s %ld\n",                  \
+            #Type, sizeof(Type));                       \
+    break;                                              \
+  case GEN_INDEX:                                       \
+    printf("#define IDX_SIZE_%-35s %d\n",               \
+            #Type, index++);                            \
+    break;                                              \
+  case GEN_TABLE:                                       \
+    printf("\tSIZE_%s,\n", #Type);                      \
+    break;                                              \
+  }
+
+#define GEN_VALUE(String,Value)                         \
+  switch(gen_variant) {                                 \
+  case GEN_OFFSET:                                      \
+    printf("#define %-40s %d\n", #String, Value);       \
+    break;                                              \
+  case GEN_INDEX:                                       \
+    printf("#define IDX_%-40s %d\n", #String, index++); \
+    break;                                              \
+  case GEN_TABLE:                                       \
+    printf("\t" #String ",\n");                         \
+    break;                                              \
+  }
+
+void gen_prologue(GEN_variant gen_variant) {
+    const char *suffix = "Undefined-Suffix";
+
+    switch(gen_variant) {
+      case GEN_OFFSET: suffix = ".h";        break;
+      case GEN_INDEX:  suffix = "Index.h";   break;
+      case GEN_TABLE:  suffix = ".cpp";      break;
+    }
+
+    printf("/*\n");
+    printf(" * JvmOffsets%s !!!DO NOT EDIT!!! \n", suffix);
+    printf(" * The generateJvmOffsets program generates this file!\n");
+    printf(" */\n\n");
+    switch(gen_variant) {
+
+      case GEN_OFFSET:
+      case GEN_INDEX:
+        break;
+
+      case GEN_TABLE:
+        printf("#include \"JvmOffsets.h\"\n");
+        printf("\n");
+        printf("int __JvmOffsets[] = {\n");
+        break;
+    }
+}
+
+void gen_epilogue(GEN_variant gen_variant) {
+    if (gen_variant != GEN_TABLE) {
+        return;
+    }
+    printf("};\n\n");
+    return;
+}
+
+int generateJvmOffsets(GEN_variant gen_variant) {
+  int index = 0;        /* It is used to generate JvmOffsetsIndex.h */
+  int pointer_size = sizeof(void *);
+  int data_model = (pointer_size == 4) ? PR_MODEL_ILP32 : PR_MODEL_LP64;
+
+  gen_prologue(gen_variant);
+
+  GEN_VALUE(DATA_MODEL, data_model);
+  GEN_VALUE(POINTER_SIZE, pointer_size);
+#if COMPILER1_AND_COMPILER2
+  GEN_VALUE(COMPILER, 3);
+#elif COMPILER1
+  GEN_VALUE(COMPILER, 1);
+#elif COMPILER2
+  GEN_VALUE(COMPILER, 2);
+#else
+  GEN_VALUE(COMPILER, 0);
+#endif // COMPILER1 && COMPILER2
+  printf("\n");
+
+  GEN_OFFS(CollectedHeap, _reserved);
+  GEN_OFFS(MemRegion, _start);
+  GEN_OFFS(MemRegion, _word_size);
+  GEN_SIZE(HeapWord);
+  printf("\n");
+
+  GEN_OFFS(VMStructEntry, typeName);
+  GEN_OFFS(VMStructEntry, fieldName);
+  GEN_OFFS(VMStructEntry, address);
+  GEN_SIZE(VMStructEntry);
+  printf("\n");
+
+  GEN_VALUE(MAX_METHOD_CODE_SIZE, max_method_code_size);
+#if defined(i386) || defined(__i386) || defined(__amd64)
+  GEN_VALUE(OFFSET_interpreter_frame_sender_sp, -1 * pointer_size);
+  GEN_VALUE(OFFSET_interpreter_frame_method, -3 * pointer_size);
+  GEN_VALUE(OFFSET_interpreter_frame_bcp_offset, -7 * pointer_size);
+#endif
+
+  GEN_OFFS(Klass, _name);
+  GEN_OFFS(ConstantPool, _pool_holder);
+  printf("\n");
+
+  GEN_VALUE(OFFSET_HeapBlockHeader_used, (int) offset_of(HeapBlock::Header, _used));
+  GEN_OFFS(oopDesc, _metadata);
+  printf("\n");
+
+  GEN_VALUE(AccessFlags_NATIVE, JVM_ACC_NATIVE);
+  GEN_VALUE(ConstMethod_has_linenumber_table, ConstMethod::_has_linenumber_table);
+  GEN_OFFS(AccessFlags, _flags);
+  GEN_OFFS(Symbol, _length);
+  GEN_OFFS(Symbol, _body);
+  printf("\n");
+
+  GEN_OFFS(Method, _constMethod);
+  GEN_OFFS(Method, _access_flags);
+  printf("\n");
+
+  GEN_OFFS(ConstMethod, _constants);
+  GEN_OFFS(ConstMethod, _flags);
+  GEN_OFFS(ConstMethod, _code_size);
+  GEN_OFFS(ConstMethod, _name_index);
+  GEN_OFFS(ConstMethod, _signature_index);
+  printf("\n");
+
+  GEN_OFFS(CodeHeap, _memory);
+  GEN_OFFS(CodeHeap, _segmap);
+  GEN_OFFS(CodeHeap, _log2_segment_size);
+  printf("\n");
+
+  GEN_OFFS(VirtualSpace, _low_boundary);
+  GEN_OFFS(VirtualSpace, _high_boundary);
+  GEN_OFFS(VirtualSpace, _low);
+  GEN_OFFS(VirtualSpace, _high);
+  printf("\n");
+
+  /* We need to use different names here because of the template parameter */
+  GEN_OFFS_NAME(GrowableArray<CodeHeap*>, _data, GrowableArray_CodeHeap);
+  GEN_OFFS_NAME(GrowableArray<CodeHeap*>, _len, GrowableArray_CodeHeap);
+  printf("\n");
+
+  GEN_OFFS(CodeBlob, _name);
+  GEN_OFFS(CodeBlob, _header_size);
+  GEN_OFFS(CodeBlob, _content_begin);
+  GEN_OFFS(CodeBlob, _code_begin);
+  GEN_OFFS(CodeBlob, _code_end);
+  GEN_OFFS(CodeBlob, _data_offset);
+  GEN_OFFS(CodeBlob, _frame_size);
+  printf("\n");
+
+  GEN_OFFS(nmethod, _method);
+  GEN_OFFS(nmethod, _dependencies_offset);
+  GEN_OFFS(nmethod, _metadata_offset);
+  GEN_OFFS(nmethod, _scopes_data_begin);
+  GEN_OFFS(nmethod, _scopes_pcs_offset);
+  GEN_OFFS(nmethod, _handler_table_offset);
+  GEN_OFFS(nmethod, _deopt_handler_begin);
+  GEN_OFFS(nmethod, _orig_pc_offset);
+
+  GEN_OFFS(PcDesc, _pc_offset);
+  GEN_OFFS(PcDesc, _scope_decode_offset);
+
+  printf("\n");
+
+  GEN_OFFS(NarrowPtrStruct, _base);
+  GEN_OFFS(NarrowPtrStruct, _shift);
+  printf("\n");
+
+  GEN_VALUE(SIZE_HeapBlockHeader, (int) sizeof(HeapBlock::Header));
+  GEN_SIZE(oopDesc);
+  GEN_SIZE(ConstantPool);
+  printf("\n");
+
+  GEN_SIZE(PcDesc);
+  GEN_SIZE(Method);
+  GEN_SIZE(ConstMethod);
+  GEN_SIZE(nmethod);
+  GEN_SIZE(CodeBlob);
+  GEN_SIZE(BufferBlob);
+  GEN_SIZE(SingletonBlob);
+  GEN_SIZE(RuntimeStub);
+  GEN_SIZE(SafepointBlob);
+
+  gen_epilogue(gen_variant);
+  printf("\n");
+
+  fflush(stdout);
+  return 0;
+}
+
+const char *HELP =
+    "HELP: generateJvmOffsets {-header | -index | -table} \n";
+
+int main(int argc, const char *argv[]) {
+    GEN_variant gen_var;
+
+    if (argc != 2) {
+        printf("%s", HELP);
+        return 1;
+    }
+
+    if (0 == strcmp(argv[1], "-header")) {
+        gen_var = GEN_OFFSET;
+    }
+    else if (0 == strcmp(argv[1], "-index")) {
+        gen_var = GEN_INDEX;
+    }
+    else if (0 == strcmp(argv[1], "-table")) {
+        gen_var = GEN_TABLE;
+    }
+    else {
+        printf("%s", HELP);
+        return 1;
+    }
+    return generateJvmOffsets(gen_var);
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/symbols/symbols-solaris jdk18u-jdk-18.0.2.1-ga/make/hotspot/symbols/symbols-solaris
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/symbols/symbols-solaris	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/symbols/symbols-solaris	2024-08-17 18:29:44.535942106 +0200
@@ -0,0 +1,25 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+JVM_handle_solaris_signal
+sysThreadAvailableStackWithSlack
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 jdk18u-jdk-18.0.2.1-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler1
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler1	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler1	2024-08-17 18:29:44.536229323 +0200
@@ -0,0 +1,34 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+__1cGMethodG__vtbl_
+__1cHnmethodG__vtbl_
+__1cICodeBlobG__vtbl_
+__1cIUniverseO_collectedHeap_
+__1cJCodeCacheG_heaps_
+__1cKBufferBlobG__vtbl_
+__1cLRuntimeStubG__vtbl_
+__1cNSafepointBlobG__vtbl_
+__1cSDeoptimizationBlobG__vtbl_
+
+__JvmOffsets
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 jdk18u-jdk-18.0.2.1-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler2
--- jdk18u-jdk-18.0.2.1-ga.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler2	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/hotspot/symbols/symbols-solaris-dtrace-compiler2	2024-08-17 18:29:44.537217618 +0200
@@ -0,0 +1,36 @@
+#
+# Copyright (c) 2016, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+__1cGMethodG__vtbl_
+__1cHnmethodG__vtbl_
+__1cICodeBlobG__vtbl_
+__1cIUniverseO_collectedHeap_
+__1cJCodeCacheG_heaps_
+__1cKBufferBlobG__vtbl_
+__1cLRuntimeStubG__vtbl_
+__1cNSafepointBlobG__vtbl_
+__1cSDeoptimizationBlobG__vtbl_
+__1cNExceptionBlobG__vtbl_
+__1cQUncommonTrapBlobG__vtbl_
+
+__JvmOffsets
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/ide/visualstudio/hotspot/CreateVSProject.gmk jdk18u-jdk-18.0.2.1-ga/make/ide/visualstudio/hotspot/CreateVSProject.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/ide/visualstudio/hotspot/CreateVSProject.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/ide/visualstudio/hotspot/CreateVSProject.gmk	2024-08-17 18:29:44.453374094 +0200
@@ -76,6 +76,7 @@
     -ignorePath linux \
     -ignorePath posix \
     -ignorePath ppc \
+    -ignorePath solaris \
     -ignorePath x86_32 \
     -ignorePath zero \
       #
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/langtools/build.xml jdk18u-jdk-18.0.2.1-ga/make/langtools/build.xml
--- jdk18u-jdk-18.0.2.1-ga.orig/make/langtools/build.xml	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/langtools/build.xml	2024-08-17 18:29:44.453926724 +0200
@@ -100,7 +100,7 @@
     <property name="xpatch.noquotes.cmd" value="--patch-module=${xpatch.noquotes.rest}"/>
 
     <!-- java.marker is set to a marker file to check for within a Java install dir.
-         The best file to check for across Linux/Windows/MacOS is one of the
+         The best file to check for across Solaris/Linux/Windows/MacOS is one of the
          executables; regrettably, that is OS-specific. -->
     <condition property="java.marker" value="bin/java">
         <os family="unix"/>
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/Copy.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/Copy.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/Copy.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/Copy.gmk	2024-08-17 18:29:44.454403288 +0200
@@ -190,7 +190,7 @@
 
 TARGETS += $(NET_PROPERTIES_DST)
 
-ifeq ($(call isTargetOs, linux), true)
+ifeq ($(call isTargetOs, solaris linux), true)
   $(eval $(call SetupCopyFiles, COPY_SDP_CONF, \
       FILES := $(TOPDIR)/src/java.base/$(OPENJDK_TARGET_OS_TYPE)/conf/sdp/sdp.conf.template, \
       DEST := $(CONF_DST_DIR)/sdp, \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/gensrc/GensrcMisc.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/gensrc/GensrcMisc.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/gensrc/GensrcMisc.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/gensrc/GensrcMisc.gmk	2024-08-17 18:29:44.455867085 +0200
@@ -110,6 +110,21 @@
 
 endif
 
+################################################################################
+
+ifeq ($(call isTargetOs, solaris), true)
+
+  GENSRC_SC_FILE := $(SUPPORT_OUTPUTDIR)/gensrc/java.base/sun/nio/fs/SolarisConstants.java
+
+  $(GENSRC_SC_FILE): \
+      $(TOPDIR)/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template
+	$(generate-preproc-src)
+
+  TARGETS += $(GENSRC_SC_FILE)
+
+endif
+
+################################################################################
 # Create the javax/crypto/JceSecurity.class, using the build default.
 #
 ifeq ($(UNLIMITED_CRYPTO), true)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/Launcher.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/Launcher.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/Launcher.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/Launcher.gmk	2024-08-17 18:29:44.454845399 +0200
@@ -64,6 +64,7 @@
       CFLAGS := $(CFLAGS_JDKEXE) \
           -I$(TOPDIR)/src/$(MODULE)/share/native/libjli, \
       CFLAGS_linux := -fPIC, \
+      CFLAGS_solaris := -KPIC, \
       LDFLAGS := $(LDFLAGS_JDKEXE), \
       OUTPUT_DIR := $(SUPPORT_OUTPUTDIR)/modules_libs/$(MODULE), \
   ))
@@ -73,7 +74,7 @@
 
 ################################################################################
 
-ifeq ($(call isTargetOs, macosx aix linux), true)
+ifeq ($(call isTargetOs, macosx solaris aix linux), true)
   $(eval $(call SetupJdkExecutable, BUILD_JSPAWNHELPER, \
       NAME := jspawnhelper, \
       SRC := $(TOPDIR)/src/$(MODULE)/unix/native/jspawnhelper, \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/lib/CoreLibraries.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/lib/CoreLibraries.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/lib/CoreLibraries.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/lib/CoreLibraries.gmk	2024-08-17 18:29:44.456522861 +0200
@@ -29,6 +29,10 @@
 
 BUILD_LIBFDLIBM_OPTIMIZATION := NONE
 
+ifeq ($(call isTargetOs, solaris), true)
+  BUILD_LIBFDLIBM_OPTIMIZATION := HIGH
+endif
+
 # If FDLIBM_CFLAGS is non-empty we know that we can optimize
 # fdlibm when adding those extra C flags. Currently GCC,
 # and clang only.
@@ -58,7 +62,7 @@
 ##########################################################################################
 
 LIBVERIFY_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, linux), true)
+ifeq ($(call isTargetOs, solaris linux), true)
   ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true)
     LIBVERIFY_OPTIMIZATION := LOW
   endif
@@ -101,6 +105,7 @@
     LIBS := $(BUILD_LIBFDLIBM_TARGET), \
     LIBS_unix := -ljvm, \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := -lsocket -lnsl -lscf $(LIBDL), \
     LIBS_aix := $(LIBDL) $(LIBM),\
     LIBS_macosx := -framework CoreFoundation \
         -framework Foundation \
@@ -208,6 +213,7 @@
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS_unix := $(LIBZ_LIBS), \
     LIBS_linux := $(LIBDL) -lpthread, \
+    LIBS_solaris := $(LIBDL), \
     LIBS_aix := $(LIBDL),\
     LIBS_macosx := -framework Cocoa -framework Security -framework ApplicationServices, \
     LIBS_windows := advapi32.lib comctl32.lib user32.lib, \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.base/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.base/Lib.gmk	2024-08-17 18:29:44.455379034 +0200
@@ -52,6 +52,7 @@
     LDFLAGS_windows := -delayload:secur32.dll -delayload:iphlpapi.dll, \
     LIBS_unix := -ljvm -ljava, \
     LIBS_linux := $(LIBDL) -lpthread, \
+    LIBS_solaris := -lnsl -lsocket $(LIBDL), \
     LIBS_aix := $(LIBDL),\
     LIBS_windows := ws2_32.lib jvm.lib secur32.lib iphlpapi.lib winhttp.lib \
         delayimp.lib $(WIN_JAVA_LIB) advapi32.lib, \
@@ -80,6 +81,8 @@
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS_unix := -ljava -lnet, \
     LIBS_linux := -lpthread $(LIBDL), \
+    LIBS_solaris := -ljvm -lsocket -lposix4 $(LIBDL) \
+        -lsendfile, \
     LIBS_aix := $(LIBDL), \
     LIBS_macosx := \
         -framework CoreFoundation -framework CoreServices, \
@@ -134,6 +137,7 @@
         LDFLAGS := $(LDFLAGS_JDKLIB) \
             $(call SET_SHARED_LIBRARY_ORIGIN), \
         LIBS_linux := $(LIBDL), \
+        LIBS_solaris := $(LIBDL), \
         LIBS_aix := $(LIBDL), \
     ))
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.desktop/Gensrc.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.desktop/Gensrc.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.desktop/Gensrc.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.desktop/Gensrc.gmk	2024-08-17 18:29:44.457034558 +0200
@@ -32,7 +32,7 @@
   include gensrc/GensrcIcons.gmk
 endif
 
-ifeq ($(call isTargetOs, linux aix), true)
+ifeq ($(call isTargetOs, linux solaris aix), true)
   include gensrc/GensrcX11Wrappers.gmk
 endif
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.desktop/lib/Awt2dLibraries.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.desktop/lib/Awt2dLibraries.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.desktop/lib/Awt2dLibraries.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.desktop/lib/Awt2dLibraries.gmk	2024-08-17 18:29:44.458356145 +0200
@@ -76,7 +76,7 @@
       #
 endif
 
-ifeq ($(call isTargetOs, linux macosx aix), true)
+ifeq ($(call isTargetOs, solaris linux macosx aix), true)
   LIBAWT_EXFILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c
 endif
 
@@ -156,6 +156,7 @@
         -delayload:comctl32.dll -delayload:shlwapi.dll, \
     LIBS_unix := -ljvm -ljava $(LIBM), \
     LIBS_linux :=  $(LIBDL), \
+    LIBS_solaris := $(LIBDL), \
     LIBS_aix := $(LIBDL),\
     LIBS_macosx := -lmlib_image \
         -framework Cocoa \
@@ -387,6 +388,7 @@
       LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
       LIBS_unix := -lawt -ljvm -ljava, \
       LIBS_linux := $(LIBM) $(LIBDL), \
+      LIBS_solaris := $(LIBM) $(LIBDL) $(LIBCXX), \
   ))
 
   $(BUILD_LIBAWT_HEADLESS): $(BUILD_LIBAWT)
@@ -444,7 +446,7 @@
                         -DHAVE_SYSCONF -DHAVE_SYS_MMAN_H -DHAVE_UNISTD_H \
                         -DHB_NO_PRAGMA_GCC_DIAGNOSTIC
    endif
-   ifeq ($(call isTargetOs, linux macosx), true)
+   ifeq ($(call isTargetOs, solaris linux macosx), true)
      HARFBUZZ_CFLAGS += -DHAVE_INTEL_ATOMIC_PRIMITIVES
    endif
 
@@ -597,7 +599,10 @@
   ifeq ($(call isTargetOs, macosx), true)
     JAWT_LIBS := -lawt_lwawt
   else
-    JAWT_LIBS := -lawt
+    JAWT_LIBS :=
+    ifeq ($(call isTargetOs, solaris), false)
+      JAWT_LIBS += -lawt
+    endif
     ifeq ($(ENABLE_HEADLESS_ONLY), false)
       JAWT_LIBS += -lawt_xawt
     else
@@ -624,6 +629,7 @@
       LDFLAGS_unix := -L$(INSTALL_LIBRARIES_HERE), \
       LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \
       LIBS_unix := $(JAWT_LIBS) $(JDKLIB_LIBS), \
+      LIBS_solaris := $(X_LIBS) -lXrender, \
       LIBS_macosx := -framework Cocoa, \
   ))
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.desktop/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.desktop/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.desktop/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.desktop/Lib.gmk	2024-08-17 18:29:44.457463511 +0200
@@ -47,10 +47,15 @@
       -DX_PLATFORM=X_$(OPENJDK_TARGET_OS_UPPERCASE) \
       -DUSE_PORTS=TRUE \
       -DUSE_DAUDIO=TRUE \
-      -DUSE_PLATFORM_MIDI_OUT=TRUE \
-      -DUSE_PLATFORM_MIDI_IN=TRUE \
       #
 
+  ifeq ($(call isTargetOs, solaris), false)
+    LIBJSOUND_CFLAGS += \
+        -DUSE_PLATFORM_MIDI_OUT=TRUE \
+        -DUSE_PLATFORM_MIDI_IN=TRUE \
+        #
+  endif
+
   ifeq ($(call isTargetOs, macosx), true)
     LIBJSOUND_TOOLCHAIN := TOOLCHAIN_LINK_CXX
   endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.instrument/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.instrument/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.instrument/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.instrument/Lib.gmk	2024-08-17 18:29:44.458853056 +0200
@@ -45,11 +45,13 @@
         $(call SET_SHARED_LIBRARY_ORIGIN) \
         $(LIBINSTRUMENT_LDFLAGS), \
     LDFLAGS_linux := -L$(call FindLibDirForModule, java.base), \
+    LDFLAGS_solaris := -L$(call FindLibDirForModule, java.base), \
     LDFLAGS_macosx := -L$(call FindLibDirForModule, java.base), \
     LDFLAGS_aix := -L$(SUPPORT_OUTPUTDIR)/native/java.base, \
     LIBS := $(JDKLIB_LIBS), \
     LIBS_unix := -ljava -ljvm $(LIBZ_LIBS), \
     LIBS_linux := -ljli $(LIBDL), \
+    LIBS_solaris := -ljli $(LIBDL), \
     LIBS_aix := -liconv -ljli_static $(LIBDL), \
     LIBS_macosx := -ljli -liconv -framework Cocoa -framework Security \
         -framework ApplicationServices, \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.management/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.management/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.management/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.management/Lib.gmk	2024-08-17 18:29:44.459362889 +0200
@@ -28,7 +28,7 @@
 ################################################################################
 
 LIBMANAGEMENT_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, linux), true)
+ifeq ($(call isTargetOs, solaris linux), true)
   ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true)
     LIBMANAGEMENT_OPTIMIZATION := LOW
   endif
@@ -41,6 +41,7 @@
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS := $(JDKLIB_LIBS), \
+    LIBS_solaris := -lkstat, \
     LIBS_aix := -lperfstat,\
     LIBS_windows := jvm.lib psapi.lib $(WIN_JAVA_LIB) advapi32.lib, \
 ))
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.prefs/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/java.prefs/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/java.prefs/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/java.prefs/Lib.gmk	2024-08-17 18:29:44.459806116 +0200
@@ -41,6 +41,7 @@
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS_unix := -ljvm, \
     LIBS_linux := -ljava, \
+    LIBS_solaris := -ljava, \
     LIBS_aix := -ljava, \
     LIBS_macosx := -framework CoreFoundation -framework Foundation, \
     LIBS_windows := advapi32.lib jvm.lib $(WIN_JAVA_LIB), \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.attach/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.attach/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.attach/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.attach/Lib.gmk	2024-08-17 18:29:44.460267171 +0200
@@ -42,6 +42,7 @@
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS := $(JDKLIB_LIBS), \
+    LIBS_solaris := -ldoor, \
     LIBS_windows := $(WIN_JAVA_LIB) advapi32.lib psapi.lib, \
 ))
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.crypto.cryptoki/Copy.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.crypto.cryptoki/Copy.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.crypto.cryptoki/Copy.gmk	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.crypto.cryptoki/Copy.gmk	2024-08-17 18:29:44.537587457 +0200
@@ -0,0 +1,45 @@
+#
+# Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
+# DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+#
+# This code is free software; you can redistribute it and/or modify it
+# under the terms of the GNU General Public License version 2 only, as
+# published by the Free Software Foundation.  Oracle designates this
+# particular file as subject to the "Classpath" exception as provided
+# by Oracle in the LICENSE file that accompanied this code.
+#
+# This code is distributed in the hope that it will be useful, but WITHOUT
+# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+# FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+# version 2 for more details (a copy is included in the LICENSE file that
+# accompanied this code).
+#
+# You should have received a copy of the GNU General Public License version
+# 2 along with this work; if not, write to the Free Software Foundation,
+# Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+#
+# Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+# or visit www.oracle.com if you need additional information or have any
+# questions.
+#
+
+include CopyCommon.gmk
+
+################################################################################
+
+ifeq ($(call isTargetOs, solaris), true)
+
+  SUNPKCS11_CFG_SRC := \
+      $(TOPDIR)/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg
+  SUNPKCS11_CFG_DST := $(CONF_DST_DIR)/security/sunpkcs11-solaris.cfg
+
+  $(SUNPKCS11_CFG_DST): $(SUNPKCS11_CFG_SRC)
+	$(call install-file)
+
+  SECURITY_PKCS11_CONF_FILES += $(SUNPKCS11_CFG_DST)
+
+  TARGETS := $(SUNPKCS11_CFG_DST)
+
+endif
+
+################################################################################
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.hotspot.agent/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.hotspot.agent/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.hotspot.agent/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.hotspot.agent/Lib.gmk	2024-08-17 18:29:44.460720025 +0200
@@ -65,10 +65,11 @@
     CFLAGS := $(CFLAGS_JDKLIB) $(SA_CFLAGS), \
     CXXFLAGS := $(CXXFLAGS_JDKLIB) $(SA_CFLAGS) $(SA_CXXFLAGS), \
     EXTRA_SRC := $(LIBSA_EXTRA_SRC), \
-    LDFLAGS := $(LDFLAGS_JDKLIB) $(call SET_SHARED_LIBRARY_ORIGIN), \
+    LDFLAGS := $(LDFLAGS_JDKLIB) $(SA_LDFLAGS) $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS := $(LIBCXX), \
     LIBS_unix := -ljava, \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := -ldl -lstdc++ -lthread -lproc, \
     LIBS_macosx := -framework Foundation \
         -framework JavaRuntimeSupport -framework Security -framework CoreFoundation, \
     LIBS_windows := dbgeng.lib $(WIN_JAVA_LIB), \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.jdwp.agent/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.jdwp.agent/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.jdwp.agent/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.jdwp.agent/Lib.gmk	2024-08-17 18:29:44.461209939 +0200
@@ -37,6 +37,7 @@
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS_linux := -lpthread, \
+    LIBS_solaris := -lnsl -lsocket, \
     LIBS_windows := $(JDKLIB_LIBS) ws2_32.lib iphlpapi.lib, \
 ))
 
@@ -62,6 +63,7 @@
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS := $(JDKLIB_LIBS), \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := $(LIBDL), \
     LIBS_macosx := -liconv, \
     LIBS_aix := -liconv, \
 ))
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.management/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.management/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.management/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.management/Lib.gmk	2024-08-17 18:29:44.461700327 +0200
@@ -35,7 +35,7 @@
 endif
 
 LIBMANAGEMENT_EXT_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, linux), true)
+ifeq ($(call isTargetOs, solaris linux), true)
   ifeq ($(COMPILE_WITH_DEBUG_SYMBOLS), true)
     LIBMANAGEMENT_EXT_OPTIMIZATION := LOW
   endif
@@ -49,6 +49,7 @@
     LDFLAGS := $(LDFLAGS_JDKLIB) \
         $(call SET_SHARED_LIBRARY_ORIGIN), \
     LIBS := $(JDKLIB_LIBS), \
+    LIBS_solaris := -lkstat, \
     LIBS_aix := -lperfstat,\
     LIBS_windows := jvm.lib psapi.lib $(WIN_JAVA_LIB) advapi32.lib, \
 ))
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.net/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.net/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.net/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.net/Lib.gmk	2024-08-17 18:29:44.462139561 +0200
@@ -36,6 +36,7 @@
       LDFLAGS := $(LDFLAGS_JDKLIB) \
           $(call SET_SHARED_LIBRARY_ORIGIN), \
       LIBS := -ljava, \
+      LIBS_solaris := -lsocket, \
       LIBS_linux := -ljvm, \
   ))
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.sctp/Lib.gmk jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.sctp/Lib.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/modules/jdk.sctp/Lib.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/modules/jdk.sctp/Lib.gmk	2024-08-17 18:29:44.462592152 +0200
@@ -44,6 +44,7 @@
             $(call SET_SHARED_LIBRARY_ORIGIN), \
         LIBS_unix := -lnio -lnet -ljava -ljvm, \
         LIBS_linux := -lpthread $(LIBDL), \
+        LIBS_solaris := -lsocket, \
     ))
 
     TARGETS += $(BUILD_LIBSCTP)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/RunTestsPrebuilt.gmk jdk18u-jdk-18.0.2.1-ga/make/RunTestsPrebuilt.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/RunTestsPrebuilt.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/RunTestsPrebuilt.gmk	2024-08-17 18:29:44.441397546 +0200
@@ -163,6 +163,8 @@
     OPENJDK_TARGET_OS := linux
   else ifeq ($(UNAME_OS), Darwin)
     OPENJDK_TARGET_OS := macosx
+  else ifeq ($(UNAME_OS), SunOS)
+    OPENJDK_TARGET_OS := solaris
   else
     OPENJDK_TARGET_OS := $(UNAME_OS)
   endif
@@ -172,15 +174,28 @@
 # Assume little endian unless otherwise specified
 OPENJDK_TARGET_CPU_ENDIAN := little
 
-UNAME_CPU := $(shell $(UNAME) -m)
-ifeq ($(UNAME_CPU), i686)
-  OPENJDK_TARGET_CPU := x86
-  OPENJDK_TARGET_CPU_BITS := 32
-else
-  # Assume all others are 64-bit. We use the same CPU name as uname for
-  # at least x86_64 and aarch64.
-  OPENJDK_TARGET_CPU := $(UNAME_CPU)
+ifeq ($(OPENJDK_TARGET_OS), solaris)
+  # On solaris, use uname -p
+  UNAME_CPU := $(shell $(UNAME) -p)
+  # Assume 64-bit platform
   OPENJDK_TARGET_CPU_BITS := 64
+  ifeq ($(UNAME_CPU), i386)
+    OPENJDK_TARGET_CPU := x86_64
+  else
+    OPENJDK_TARGET_CPU := $(UNAME_CPU)
+  endif
+else
+  # ... all others use uname -m
+  UNAME_CPU := $(shell $(UNAME) -m)
+  ifeq ($(UNAME_CPU), i686)
+    OPENJDK_TARGET_CPU := x86
+    OPENJDK_TARGET_CPU_BITS := 32
+  else
+    # Assume all others are 64-bit. We use the same CPU name as uname for
+    # at least x86_64 and aarch64.
+    OPENJDK_TARGET_CPU := $(UNAME_CPU)
+    OPENJDK_TARGET_CPU_BITS := 64
+  endif
 endif
 
 OPENJDK_TARGET_CPU_ARCH := $(OPENJDK_TARGET_CPU)
@@ -205,6 +220,11 @@
 else ifeq ($(OPENJDK_TARGET_OS), macosx)
   NUM_CORES := $(shell /usr/sbin/sysctl -n hw.ncpu)
   MEMORY_SIZE := $(shell $(EXPR) `/usr/sbin/sysctl -n hw.memsize` / 1024 / 1024)
+else ifeq ($(OPENJDK_TARGET_OS), solaris)
+  NUM_CORES := $(shell /usr/sbin/psrinfo -v | $(GREP) -c on-line)
+  MEMORY_SIZE := $(shell \
+      /usr/sbin/prtconf 2> /dev/null | $(GREP) "^Memory [Ss]ize" | $(AWK) '{print $$3}' \
+  )
 else ifeq ($(OPENJDK_TARGET_OS), windows)
   NUM_CORES := $(NUMBER_OF_PROCESSORS)
   MEMORY_SIZE := $(shell \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/RunTestsPrebuiltSpec.gmk jdk18u-jdk-18.0.2.1-ga/make/RunTestsPrebuiltSpec.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/RunTestsPrebuiltSpec.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/RunTestsPrebuiltSpec.gmk	2024-08-17 18:29:44.441840542 +0200
@@ -172,6 +172,16 @@
 HG := hg
 ULIMIT := ulimit
 
+# On Solaris gnu versions of some tools are required.
+ifeq ($(OPENJDK_BUILD_OS), solaris)
+  AWK := gawk
+  GREP := ggrep
+  EGREP := ggrep -E
+  FGREP := grep -F
+  SED := gsed
+  TAR := gtar
+endif
+
 ifeq ($(OPENJDK_BUILD_OS), windows)
   PATHTOOL := cygpath
 endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/compare_exceptions.sh.incl jdk18u-jdk-18.0.2.1-ga/make/scripts/compare_exceptions.sh.incl
--- jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/compare_exceptions.sh.incl	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/scripts/compare_exceptions.sh.incl	2024-08-17 18:29:44.463981019 +0200
@@ -45,6 +45,21 @@
         ./hotspot/gtest/server/libjvm.so
         "
    fi
+elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
+  SKIP_BIN_DIFF="true"
+  SKIP_FULLDUMP_DIFF="true"
+  MAX_KNOWN_DIS_DIFF_SIZE="3000"
+  SORT_SYMBOLS="
+      ./lib/libfontmanager.so
+      ./lib/libjimage.so
+      ./lib/server/libjvm.so
+      ./hotspot/gtest/server/libjvm.so
+      "
+  KNOWN_DIS_DIFF="
+      ./lib/libfontmanager.so
+      ./lib/libsaproc.so
+  "
+  STRIP_TESTS_BEFORE_COMPARE="true"
 elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then
   SKIP_BIN_DIFF="true"
   SKIP_FULLDUMP_DIFF="true"
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/compare.sh jdk18u-jdk-18.0.2.1-ga/make/scripts/compare.sh
--- jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/compare.sh	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/scripts/compare.sh	2024-08-17 18:29:44.463553962 +0200
@@ -72,7 +72,14 @@
 # Disassembly diff filters. These filters try to filter out ephemeral parts of the
 # disassembly, such as hard-coded addresses, to be able to catch "actual" differences.
 
-if [ "$OPENJDK_TARGET_OS" = "windows" ]; then
+if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
+  if [ "$OPENJDK_TARGET_CPU" = "x86_64" ]; then
+    # Random strings looking like this differ: <.XAKoKoPIac2W0OA.
+    DIS_DIFF_FILTER="$SED \
+        -e 's/<\.[A-Za-z0-9]\{\15}\./<.SYM./' \
+        "
+  fi
+elif [ "$OPENJDK_TARGET_OS" = "windows" ]; then
   if [ "$OPENJDK_TARGET_CPU" = "x86" ]; then
     DIS_DIFF_FILTER="$SED -r \
         -e 's/^  [0-9A-F]{16}: //' \
@@ -439,7 +446,14 @@
     fi
 
     CONTENTS_DIFF_FILE=$WORK_DIR/$ZIP_FILE.diff
-    $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE
+    # On solaris, there is no -q option.
+    if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
+        $DIFF -r $OTHER_UNZIPDIR $THIS_UNZIPDIR \
+            | $GREP -v -e "^<" -e "^>" -e "^Common subdirectories:" \
+            > $CONTENTS_DIFF_FILE
+    else
+        $DIFF -rq $OTHER_UNZIPDIR $THIS_UNZIPDIR > $CONTENTS_DIFF_FILE
+    fi
 
     ONLY_OTHER=$($GREP "^Only in $OTHER_UNZIPDIR" $CONTENTS_DIFF_FILE)
     ONLY_THIS=$($GREP "^Only in $THIS_UNZIPDIR" $CONTENTS_DIFF_FILE)
@@ -459,8 +473,14 @@
     fi
 
     if [ "$CMP_ZIPS_CONTENTS" = "true" ]; then
-        DIFFING_FILES=$($GREP -e "differ$" $CONTENTS_DIFF_FILE \
-            | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g")
+        if [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
+            DIFFING_FILES=$($GREP -e 'differ$' -e '^diff ' $CONTENTS_DIFF_FILE \
+                | $SED -e 's/^Files //g' -e 's/diff -r //g' | $CUT -f 1 -d ' ' \
+                | $SED "s|$OTHER_UNZIPDIR/||g")
+        else
+            DIFFING_FILES=$($GREP -e "differ$" $CONTENTS_DIFF_FILE \
+                | $CUT -f 2 -d ' ' | $SED "s|$OTHER_UNZIPDIR/||g")
+        fi
 
         # Separate executable/library files from other files in zip.
         DIFFING_TEXT_FILES=
@@ -797,6 +817,10 @@
         # to filter out that extra information.
         $DUMPBIN -exports $OTHER_FILE | $GREP  -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
         $DUMPBIN -exports $THIS_FILE  | $GREP  -E '^ +[0-9A-F]+ +[0-9A-F]+ [0-9A-F]+' | sed 's/ = .*//g' | cut -c27- | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
+    elif [ "$OPENJDK_TARGET_OS" = "solaris" ]; then
+        # Some symbols get seemingly random 15 character prefixes. Filter them out.
+        $NM -a $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
+        $NM -a $ORIG_THIS_FILE  2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SED 's/^\([a-zA-Z] [\.\$]\)[a-zA-Z0-9_\$]\{15,15\}\./\1./g' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
     elif [ "$OPENJDK_TARGET_OS" = "aix" ]; then
         $OBJDUMP -T $ORIG_OTHER_FILE 2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.other
         $OBJDUMP -T $ORIG_THIS_FILE  2> /dev/null | $GREP -v $NAME | $AWK '{print $2, $3, $4, $5}' | $SYM_SORT_CMD > $WORK_FILE_BASE.symbols.this
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/hide_important_warnings_from_javac.sh jdk18u-jdk-18.0.2.1-ga/make/scripts/hide_important_warnings_from_javac.sh
--- jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/hide_important_warnings_from_javac.sh	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/scripts/hide_important_warnings_from_javac.sh	2024-08-17 18:29:44.464390963 +0200
@@ -22,8 +22,13 @@
 # questions.
 #
 
-GREP=grep
-
+if [ -x /usr/bin/ggrep ] ; then
+    # Gnu grep on Solaris
+    # (reference configure and build/solaris-i586-clientANDserver-release/spec.gmk
+    GREP=/usr/bin/ggrep
+else
+    GREP=grep
+fi
 #
 EXP="Note: Some input files use or override a deprecated API."
 EXP="${EXP}|Note: Recompile with -Xlint:deprecation for details."
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/update_copyright_year.sh jdk18u-jdk-18.0.2.1-ga/make/scripts/update_copyright_year.sh
--- jdk18u-jdk-18.0.2.1-ga.orig/make/scripts/update_copyright_year.sh	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/scripts/update_copyright_year.sh	2024-08-17 18:29:44.464804360 +0200
@@ -26,7 +26,11 @@
 # Script to update the Copyright YEAR range in Mercurial sources.
 #  (Originally from xdono, Thanks!)
 
-awk=awk
+if [ "`uname -s`" = "SunOS" ] ; then
+  awk=nawk
+else
+  awk=awk
+fi
 
 # Stop on any error
 set -e
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/test/JtregNativeHotspot.gmk jdk18u-jdk-18.0.2.1-ga/make/test/JtregNativeHotspot.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/test/JtregNativeHotspot.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/test/JtregNativeHotspot.gmk	2024-08-17 18:29:44.465726341 +0200
@@ -869,6 +869,10 @@
 
 BUILD_HOTSPOT_JTREG_EXECUTABLES_LIBS_exesigtest := -ljvm
 
+ifeq ($(call isTargetOs, solaris), true)
+    BUILD_HOTSPOT_JTREG_EXCLUDE += libterminatedThread.c
+endif
+
 ifeq ($(call isTargetOs, windows), true)
     BUILD_HOTSPOT_JTREG_EXECUTABLES_CFLAGS_exeFPRegs := -MT
     BUILD_HOTSPOT_JTREG_EXCLUDE += exesigtest.c libterminatedThread.c libTestJNI.c
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/make/test/JtregNativeJdk.gmk jdk18u-jdk-18.0.2.1-ga/make/test/JtregNativeJdk.gmk
--- jdk18u-jdk-18.0.2.1-ga.orig/make/test/JtregNativeJdk.gmk	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/make/test/JtregNativeJdk.gmk	2024-08-17 18:29:44.466186052 +0200
@@ -77,6 +77,9 @@
   ifeq ($(call isTargetOs, linux), true)
     BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava
     BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -ldl
+  else ifeq ($(call isTargetOs, solaris), true)
+    BUILD_JDK_JTREG_LIBRARIES_LIBS_libInheritedChannel := -ljava -lsocket -lnsl
+    BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -lthread -ldl
   endif
   BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeJliLaunchTest := -ljli
   BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeCallerAccessTest := -ljvm
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/cpu/x86/globalDefinitions_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/cpu/x86/globalDefinitions_x86.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/cpu/x86/globalDefinitions_x86.hpp	2024-08-17 18:29:44.466785287 +0200
@@ -65,7 +65,7 @@
 #define INCLUDE_RTM_OPT 1
 #endif
 
-#if defined(LINUX) || defined(__APPLE__)
+#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__)
 #define SUPPORT_RESERVED_STACK_AREA
 #endif
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/include/jvm_md.h jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/include/jvm_md.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/include/jvm_md.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/include/jvm_md.h	2024-08-17 18:29:44.467364880 +0200
@@ -54,7 +54,7 @@
 #endif
 #define JNI_LIB_NAME(NAME) JNI_LIB_PREFIX NAME JNI_LIB_SUFFIX
 
-#if defined(AIX)
+#if defined(AIX) || defined(SOLARIS)
 #define JVM_MAXPATHLEN MAXPATHLEN
 #else
 // Hack: MAXPATHLEN is 4095 on some Linux and 4096 on others. This may
@@ -87,8 +87,14 @@
 #define JVM_SIGTERM    SIGTERM
 
 #define BREAK_SIGNAL     SIGQUIT           /* Thread dumping support.    */
+#ifdef SOLARIS
+#define ASYNC_SIGNAL     SIGJVM2           /* Event-based suspend/resume support */
+#endif // SOLARIS
 #define SHUTDOWN1_SIGNAL SIGHUP            /* Shutdown Hooks support.    */
 #define SHUTDOWN2_SIGNAL SIGINT
 #define SHUTDOWN3_SIGNAL SIGTERM
 
+/* With 1.4.1 libjsig added versioning: used in os_solaris.cpp and jsig.c */
+#define JSIG_VERSION_1_4_1   0x30140100
+
 #endif /* !_JAVASOFT_JVM_MD_H_ */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/os_posix.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/os_posix.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/os_posix.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/os_posix.cpp	2024-08-17 18:29:44.468389496 +0200
@@ -476,7 +476,7 @@
   st->print("%d", sysconf(_SC_CHILD_MAX));
 
   print_rlimit(st, ", THREADS", RLIMIT_THREADS);
-#else
+#elif !defined(SOLARIS)
   print_rlimit(st, ", NPROC", RLIMIT_NPROC);
 #endif
 
@@ -494,6 +494,12 @@
   print_rlimit(st, ", MEMLOCK", RLIMIT_MEMLOCK, true);
 #endif
 
+#if defined(SOLARIS)
+  // maximum size of mapped address space of a process in bytes;
+  // if the limit is exceeded, mmap and brk fail
+  print_rlimit(st, ", VMEM", RLIMIT_VMEM, true);
+#endif
+
   // MacOS; The maximum size (in bytes) to which a process's resident set size may grow.
 #if defined(__APPLE__)
   print_rlimit(st, ", RSS", RLIMIT_RSS, true);
@@ -920,7 +926,7 @@
 // page size which again depends on the concrete system the VM is running
 // on. Space for libc guard pages is not included in this size.
 jint os::Posix::set_minimum_stack_sizes() {
-  size_t os_min_stack_allowed = PTHREAD_STACK_MIN;
+  size_t os_min_stack_allowed = SOLARIS_ONLY(thr_min_stack()) NOT_SOLARIS(PTHREAD_STACK_MIN);
 
   _java_thread_min_stack_allowed = _java_thread_min_stack_allowed +
                                    StackOverflow::stack_guard_zone_size() +
@@ -1240,7 +1246,8 @@
   if ((status = pthread_mutexattr_settype(_mutexAttr, PTHREAD_MUTEX_NORMAL)) != 0) {
     fatal("pthread_mutexattr_settype: %s", os::strerror(status));
   }
-  os::PlatformMutex::init();
+  // Solaris has it's own PlatformMutex, distinct from the one for POSIX.
+  NOT_SOLARIS(os::PlatformMutex::init();)
 }
 
 static int (*_pthread_condattr_setclock)(pthread_condattr_t *, clockid_t) = NULL;
@@ -1511,6 +1518,7 @@
 // Shared pthread_mutex/cond based PlatformEvent implementation.
 // Not currently usable by Solaris.
 
+#ifndef SOLARIS
 
 // PlatformEvent
 //
@@ -1941,6 +1949,8 @@
   }
 }
 
+#endif // !SOLARIS
+
 // Darwin has no "environ" in a dynamic library.
 #ifdef __APPLE__
   #define environ (*_NSGetEnviron())
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/os_posix.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/os_posix.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/os_posix.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/os_posix.hpp	2024-08-17 18:29:44.468876460 +0200
@@ -132,6 +132,8 @@
   sigjmp_buf _jmpbuf;
 };
 
+#ifndef SOLARIS
+
 /*
  * This is the platform-specific implementation underpinning
  * the ParkEvent class, which itself underpins Java-level monitor
@@ -297,4 +299,6 @@
   void notify_all();
 };
 
+#endif // !SOLARIS
+
 #endif // OS_POSIX_OS_POSIX_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/os_posix.inline.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/os_posix.inline.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/os_posix.inline.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/os_posix.inline.hpp	2024-08-17 18:29:44.469333418 +0200
@@ -45,6 +45,7 @@
   return _result; \
 } while(false)
 
+#ifndef SOLARIS
 // Aix does not have NUMA support but need these for compilation.
 inline bool os::numa_has_static_binding()   { AIX_ONLY(ShouldNotReachHere();) return true; }
 inline bool os::numa_has_group_homing()     { AIX_ONLY(ShouldNotReachHere();) return false;  }
@@ -77,4 +78,6 @@
   assert_status(status == 0, status, "cond_broadcast");
 }
 
+#endif // !SOLARIS
+
 #endif // OS_POSIX_OS_POSIX_INLINE_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/vmError_posix.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/vmError_posix.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/posix/vmError_posix.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/posix/vmError_posix.cpp	2024-08-17 18:29:44.469735038 +0200
@@ -39,6 +39,9 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 #endif
+#ifdef SOLARIS
+#include <thread.h>
+#endif
 #ifdef AIX
 #include <unistd.h>
 #endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/attachListener_solaris.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/attachListener_solaris.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/attachListener_solaris.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/attachListener_solaris.cpp	2024-08-17 18:29:44.538346616 +0200
@@ -0,0 +1,755 @@
+/*
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "logging/log.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/os.inline.hpp"
+#include "services/attachListener.hpp"
+#include "services/dtraceAttacher.hpp"
+#include "utilities/vmError.hpp"
+
+#include <door.h>
+#include <limits.h>
+#include <string.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+
+// stropts.h uses STR in stream ioctl defines
+#undef STR
+#include <stropts.h>
+#undef STR
+#define STR(a) #a
+
+// The attach mechanism on Solaris is implemented using the Doors IPC
+// mechanism. The first tool to attempt to attach causes the attach
+// listener thread to startup. This thread creats a door that is
+// associated with a function that enqueues an operation to the attach
+// listener. The door is attached to a file in the file system so that
+// client (tools) can locate it. To enqueue an operation to the VM the
+// client calls through the door which invokes the enqueue function in
+// this process. The credentials of the client are checked and if the
+// effective uid matches this process then the operation is enqueued.
+// When an operation completes the attach listener is required to send the
+// operation result and any result data to the client. In this implementation
+// the result is returned via a UNIX domain socket. A pair of connected
+// sockets (socketpair) is created in the enqueue function and the file
+// descriptor for one of the sockets is returned to the client as the
+// return from the door call. The other end is retained in this process.
+// When the operation completes the result is sent to the client and
+// the socket is closed.
+
+// forward reference
+class SolarisAttachOperation;
+
+class SolarisAttachListener: AllStatic {
+ private:
+
+  // the path to which we attach the door file descriptor
+  static char _door_path[PATH_MAX+1];
+  static volatile bool _has_door_path;
+
+  // door descriptor returned by door_create
+  static int _door_descriptor;
+
+  static bool _atexit_registered;
+
+  // mutex to protect operation list
+  static mutex_t _mutex;
+
+  // semaphore to wakeup listener thread
+  static sema_t _wakeup;
+
+  static mutex_t* mutex()                               { return &_mutex; }
+  static sema_t* wakeup()                               { return &_wakeup; }
+
+  // enqueued operation list
+  static SolarisAttachOperation* _head;
+  static SolarisAttachOperation* _tail;
+
+  static SolarisAttachOperation* head()                 { return _head; }
+  static void set_head(SolarisAttachOperation* head)    { _head = head; }
+
+  static SolarisAttachOperation* tail()                 { return _tail; }
+  static void set_tail(SolarisAttachOperation* tail)    { _tail = tail; }
+
+  // create the door
+  static int create_door();
+
+ public:
+  enum {
+    ATTACH_PROTOCOL_VER = 1                             // protocol version
+  };
+  enum {
+    ATTACH_ERROR_BADREQUEST     = 100,                  // error code returned by
+    ATTACH_ERROR_BADVERSION     = 101,                  // the door call
+    ATTACH_ERROR_RESOURCE       = 102,
+    ATTACH_ERROR_INTERNAL       = 103,
+    ATTACH_ERROR_DENIED         = 104
+  };
+
+  static void set_door_path(char* path) {
+    if (path == NULL) {
+      _door_path[0] = '\0';
+      _has_door_path = false;
+    } else {
+      strncpy(_door_path, path, PATH_MAX);
+      _door_path[PATH_MAX] = '\0';      // ensure it's nul terminated
+      _has_door_path = true;
+    }
+  }
+
+  static void set_door_descriptor(int dd)               { _door_descriptor = dd; }
+
+  // initialize the listener
+  static int init();
+
+  static bool has_door_path()                           { return _has_door_path; }
+  static char* door_path()                              { return _door_path; }
+  static int door_descriptor()                          { return _door_descriptor; }
+
+  // enqueue an operation
+  static void enqueue(SolarisAttachOperation* op);
+
+  // dequeue an operation
+  static SolarisAttachOperation* dequeue();
+};
+
+
+// SolarisAttachOperation is an AttachOperation that additionally encapsulates
+// a socket connection to the requesting client/tool. SolarisAttachOperation
+// can additionally be held in a linked list.
+
+class SolarisAttachOperation: public AttachOperation {
+ private:
+  friend class SolarisAttachListener;
+
+  // connection to client
+  int _socket;
+
+  // linked list support
+  SolarisAttachOperation* _next;
+
+  SolarisAttachOperation* next()                         { return _next; }
+  void set_next(SolarisAttachOperation* next)            { _next = next; }
+
+ public:
+  void complete(jint res, bufferedStream* st);
+
+  int socket() const                                     { return _socket; }
+  void set_socket(int s)                                 { _socket = s; }
+
+  SolarisAttachOperation(char* name) : AttachOperation(name) {
+    set_socket(-1);
+    set_next(NULL);
+  }
+};
+
+// statics
+char SolarisAttachListener::_door_path[PATH_MAX+1];
+volatile bool SolarisAttachListener::_has_door_path;
+int SolarisAttachListener::_door_descriptor = -1;
+bool SolarisAttachListener::_atexit_registered = false;
+mutex_t SolarisAttachListener::_mutex;
+sema_t SolarisAttachListener::_wakeup;
+SolarisAttachOperation* SolarisAttachListener::_head = NULL;
+SolarisAttachOperation* SolarisAttachListener::_tail = NULL;
+
+// Supporting class to help split a buffer into individual components
+class ArgumentIterator : public StackObj {
+ private:
+  char* _pos;
+  char* _end;
+ public:
+  ArgumentIterator(char* arg_buffer, size_t arg_size) {
+    _pos = arg_buffer;
+    _end = _pos + arg_size - 1;
+  }
+  char* next() {
+    if (*_pos == '\0') {
+      // advance the iterator if possible (null arguments)
+      if (_pos < _end) {
+        _pos += 1;
+      }
+      return NULL;
+    }
+    char* res = _pos;
+    char* next_pos = strchr(_pos, '\0');
+    if (next_pos < _end)  {
+      next_pos++;
+    }
+    _pos = next_pos;
+    return res;
+  }
+};
+
+// Calls from the door function to check that the client credentials
+// match this process. Returns 0 if credentials okay, otherwise -1.
+static int check_credentials() {
+  ucred_t *cred_info = NULL;
+  int ret = -1; // deny by default
+
+  // get client credentials
+  if (door_ucred(&cred_info) == -1) {
+    return -1; // unable to get them, deny
+  }
+
+  // get euid/egid from ucred_free
+  uid_t ucred_euid = ucred_geteuid(cred_info);
+  gid_t ucred_egid = ucred_getegid(cred_info);
+
+  // check that the effective uid/gid matches
+  if (os::Posix::matches_effective_uid_and_gid_or_root(ucred_euid, ucred_egid)) {
+    ret =  0;  // allow
+  }
+
+  ucred_free(cred_info);
+  return ret;
+}
+
+
+// Parses the argument buffer to create an AttachOperation that we should
+// enqueue to the attach listener.
+// The buffer is expected to be formatted as follows:
+// <ver>0<cmd>0<arg>0<arg>0<arg>0
+// where <ver> is the version number (must be "1"), <cmd> is the command
+// name ("load, "datadump", ...) and <arg> is an argument.
+//
+static SolarisAttachOperation* create_operation(char* argp, size_t arg_size, int* err) {
+  // assume bad request until parsed
+  *err = SolarisAttachListener::ATTACH_ERROR_BADREQUEST;
+
+  if (arg_size < 2 || argp[arg_size-1] != '\0') {
+    return NULL;   // no ver or not null terminated
+  }
+
+  // Use supporting class to iterate over the buffer
+  ArgumentIterator args(argp, arg_size);
+
+  // First check the protocol version
+  char* ver = args.next();
+  if (ver == NULL) {
+    return NULL;
+  }
+  if (atoi(ver) != SolarisAttachListener::ATTACH_PROTOCOL_VER) {
+    *err = SolarisAttachListener::ATTACH_ERROR_BADVERSION;
+    return NULL;
+  }
+
+  // Get command name and create the operation
+  char* name = args.next();
+  if (name == NULL || strlen(name) > AttachOperation::name_length_max) {
+    return NULL;
+  }
+  SolarisAttachOperation* op = new SolarisAttachOperation(name);
+
+  // Iterate over the arguments
+  for (int i=0; i<AttachOperation::arg_count_max; i++) {
+    char* arg = args.next();
+    if (arg == NULL) {
+      op->set_arg(i, NULL);
+    } else {
+      if (strlen(arg) > AttachOperation::arg_length_max) {
+        delete op;
+        return NULL;
+      }
+      op->set_arg(i, arg);
+    }
+  }
+
+  // return operation
+  *err = 0;
+  return op;
+}
+
+// This is door function which the client executes via a door_call.
+extern "C" {
+  static void enqueue_proc(void* cookie, char* argp, size_t arg_size,
+                           door_desc_t* dt, uint_t n_desc)
+  {
+    int return_fd = -1;
+    SolarisAttachOperation* op = NULL;
+
+    // wait up to 10 seconds for listener to be up and running
+    jint res = 0;
+    int sleep_count = 0;
+    while (!AttachListener::is_initialized()) {
+      sleep(1); // 1 second
+      sleep_count++;
+      if (sleep_count > 10) { // try for 10 seconds
+        debug_only(warning("door_call when not enabled"));
+        res = (jint)SolarisAttachListener::ATTACH_ERROR_INTERNAL;
+        break;
+      }
+    }
+
+    // check client credentials
+    if (res == 0) {
+      if (check_credentials() != 0) {
+        res = (jint)SolarisAttachListener::ATTACH_ERROR_DENIED;
+      }
+    }
+
+    // if we are stopped at ShowMessageBoxOnError then maybe we can
+    // load a diagnostic library
+    if (res == 0 && VMError::is_error_reported()) {
+      if (ShowMessageBoxOnError) {
+        // TBD - support loading of diagnostic library here
+      }
+
+      // can't enqueue operation after fatal error
+      res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
+    }
+
+    // create the operation
+    if (res == 0) {
+      int err;
+      op = create_operation(argp, arg_size, &err);
+      res = (op == NULL) ? (jint)err : 0;
+    }
+
+    // create a pair of connected sockets. Store the file descriptor
+    // for one end in the operation and enqueue the operation. The
+    // file descriptor for the other end wil be returned to the client.
+    if (res == 0) {
+      int s[2];
+      if (socketpair(PF_UNIX, SOCK_STREAM, 0, s) < 0) {
+        delete op;
+        res = (jint)SolarisAttachListener::ATTACH_ERROR_RESOURCE;
+      } else {
+        op->set_socket(s[0]);
+        return_fd = s[1];
+        SolarisAttachListener::enqueue(op);
+      }
+    }
+
+    // Return 0 (success) + file descriptor, or non-0 (error)
+    if (res == 0) {
+      door_desc_t desc;
+      // DOOR_RELEASE flag makes sure fd is closed after passing it to
+      // the client.  See door_return(3DOOR) man page.
+      desc.d_attributes = DOOR_DESCRIPTOR | DOOR_RELEASE;
+      desc.d_data.d_desc.d_descriptor = return_fd;
+      door_return((char*)&res, sizeof(res), &desc, 1);
+    } else {
+      door_return((char*)&res, sizeof(res), NULL, 0);
+    }
+  }
+}
+
+// atexit hook to detach the door and remove the file
+extern "C" {
+  static void listener_cleanup() {
+    int dd = SolarisAttachListener::door_descriptor();
+    if (dd >= 0) {
+      SolarisAttachListener::set_door_descriptor(-1);
+      ::close(dd);
+    }
+    if (SolarisAttachListener::has_door_path()) {
+      char* path = SolarisAttachListener::door_path();
+      ::fdetach(path);
+      ::unlink(path);
+      SolarisAttachListener::set_door_path(NULL);
+    }
+  }
+}
+
+// Create the door
+int SolarisAttachListener::create_door() {
+  char door_path[PATH_MAX+1];
+  char initial_path[PATH_MAX+1];
+  int fd, res;
+
+  // register exit function
+  if (!_atexit_registered) {
+    _atexit_registered = true;
+    ::atexit(listener_cleanup);
+  }
+
+  // create the door descriptor
+  int dd = ::door_create(enqueue_proc, NULL, 0);
+  if (dd < 0) {
+    return -1;
+  }
+
+  // create initial file to attach door descriptor
+  snprintf(door_path, sizeof(door_path), "%s/.java_pid%d",
+           os::get_temp_directory(), os::current_process_id());
+  snprintf(initial_path, sizeof(initial_path), "%s.tmp", door_path);
+  RESTARTABLE(::creat(initial_path, S_IRUSR | S_IWUSR), fd);
+  if (fd == -1) {
+    log_debug(attach)("attempt to create door file %s failed (%d)", initial_path, errno);
+    ::door_revoke(dd);
+    return -1;
+  }
+  assert(fd >= 0, "bad file descriptor");
+  ::close(fd);
+
+  // attach the door descriptor to the file
+  if ((res = ::fattach(dd, initial_path)) == -1) {
+    // if busy then detach and try again
+    if (errno == EBUSY) {
+      ::fdetach(initial_path);
+      res = ::fattach(dd, initial_path);
+    }
+    if (res == -1) {
+      log_debug(attach)("unable to create door - fattach failed (%d)", errno);
+      ::door_revoke(dd);
+      dd = -1;
+    }
+  }
+
+  // rename file so that clients can attach
+  if (dd >= 0) {
+    if (::rename(initial_path, door_path) == -1) {
+        ::close(dd);
+        ::fdetach(initial_path);
+        log_debug(attach)("unable to create door - rename %s to %s failed (%d)", initial_path, door_path, errno);
+        dd = -1;
+    }
+  }
+  if (dd >= 0) {
+    set_door_descriptor(dd);
+    set_door_path(door_path);
+    log_trace(attach)("door file %s created succesfully", door_path);
+  } else {
+    // unable to create door, attach it to file, or rename file into place
+    ::unlink(initial_path);
+    return -1;
+  }
+
+  return 0;
+}
+
+// Initialization - create the door, locks, and other initialization
+int SolarisAttachListener::init() {
+  if (create_door()) {
+    return -1;
+  }
+
+  int status = os::Solaris::mutex_init(&_mutex);
+  assert_status(status==0, status, "mutex_init");
+
+  status = ::sema_init(&_wakeup, 0, NULL, NULL);
+  assert_status(status==0, status, "sema_init");
+
+  set_head(NULL);
+  set_tail(NULL);
+
+  return 0;
+}
+
+// Dequeue an operation
+SolarisAttachOperation* SolarisAttachListener::dequeue() {
+  for (;;) {
+    int res;
+
+    // wait for somebody to enqueue something
+    while ((res = ::sema_wait(wakeup())) == EINTR)
+      ;
+    if (res) {
+      warning("sema_wait failed: %s", os::strerror(res));
+      return NULL;
+    }
+
+    // lock the list
+    res = os::Solaris::mutex_lock(mutex());
+    assert(res == 0, "mutex_lock failed");
+
+    // remove the head of the list
+    SolarisAttachOperation* op = head();
+    if (op != NULL) {
+      set_head(op->next());
+      if (head() == NULL) {
+        set_tail(NULL);
+      }
+    }
+
+    // unlock
+    os::Solaris::mutex_unlock(mutex());
+
+    // if we got an operation when return it.
+    if (op != NULL) {
+      return op;
+    }
+  }
+}
+
+// Enqueue an operation
+void SolarisAttachListener::enqueue(SolarisAttachOperation* op) {
+  // lock list
+  int res = os::Solaris::mutex_lock(mutex());
+  assert(res == 0, "mutex_lock failed");
+
+  // enqueue at tail
+  op->set_next(NULL);
+  if (head() == NULL) {
+    set_head(op);
+  } else {
+    tail()->set_next(op);
+  }
+  set_tail(op);
+
+  // wakeup the attach listener
+  RESTARTABLE(::sema_post(wakeup()), res);
+  assert(res == 0, "sema_post failed");
+
+  // unlock
+  os::Solaris::mutex_unlock(mutex());
+}
+
+
+// support function - writes the (entire) buffer to a socket
+static int write_fully(int s, char* buf, int len) {
+  do {
+    int n = ::write(s, buf, len);
+    if (n == -1) {
+      if (errno != EINTR) return -1;
+    } else {
+      buf += n;
+      len -= n;
+    }
+  }
+  while (len > 0);
+  return 0;
+}
+
+// Complete an operation by sending the operation result and any result
+// output to the client. At this time the socket is in blocking mode so
+// potentially we can block if there is a lot of data and the client is
+// non-responsive. For most operations this is a non-issue because the
+// default send buffer is sufficient to buffer everything. In the future
+// if there are operations that involves a very big reply then it the
+// socket could be made non-blocking and a timeout could be used.
+
+void SolarisAttachOperation::complete(jint res, bufferedStream* st) {
+  if (this->socket() >= 0) {
+    JavaThread* thread = JavaThread::current();
+    ThreadBlockInVM tbivm(thread);
+
+    // write operation result
+    char msg[32];
+    sprintf(msg, "%d\n", res);
+    int rc = write_fully(this->socket(), msg, strlen(msg));
+
+    // write any result data
+    if (rc == 0) {
+      write_fully(this->socket(), (char*) st->base(), st->size());
+      ::shutdown(this->socket(), 2);
+    }
+
+    // close socket and we're done
+    ::close(this->socket());
+  }
+  delete this;
+}
+
+
+// AttachListener functions
+
+AttachOperation* AttachListener::dequeue() {
+  JavaThread* thread = JavaThread::current();
+  ThreadBlockInVM tbivm(thread);
+
+  AttachOperation* op = SolarisAttachListener::dequeue();
+
+  return op;
+}
+
+
+// Performs initialization at vm startup
+// For Solaris we remove any stale .java_pid file which could cause
+// an attaching process to think we are ready to receive a door_call
+// before we are properly initialized
+
+void AttachListener::vm_start() {
+  char fn[PATH_MAX+1];
+  struct stat64 st;
+  int ret;
+
+  int n = snprintf(fn, sizeof(fn), "%s/.java_pid%d",
+           os::get_temp_directory(), os::current_process_id());
+  assert(n < sizeof(fn), "java_pid file name buffer overflow");
+
+  RESTARTABLE(::stat64(fn, &st), ret);
+  if (ret == 0) {
+    ret = ::unlink(fn);
+    if (ret == -1) {
+      log_debug(attach)("Failed to remove stale attach pid file at %s", fn);
+    }
+  }
+}
+
+int AttachListener::pd_init() {
+  JavaThread* thread = JavaThread::current();
+  ThreadBlockInVM tbivm(thread);
+
+  int ret_code = SolarisAttachListener::init();
+
+  return ret_code;
+}
+
+// Attach Listener is started lazily except in the case when
+// +ReduseSignalUsage is used
+bool AttachListener::init_at_startup() {
+  if (ReduceSignalUsage) {
+    return true;
+  } else {
+    return false;
+  }
+}
+
+bool AttachListener::check_socket_file() {
+  int ret;
+  struct stat64 st;
+  ret = stat64(SolarisAttachListener::door_path(), &st);
+  if (ret == -1) { // need to restart attach listener.
+    log_debug(attach)("Door file %s does not exist - Restart Attach Listener",
+                      SolarisAttachListener::door_path());
+
+    listener_cleanup();
+
+    // wait to terminate current attach listener instance...
+    while (AttachListener::transit_state(AL_INITIALIZING,
+                                         AL_NOT_INITIALIZED) != AL_NOT_INITIALIZED) {
+      os::naked_yield();
+    }
+    return is_init_trigger();
+  }
+  return false;
+}
+
+// If the file .attach_pid<pid> exists in the working directory
+// or /tmp then this is the trigger to start the attach mechanism
+bool AttachListener::is_init_trigger() {
+  if (init_at_startup() || is_initialized()) {
+    return false;               // initialized at startup or already initialized
+  }
+  char fn[PATH_MAX + 1];
+  int ret;
+  struct stat64 st;
+  sprintf(fn, ".attach_pid%d", os::current_process_id());
+  RESTARTABLE(::stat64(fn, &st), ret);
+  if (ret == -1) {
+    log_trace(attach)("Failed to find attach file: %s, trying alternate", fn);
+    snprintf(fn, sizeof(fn), "%s/.attach_pid%d",
+             os::get_temp_directory(), os::current_process_id());
+    RESTARTABLE(::stat64(fn, &st), ret);
+    if (ret == -1) {
+      log_debug(attach)("Failed to find attach file: %s", fn);
+    }
+  }
+  if (ret == 0) {
+    // simple check to avoid starting the attach mechanism when
+    // a bogus non-root user creates the file
+    if (os::Posix::matches_effective_uid_or_root(st.st_uid)) {
+      init();
+      log_trace(attach)("Attach triggered by %s", fn);
+      return true;
+    } else {
+      log_debug(attach)("File %s has wrong user id %d (vs %d). Attach is not triggered", fn, st.st_uid, geteuid());
+    }
+  }
+  return false;
+}
+
+// if VM aborts then detach/cleanup
+void AttachListener::abort() {
+  listener_cleanup();
+}
+
+void AttachListener::pd_data_dump() {
+  os::signal_notify(SIGQUIT);
+}
+
+static jint enable_dprobes(AttachOperation* op, outputStream* out) {
+  const char* probe = op->arg(0);
+  if (probe == NULL || probe[0] == '\0') {
+    out->print_cr("No probe specified");
+    return JNI_ERR;
+  } else {
+    char *end;
+    long val = strtol(probe, &end, 10);
+    if (end == probe || val < 0 || val > INT_MAX) {
+      out->print_cr("invalid probe type");
+      return JNI_ERR;
+    } else {
+      int probe_typess = (int) val;
+      DTrace::enable_dprobes(probe_typess);
+      return JNI_OK;
+    }
+  }
+}
+
+// platform specific operations table
+static AttachOperationFunctionInfo funcs[] = {
+  { "enabledprobes", enable_dprobes },
+  { NULL, NULL }
+};
+
+AttachOperationFunctionInfo* AttachListener::pd_find_operation(const char* name) {
+  int i;
+  for (i = 0; funcs[i].name != NULL; i++) {
+    if (strcmp(funcs[i].name, name) == 0) {
+      return &funcs[i];
+    }
+  }
+  return NULL;
+}
+
+// Solaris specific global flag set. Currently, we support only
+// changing ExtendedDTraceProbes flag.
+jint AttachListener::pd_set_flag(AttachOperation* op, outputStream* out) {
+  const char* name = op->arg(0);
+  assert(name != NULL, "flag name should not be null");
+  bool flag = true;
+  const char* arg1;
+  if ((arg1 = op->arg(1)) != NULL) {
+    char *end;
+    flag = (strtol(arg1, &end, 10) != 0);
+    if (arg1 == end) {
+      out->print_cr("flag value has to be an integer");
+      return JNI_ERR;
+    }
+  }
+
+  if (strcmp(name, "ExtendedDTraceProbes") == 0) {
+    DTrace::set_extended_dprobes(flag);
+    return JNI_OK;
+  }
+
+  if (strcmp(name, "DTraceMonitorProbes") == 0) {
+    DTrace::set_monitor_dprobes(flag);
+    return JNI_OK;
+  }
+
+  out->print_cr("flag '%s' cannot be changed", name);
+  return JNI_ERR;
+}
+
+void AttachListener::pd_detachall() {
+  DTrace::detach_all_clients();
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/c1_globals_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/c1_globals_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/c1_globals_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/c1_globals_solaris.hpp	2024-08-17 18:29:44.538653808 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
+#define OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for operating system dependent flags used by the
+// client compiler. (see c1_globals.hpp)
+//
+
+#endif // OS_SOLARIS_C1_GLOBALS_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/c2_globals_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/c2_globals_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/c2_globals_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/c2_globals_solaris.hpp	2024-08-17 18:29:44.538947190 +0200
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
+#define OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
+
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+//
+// Sets the default values for operating system dependent flags used by the
+// server compiler. (see c2_globals.hpp)
+//
+
+#endif // OS_SOLARIS_C2_GLOBALS_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/decoder_solaris.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/decoder_solaris.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/decoder_solaris.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/decoder_solaris.cpp	2024-08-17 18:29:44.539230449 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1997, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "utilities/decoder_elf.hpp"
+
+#include <demangle.h>
+
+bool ElfDecoder::demangle(const char* symbol, char *buf, int buflen) {
+  return !cplus_demangle(symbol, buf, (size_t)buflen);
+}
+
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/dtrace/jhelper.d jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/dtrace/jhelper.d
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/dtrace/jhelper.d	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/dtrace/jhelper.d	2024-08-17 18:29:44.539846334 +0200
@@ -0,0 +1,540 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/* This file is auto-generated */
+#include "JvmOffsetsIndex.h"
+
+#define DEBUG
+
+#ifdef DEBUG
+#define MARK_LINE this->line = __LINE__
+#else
+#define MARK_LINE
+#endif
+
+#ifdef _LP64
+#define STACK_BIAS 0x7ff
+#define pointer uint64_t
+#else
+#define STACK_BIAS 0
+#define pointer uint32_t
+#endif
+
+extern pointer __JvmOffsets;
+
+/* GrowableArray<CodeHeaps*>* */
+extern pointer __1cJCodeCacheG_heaps_;
+
+extern pointer __1cIUniverseO_collectedHeap_;
+
+extern pointer __1cHnmethodG__vtbl_;
+extern pointer __1cGMethodG__vtbl_;
+extern pointer __1cKBufferBlobG__vtbl_;
+
+#define copyin_ptr(ADDR)    *(pointer*)  copyin((pointer) (ADDR), sizeof(pointer))
+#define copyin_uchar(ADDR)  *(uchar_t*)  copyin((pointer) (ADDR), sizeof(uchar_t))
+#define copyin_uint16(ADDR) *(uint16_t*) copyin((pointer) (ADDR), sizeof(uint16_t))
+#define copyin_uint32(ADDR) *(uint32_t*) copyin((pointer) (ADDR), sizeof(uint32_t))
+#define copyin_int32(ADDR)  *(int32_t*)  copyin((pointer) (ADDR), sizeof(int32_t))
+#define copyin_uint8(ADDR)  *(uint8_t*)  copyin((pointer) (ADDR), sizeof(uint8_t))
+
+#define copyin_offset(JVM_CONST)  JVM_CONST = \
+	copyin_int32(JvmOffsetsPtr + IDX_##JVM_CONST * sizeof(int32_t))
+
+int init_done;
+
+dtrace:helper:ustack:
+{
+  MARK_LINE;
+  this->done = 0;
+  /*
+   * TBD:
+   * Here we initialize init_done, otherwise jhelper does not work.
+   * Therefore, copyin_offset() statements work multiple times now.
+   * There is a hope we could avoid it in the future, and so,
+   * this initialization can be removed.
+   */
+  init_done  = 0;
+  this->error = (char *) NULL;
+  this->result = (char *) NULL;
+  this->isMethod = 0;
+  this->codecache = 0;
+  this->klass = (pointer) NULL;
+  this->vtbl  = (pointer) NULL;
+  this->suffix = '\0';
+}
+
+dtrace:helper:ustack:
+{
+  MARK_LINE;
+  /* Initialization of JvmOffsets constants */
+  JvmOffsetsPtr = (pointer) &``__JvmOffsets;
+}
+
+dtrace:helper:ustack:
+/!init_done && !this->done/
+{
+  MARK_LINE;
+
+  copyin_offset(POINTER_SIZE);
+  copyin_offset(COMPILER);
+  copyin_offset(OFFSET_CollectedHeap_reserved);
+  copyin_offset(OFFSET_MemRegion_start);
+  copyin_offset(OFFSET_MemRegion_word_size);
+  copyin_offset(SIZE_HeapWord);
+
+  copyin_offset(OFFSET_interpreter_frame_method);
+  copyin_offset(OFFSET_Klass_name);
+  copyin_offset(OFFSET_ConstantPool_pool_holder);
+
+  copyin_offset(OFFSET_HeapBlockHeader_used);
+  copyin_offset(OFFSET_oopDesc_metadata);
+
+  copyin_offset(OFFSET_Symbol_length);
+  copyin_offset(OFFSET_Symbol_body);
+
+  copyin_offset(OFFSET_Method_constMethod);
+  copyin_offset(OFFSET_ConstMethod_constants);
+  copyin_offset(OFFSET_ConstMethod_name_index);
+  copyin_offset(OFFSET_ConstMethod_signature_index);
+
+  copyin_offset(OFFSET_CodeHeap_memory);
+  copyin_offset(OFFSET_CodeHeap_segmap);
+  copyin_offset(OFFSET_CodeHeap_log2_segment_size);
+
+  copyin_offset(OFFSET_GrowableArray_CodeHeap_data);
+  copyin_offset(OFFSET_GrowableArray_CodeHeap_len);
+
+  copyin_offset(OFFSET_VirtualSpace_low);
+  copyin_offset(OFFSET_VirtualSpace_high);
+
+  copyin_offset(OFFSET_CodeBlob_name);
+
+  copyin_offset(OFFSET_nmethod_method);
+  copyin_offset(SIZE_HeapBlockHeader);
+  copyin_offset(SIZE_oopDesc);
+  copyin_offset(SIZE_ConstantPool);
+
+  copyin_offset(OFFSET_NarrowPtrStruct_base);
+  copyin_offset(OFFSET_NarrowPtrStruct_shift);
+
+  /*
+   * The PC to translate is in arg0.
+   */
+  this->pc = arg0;
+
+#if defined(__i386) || defined(__amd64)
+  this->methodPtr = copyin_ptr(arg1 + OFFSET_interpreter_frame_method);
+#else
+#error "Don't know architecture"
+#endif
+
+  /* Read address of GrowableArray<CodeHeaps*> */
+  // this->code_heaps_address = copyin_ptr(&``__1cJCodeCacheG_heaps_);
+  this->code_heaps_address =  * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cJCodeCacheG_heaps_ ) , sizeof ( uint64_t ) );
+
+  /* Read address of _data array field in GrowableArray */
+  this->code_heaps_array_address = copyin_ptr(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_data);
+  this->number_of_heaps = copyin_uint32(this->code_heaps_address + OFFSET_GrowableArray_CodeHeap_len);
+
+  this->Method_vtbl = (pointer) &``__1cGMethodG__vtbl_;
+
+  /*
+   * Get Java heap bounds
+   */
+  // this->Universe_collectedHeap = copyin_ptr(&``__1cIUniverseO_collectedHeap_);
+  this->Universe_collectedHeap =  * ( uint64_t * ) copyin ( ( uint64_t ) ( &``__1cIUniverseO_collectedHeap_ ) , sizeof ( uint64_t ) );
+
+  this->heap_start = copyin_ptr(this->Universe_collectedHeap +
+      OFFSET_CollectedHeap_reserved +
+      OFFSET_MemRegion_start);
+  this->heap_size = SIZE_HeapWord *
+    copyin_ptr(this->Universe_collectedHeap +
+        OFFSET_CollectedHeap_reserved +
+        OFFSET_MemRegion_word_size
+        );
+  this->heap_end = this->heap_start + this->heap_size;
+}
+
+/*
+ * IMPORTANT: At the moment the ustack helper supports up to 5 code heaps in
+ * the code cache. If more code heaps are added the following probes have to
+ * be extended. This is done by simply adding a probe to get the heap bounds
+ * and another probe to set the code heap address of the newly created heap.
+ */
+
+/*
+ * ----- BEGIN: Get bounds of code heaps -----
+ */
+dtrace:helper:ustack:
+/init_done < 1 && this->number_of_heaps >= 1 && !this->done/
+{
+  MARK_LINE;
+  /* CodeHeap 1 */
+  init_done = 1;
+  this->code_heap1_address = copyin_ptr(this->code_heaps_array_address);
+  this->code_heap1_low = copyin_ptr(this->code_heap1_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
+  this->code_heap1_high = copyin_ptr(this->code_heap1_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
+}
+
+dtrace:helper:ustack:
+/init_done < 2 && this->number_of_heaps >= 2 && !this->done/
+{
+  MARK_LINE;
+  /* CodeHeap 2 */
+  init_done = 2;
+  this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
+  this->code_heap2_address = copyin_ptr(this->code_heaps_array_address);
+  this->code_heap2_low = copyin_ptr(this->code_heap2_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
+  this->code_heap2_high = copyin_ptr(this->code_heap2_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
+}
+
+dtrace:helper:ustack:
+/init_done < 3 && this->number_of_heaps >= 3 && !this->done/
+{
+  /* CodeHeap 3 */
+  init_done = 3;
+  this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
+  this->code_heap3_address = copyin_ptr(this->code_heaps_array_address);
+  this->code_heap3_low = copyin_ptr(this->code_heap3_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
+  this->code_heap3_high = copyin_ptr(this->code_heap3_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
+}
+
+dtrace:helper:ustack:
+/init_done < 4 && this->number_of_heaps >= 4 && !this->done/
+{
+  /* CodeHeap 4 */
+  init_done = 4;
+  this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
+  this->code_heap4_address = copyin_ptr(this->code_heaps_array_address);
+  this->code_heap4_low = copyin_ptr(this->code_heap4_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
+  this->code_heap4_high = copyin_ptr(this->code_heap4_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
+}
+
+dtrace:helper:ustack:
+/init_done < 5 && this->number_of_heaps >= 5 && !this->done/
+{
+  /* CodeHeap 5 */
+  init_done = 5;
+  this->code_heaps_array_address = this->code_heaps_array_address + POINTER_SIZE;
+  this->code_heap5_address = copyin_ptr(this->code_heaps_array_address);
+  this->code_heap5_low = copyin_ptr(this->code_heap5_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
+  this->code_heap5_high = copyin_ptr(this->code_heap5_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_high);
+}
+/*
+ * ----- END: Get bounds of code heaps -----
+ */
+
+/*
+ * ----- BEGIN: Get address of the code heap pc points to -----
+ */
+dtrace:helper:ustack:
+/!this->done && this->number_of_heaps >= 1 && this->code_heap1_low <= this->pc && this->pc < this->code_heap1_high/
+{
+  MARK_LINE;
+  this->codecache = 1;
+  this->code_heap_address = this->code_heap1_address;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->number_of_heaps >= 2 && this->code_heap2_low <= this->pc && this->pc < this->code_heap2_high/
+{
+  MARK_LINE;
+  this->codecache = 1;
+  this->code_heap_address = this->code_heap2_address;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->number_of_heaps >= 3 && this->code_heap3_low <= this->pc && this->pc < this->code_heap3_high/
+{
+  MARK_LINE;
+  this->codecache = 1;
+  this->code_heap_address = this->code_heap3_address;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->number_of_heaps >= 4 && this->code_heap4_low <= this->pc && this->pc < this->code_heap4_high/
+{
+  MARK_LINE;
+  this->codecache = 1;
+  this->code_heap_address = this->code_heap4_address;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->number_of_heaps >= 5 && this->code_heap5_low <= this->pc && this->pc < this->code_heap5_high/
+{
+  MARK_LINE;
+  this->codecache = 1;
+  this->code_heap_address = this->code_heap5_address;
+}
+/*
+ * ----- END: Get address of the code heap pc points to -----
+ */
+
+dtrace:helper:ustack:
+/!this->done && this->codecache/
+{
+  MARK_LINE;
+  /*
+   * Get code heap configuration
+   */
+  this->code_heap_low = copyin_ptr(this->code_heap_address +
+      OFFSET_CodeHeap_memory + OFFSET_VirtualSpace_low);
+  this->code_heap_segmap_low = copyin_ptr(this->code_heap_address +
+      OFFSET_CodeHeap_segmap + OFFSET_VirtualSpace_low);
+  this->code_heap_log2_segment_size = copyin_uint32(
+      this->code_heap_address + OFFSET_CodeHeap_log2_segment_size);
+
+  /*
+   * Find start
+   */
+  this->segment = (this->pc - this->code_heap_low) >>
+    this->code_heap_log2_segment_size;
+  this->block = this->code_heap_segmap_low;
+  this->tag = copyin_uchar(this->block + this->segment);
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && this->tag > 0/
+{
+  MARK_LINE;
+  this->tag = copyin_uchar(this->block + this->segment);
+  this->segment = this->segment - this->tag;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && this->tag > 0/
+{
+  MARK_LINE;
+  this->tag = copyin_uchar(this->block + this->segment);
+  this->segment = this->segment - this->tag;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && this->tag > 0/
+{
+  MARK_LINE;
+  this->tag = copyin_uchar(this->block + this->segment);
+  this->segment = this->segment - this->tag;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && this->tag > 0/
+{
+  MARK_LINE;
+  this->tag = copyin_uchar(this->block + this->segment);
+  this->segment = this->segment - this->tag;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && this->tag > 0/
+{
+  MARK_LINE;
+  this->tag = copyin_uchar(this->block + this->segment);
+  this->segment = this->segment - this->tag;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && this->tag > 0/
+{
+  MARK_LINE;
+  this->error = "<couldn't find start>";
+  this->done = 1;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache/
+{
+  MARK_LINE;
+  this->block = this->code_heap_low +
+    (this->segment << this->code_heap_log2_segment_size);
+  this->used = copyin_uint32(this->block + OFFSET_HeapBlockHeader_used);
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache && !this->used/
+{
+  MARK_LINE;
+  this->error = "<block not in use>";
+  this->done = 1;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache/
+{
+  MARK_LINE;
+  this->start = this->block + SIZE_HeapBlockHeader;
+  this->vtbl = copyin_ptr(this->start);
+
+  this->nmethod_vtbl            = (pointer) &``__1cHnmethodG__vtbl_;
+  this->BufferBlob_vtbl         = (pointer) &``__1cKBufferBlobG__vtbl_;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->vtbl == this->nmethod_vtbl/
+{
+  MARK_LINE;
+  this->methodPtr = copyin_ptr(this->start + OFFSET_nmethod_method);
+  this->suffix = '*';
+  this->isMethod = 1;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->vtbl == this->BufferBlob_vtbl/
+{
+  MARK_LINE;
+  this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name);
+}
+
+
+dtrace:helper:ustack:
+/!this->done && this->vtbl == this->BufferBlob_vtbl && this->methodPtr != 0/
+{
+  MARK_LINE;
+  this->klass = copyin_ptr(this->methodPtr);
+  this->isMethod = this->klass == this->Method_vtbl;
+  this->done = !this->isMethod;
+}
+
+dtrace:helper:ustack:
+/!this->done && !this->isMethod/
+{
+  MARK_LINE;
+  this->name = copyin_ptr(this->start + OFFSET_CodeBlob_name);
+  this->result = this->name != 0 ? copyinstr(this->name) : "<CodeBlob>";
+  this->done = 1;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->isMethod/
+{
+  MARK_LINE;
+  this->constMethod = copyin_ptr(this->methodPtr +
+      OFFSET_Method_constMethod);
+
+  this->nameIndex = copyin_uint16(this->constMethod +
+      OFFSET_ConstMethod_name_index);
+
+  this->signatureIndex = copyin_uint16(this->constMethod +
+      OFFSET_ConstMethod_signature_index);
+
+  this->constantPool = copyin_ptr(this->constMethod +
+      OFFSET_ConstMethod_constants);
+
+  this->nameSymbol = copyin_ptr(this->constantPool +
+      this->nameIndex * sizeof (pointer) + SIZE_ConstantPool);
+  /* The symbol is a CPSlot and has lower bit set to indicate metadata */
+  this->nameSymbol &= (~1); /* remove metadata lsb */
+
+  this->nameSymbolLength = copyin_uint16(this->nameSymbol +
+      OFFSET_Symbol_length);
+
+  this->signatureSymbol = copyin_ptr(this->constantPool +
+      this->signatureIndex * sizeof (pointer) + SIZE_ConstantPool);
+  this->signatureSymbol &= (~1); /* remove metadata lsb */
+
+  this->signatureSymbolLength = copyin_uint16(this->signatureSymbol +
+      OFFSET_Symbol_length);
+
+  this->klassPtr = copyin_ptr(this->constantPool +
+      OFFSET_ConstantPool_pool_holder);
+
+  this->klassSymbol = copyin_ptr(this->klassPtr +
+      OFFSET_Klass_name);
+
+  this->klassSymbolLength = copyin_uint16(this->klassSymbol +
+      OFFSET_Symbol_length);
+
+  /*
+   * Enough for three strings, plus the '.', plus the trailing '\0'.
+   */
+  this->result = (char *) alloca(this->klassSymbolLength +
+      this->nameSymbolLength +
+      this->signatureSymbolLength + 2 + 1);
+
+  copyinto(this->klassSymbol + OFFSET_Symbol_body,
+      this->klassSymbolLength, this->result);
+
+  /*
+   * Add the '.' between the class and the name.
+   */
+  this->result[this->klassSymbolLength] = '.';
+
+  copyinto(this->nameSymbol + OFFSET_Symbol_body,
+      this->nameSymbolLength,
+      this->result + this->klassSymbolLength + 1);
+
+  copyinto(this->signatureSymbol + OFFSET_Symbol_body,
+      this->signatureSymbolLength,
+      this->result + this->klassSymbolLength +
+      this->nameSymbolLength + 1);
+
+  /*
+   * Now we need to add a trailing '\0' and possibly a tag character.
+   */
+  this->result[this->klassSymbolLength + 1 +
+      this->nameSymbolLength +
+      this->signatureSymbolLength] = this->suffix;
+  this->result[this->klassSymbolLength + 2 +
+      this->nameSymbolLength +
+      this->signatureSymbolLength] = '\0';
+
+  this->done = 1;
+}
+
+dtrace:helper:ustack:
+/this->done && this->error == (char *) NULL/
+{
+  this->result;
+}
+
+dtrace:helper:ustack:
+/this->done && this->error != (char *) NULL/
+{
+  this->error;
+}
+
+dtrace:helper:ustack:
+/!this->done && this->codecache/
+{
+  this->done = 1;
+  "error";
+}
+
+
+dtrace:helper:ustack:
+/!this->done/
+{
+  NULL;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/globals_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/globals_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/globals_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/globals_solaris.hpp	2024-08-17 18:29:44.540153434 +0200
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2005, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_GLOBALS_SOLARIS_HPP
+#define OS_SOLARIS_GLOBALS_SOLARIS_HPP
+
+//
+// Defines Solaris specific flags. They are not available on other platforms.
+//
+#define RUNTIME_OS_FLAGS(develop, \
+                         develop_pd, \
+                         product, \
+                         product_pd, \
+                         notproduct, \
+                         range, \
+                         constraint)
+
+//
+// Defines Solaris-specific default values. The flags are available on all
+// platforms, but they may have different default values on other platforms.
+//
+define_pd_global(size_t, PreTouchParallelChunkSize, 1 * G);
+define_pd_global(bool, UseLargePages, true);
+define_pd_global(bool, UseLargePagesIndividualAllocation, false);
+define_pd_global(bool, UseOSErrorReporting, false);
+define_pd_global(bool, UseThreadPriorities, false);
+
+#endif // OS_SOLARIS_GLOBALS_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_perf_solaris.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_perf_solaris.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_perf_solaris.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_perf_solaris.cpp	2024-08-17 18:29:44.541429258 +0200
@@ -0,0 +1,808 @@
+/*
+ * Copyright (c) 2012, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "jvm.h"
+#include "memory/allocation.inline.hpp"
+#include "runtime/os.hpp"
+#include "runtime/os_perf.hpp"
+#include "os_solaris.inline.hpp"
+#include "utilities/globalDefinitions.hpp"
+#include "utilities/macros.hpp"
+
+#include CPU_HEADER(vm_version_ext)
+
+#include <sys/types.h>
+#include <procfs.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <strings.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <kstat.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/sysinfo.h>
+#include <sys/lwp.h>
+#include <pthread.h>
+#include <time.h>
+#include <utmpx.h>
+#include <dlfcn.h>
+#include <sys/loadavg.h>
+#include <limits.h>
+
+static const double NANOS_PER_SEC = 1000000000.0;
+
+struct CPUPerfTicks {
+  kstat_t* kstat;
+  uint64_t last_idle;
+  uint64_t last_total;
+  double   last_ratio;
+};
+
+struct CPUPerfCounters {
+  int           nProcs;
+  CPUPerfTicks* jvmTicks;
+  kstat_ctl_t*  kstat_ctrl;
+};
+
+static int get_info(const char* path, void* info, size_t s, off_t o) {
+  assert(path != NULL, "path is NULL!");
+  assert(info != NULL, "info is NULL!");
+
+  int fd = -1;
+
+  if ((fd = os::open(path, O_RDONLY, 0)) < 0) {
+    return OS_ERR;
+  }
+  if (pread(fd, info, s, o) != s) {
+    close(fd);
+    return OS_ERR;
+  }
+  close(fd);
+  return OS_OK;
+}
+
+static int get_psinfo2(void* info, size_t s, off_t o) {
+  return get_info("/proc/self/psinfo", info, s, o);
+}
+
+static int get_psinfo(psinfo_t* info) {
+  return get_psinfo2(info, sizeof(*info), 0);
+}
+
+static int read_cpustat(kstat_ctl_t* kstat_ctrl, CPUPerfTicks* load, cpu_stat_t* cpu_stat) {
+  assert(kstat_ctrl != NULL, "kstat_ctrl pointer is NULL!");
+  assert(load != NULL, "load pointer is NULL!");
+  assert(cpu_stat != NULL, "cpu_stat pointer is NULL!");
+
+  if (load->kstat == NULL) {
+    // no handle.
+    return OS_ERR;
+  }
+  if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == OS_ERR) {
+    // disable handle for this CPU
+     load->kstat = NULL;
+     return OS_ERR;
+  }
+  return OS_OK;
+}
+
+static double get_cpu_load(int which_logical_cpu, CPUPerfCounters* counters) {
+  assert(counters != NULL, "counters pointer is NULL!");
+
+  cpu_stat_t  cpu_stat = {0};
+
+  if (which_logical_cpu >= counters->nProcs) {
+    return .0;
+  }
+
+  CPUPerfTicks load = counters->jvmTicks[which_logical_cpu];
+  if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) != OS_OK) {
+    return .0;
+  }
+
+  uint_t* usage = cpu_stat.cpu_sysinfo.cpu;
+  if (usage == NULL) {
+    return .0;
+  }
+
+  uint64_t c_idle  = usage[CPU_IDLE];
+  uint64_t c_total = 0;
+
+  for (int i = 0; i < CPU_STATES; i++) {
+    c_total += usage[i];
+  }
+
+  // Calculate diff against previous snapshot
+  uint64_t d_idle  = c_idle - load.last_idle;
+  uint64_t d_total = c_total - load.last_total;
+
+  /** update if weve moved */
+  if (d_total > 0) {
+    // Save current values for next time around
+    load.last_idle  = c_idle;
+    load.last_total = c_total;
+    load.last_ratio = (double) (d_total - d_idle) / d_total;
+  }
+
+  return load.last_ratio;
+}
+
+static int get_boot_time(uint64_t* time) {
+  assert(time != NULL, "time pointer is NULL!");
+  setutxent();
+  for(;;) {
+    struct utmpx* u;
+    if ((u = getutxent()) == NULL) {
+      break;
+    }
+    if (u->ut_type == BOOT_TIME) {
+      *time = u->ut_xtime;
+      endutxent();
+      return OS_OK;
+    }
+  }
+  endutxent();
+  return OS_ERR;
+}
+
+static int get_noof_context_switches(CPUPerfCounters* counters, uint64_t* switches) {
+  assert(switches != NULL, "switches pointer is NULL!");
+  assert(counters != NULL, "counter pointer is NULL!");
+  *switches = 0;
+  uint64_t s = 0;
+
+  // Collect data from all CPUs
+  for (int i = 0; i < counters->nProcs; i++) {
+    cpu_stat_t cpu_stat = {0};
+    CPUPerfTicks load = counters->jvmTicks[i];
+
+    if (read_cpustat(counters->kstat_ctrl, &load, &cpu_stat) == OS_OK) {
+      s += cpu_stat.cpu_sysinfo.pswitch;
+    } else {
+      //fail fast...
+      return OS_ERR;
+    }
+  }
+  *switches = s;
+  return OS_OK;
+}
+
+static int perf_context_switch_rate(CPUPerfCounters* counters, double* rate) {
+  assert(counters != NULL, "counters is NULL!");
+  assert(rate != NULL, "rate pointer is NULL!");
+  static pthread_mutex_t contextSwitchLock = PTHREAD_MUTEX_INITIALIZER;
+  static uint64_t lastTime = 0;
+  static uint64_t lastSwitches = 0;
+  static double   lastRate = 0.0;
+
+  uint64_t lt = 0;
+  int res = 0;
+
+  if (lastTime == 0) {
+    uint64_t tmp;
+    if (get_boot_time(&tmp) < 0) {
+      return OS_ERR;
+    }
+    lt = tmp * 1000;
+  }
+
+  res = OS_OK;
+
+  pthread_mutex_lock(&contextSwitchLock);
+  {
+
+    uint64_t sw = 0;
+    clock_t t, d;
+
+    if (lastTime == 0) {
+      lastTime = lt;
+    }
+
+    t = clock();
+    d = t - lastTime;
+
+    if (d == 0) {
+      *rate = lastRate;
+    } else if (get_noof_context_switches(counters, &sw)== OS_OK) {
+      *rate      = ((double)(sw - lastSwitches) / d) * 1000;
+      lastRate     = *rate;
+      lastSwitches = sw;
+      lastTime     = t;
+    } else {
+      *rate = 0.0;
+      res   = OS_ERR;
+    }
+    if (*rate < 0.0) {
+      *rate = 0.0;
+      lastRate = 0.0;
+    }
+  }
+  pthread_mutex_unlock(&contextSwitchLock);
+  return res;
+ }
+
+
+
+class CPUPerformanceInterface::CPUPerformance : public CHeapObj<mtInternal> {
+   friend class CPUPerformanceInterface;
+ private:
+  CPUPerfCounters _counters;
+  int cpu_load(int which_logical_cpu, double* cpu_load);
+  int context_switch_rate(double* rate);
+  int cpu_load_total_process(double* cpu_load);
+  int cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad);
+
+  CPUPerformance();
+  ~CPUPerformance();
+  bool initialize();
+};
+
+CPUPerformanceInterface::CPUPerformance::CPUPerformance() {
+  _counters.nProcs = 0;
+  _counters.jvmTicks = NULL;
+  _counters.kstat_ctrl = NULL;
+}
+
+bool CPUPerformanceInterface::CPUPerformance::initialize() {
+  // initialize kstat control structure,
+  _counters.kstat_ctrl = kstat_open();
+  assert(_counters.kstat_ctrl != NULL, "error initializing kstat control structure!");
+
+  if (NULL == _counters.kstat_ctrl) {
+    return false;
+  }
+
+  // Get number of CPU(s)
+  if ((_counters.nProcs = sysconf(_SC_NPROCESSORS_ONLN)) == OS_ERR) {
+    // ignore error?
+    _counters.nProcs = 1;
+  }
+
+  assert(_counters.nProcs > 0, "no CPUs detected in sysconf call!");
+  if (_counters.nProcs == 0) {
+    return false;
+  }
+
+  // Data structure(s) for saving CPU load (one per CPU)
+  size_t array_entry_count = _counters.nProcs;
+  _counters.jvmTicks = NEW_C_HEAP_ARRAY(CPUPerfTicks, array_entry_count, mtInternal);
+  memset(_counters.jvmTicks, 0, array_entry_count * sizeof(*_counters.jvmTicks));
+
+  // Get kstat cpu_stat counters for every CPU
+  // loop over kstat to find our cpu_stat(s)
+  int i = 0;
+  for (kstat_t* kstat = _counters.kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
+    if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
+      if (kstat_read(_counters.kstat_ctrl, kstat, NULL) == OS_ERR) {
+        continue;
+      }
+      if (i == _counters.nProcs) {
+        // more cpu_stats than reported CPUs
+        break;
+      }
+      _counters.jvmTicks[i++].kstat = kstat;
+    }
+  }
+  return true;
+}
+
+CPUPerformanceInterface::CPUPerformance::~CPUPerformance() {
+  FREE_C_HEAP_ARRAY(char, _counters.jvmTicks);
+  if (_counters.kstat_ctrl != NULL) {
+    kstat_close(_counters.kstat_ctrl);
+  }
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load(int which_logical_cpu, double* cpu_load) {
+  assert(cpu_load != NULL, "cpu_load pointer is NULL!");
+  double t = .0;
+  if (-1 == which_logical_cpu) {
+    for (int i = 0; i < _counters.nProcs; i++) {
+      t += get_cpu_load(i, &_counters);
+    }
+    // Cap total systemload to 1.0
+    t = MIN2<double>((t / _counters.nProcs), 1.0);
+  } else {
+    t = MIN2<double>(get_cpu_load(which_logical_cpu, &_counters), 1.0);
+  }
+
+  *cpu_load = t;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_load_total_process(double* cpu_load) {
+  assert(cpu_load != NULL, "cpu_load pointer is NULL!");
+
+  psinfo_t info;
+
+  // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
+  // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
+  if (get_psinfo2(&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) != 0) {
+    *cpu_load = 0.0;
+    return OS_ERR;
+  }
+  *cpu_load = (double) info.pr_pctcpu / 0x8000;
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) {
+  assert(pjvmUserLoad != NULL, "pjvmUserLoad not inited");
+  assert(pjvmKernelLoad != NULL, "pjvmKernelLoad not inited");
+  assert(psystemTotalLoad != NULL, "psystemTotalLoad not inited");
+
+  static uint64_t lastTime;
+  static uint64_t lastUser, lastKernel;
+  static double lastUserRes, lastKernelRes;
+
+  pstatus_t pss;
+  psinfo_t  info;
+
+  *pjvmKernelLoad = *pjvmUserLoad = *psystemTotalLoad = 0;
+  if (get_info("/proc/self/status", &pss.pr_utime, sizeof(timestruc_t)*2, offsetof(pstatus_t, pr_utime)) != 0) {
+    return OS_ERR;
+  }
+
+  if (get_psinfo(&info) != 0) {
+    return OS_ERR;
+  }
+
+  // get the total time in user, kernel and total time
+  // check ratios for 'lately' and multiply the 'recent load'.
+  uint64_t time   = (info.pr_time.tv_sec * NANOS_PER_SEC) + info.pr_time.tv_nsec;
+  uint64_t user   = (pss.pr_utime.tv_sec * NANOS_PER_SEC) + pss.pr_utime.tv_nsec;
+  uint64_t kernel = (pss.pr_stime.tv_sec * NANOS_PER_SEC) + pss.pr_stime.tv_nsec;
+  uint64_t diff   = time - lastTime;
+  double load     = (double) info.pr_pctcpu / 0x8000;
+
+  if (diff > 0) {
+    lastUserRes = (load * (user - lastUser)) / diff;
+    lastKernelRes = (load * (kernel - lastKernel)) / diff;
+
+    // BUG9182835 - patch for clamping these values to sane ones.
+    lastUserRes   = MIN2<double>(1, lastUserRes);
+    lastUserRes   = MAX2<double>(0, lastUserRes);
+    lastKernelRes = MIN2<double>(1, lastKernelRes);
+    lastKernelRes = MAX2<double>(0, lastKernelRes);
+  }
+
+  double t = .0;
+  cpu_load(-1, &t);
+  // clamp at user+system and 1.0
+  if (lastUserRes + lastKernelRes > t) {
+    t = MIN2<double>(lastUserRes + lastKernelRes, 1.0);
+  }
+
+  *pjvmUserLoad   = lastUserRes;
+  *pjvmKernelLoad = lastKernelRes;
+  *psystemTotalLoad = t;
+
+  lastTime   = time;
+  lastUser   = user;
+  lastKernel = kernel;
+
+  return OS_OK;
+}
+
+int CPUPerformanceInterface::CPUPerformance::context_switch_rate(double* rate) {
+  return perf_context_switch_rate(&_counters, rate);
+}
+
+CPUPerformanceInterface::CPUPerformanceInterface() {
+  _impl = NULL;
+}
+
+bool CPUPerformanceInterface::initialize() {
+  _impl = new CPUPerformanceInterface::CPUPerformance();
+  return _impl->initialize();
+}
+
+CPUPerformanceInterface::~CPUPerformanceInterface(void) {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+int CPUPerformanceInterface::cpu_load(int which_logical_cpu, double* cpu_load) const {
+  return _impl->cpu_load(which_logical_cpu, cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_load_total_process(double* cpu_load) const {
+  return _impl->cpu_load_total_process(cpu_load);
+}
+
+int CPUPerformanceInterface::cpu_loads_process(double* pjvmUserLoad, double* pjvmKernelLoad, double* psystemTotalLoad) const {
+  return _impl->cpu_loads_process(pjvmUserLoad, pjvmKernelLoad, psystemTotalLoad);
+}
+
+int CPUPerformanceInterface::context_switch_rate(double* rate) const {
+  return _impl->context_switch_rate(rate);
+}
+
+class SystemProcessInterface::SystemProcesses : public CHeapObj<mtInternal> {
+  friend class SystemProcessInterface;
+ private:
+  class ProcessIterator : public CHeapObj<mtInternal> {
+    friend class SystemProcessInterface::SystemProcesses;
+   private:
+    DIR*           _dir;
+    struct dirent* _entry;
+    bool           _valid;
+
+    ProcessIterator();
+    ~ProcessIterator();
+    bool initialize();
+
+    bool is_valid() const { return _valid; }
+    bool is_valid_entry(struct dirent* const entry) const;
+    bool is_dir(const char* const name) const;
+    char* allocate_string(const char* const str) const;
+    int current(SystemProcess* const process_info);
+    int next_process();
+  };
+
+  ProcessIterator* _iterator;
+  SystemProcesses();
+  bool initialize();
+  ~SystemProcesses();
+
+  //information about system processes
+  int system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const;
+};
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_dir(const char* name) const {
+  struct stat64 mystat;
+  int ret_val = 0;
+
+  ret_val = ::stat64(name, &mystat);
+
+  if (ret_val < 0) {
+    return false;
+  }
+  ret_val = S_ISDIR(mystat.st_mode);
+  return ret_val > 0;
+}
+
+// if it has a numeric name, is a directory and has a 'psinfo' file in it
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::is_valid_entry(struct dirent* entry) const {
+  // ignore the "." and ".." directories
+  if ((strcmp(entry->d_name, ".") == 0) ||
+      (strcmp(entry->d_name, "..") == 0)) {
+    return false;
+  }
+
+  char buffer[PATH_MAX] = {0};
+  uint64_t size = 0;
+  bool result = false;
+  FILE *fp = NULL;
+
+  if (atoi(entry->d_name) != 0) {
+    jio_snprintf(buffer, PATH_MAX, "/proc/%s", entry->d_name);
+
+    if (is_dir(buffer)) {
+      memset(buffer, 0, PATH_MAX);
+      jio_snprintf(buffer, PATH_MAX, "/proc/%s/psinfo", entry->d_name);
+      if ((fp = fopen(buffer, "r")) != NULL) {
+        int nread = 0;
+        psinfo_t psinfo_data;
+        if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) != -1) {
+          // only considering system process owned by root
+          if (psinfo_data.pr_uid == 0) {
+            result = true;
+          }
+        }
+      }
+    }
+  }
+
+  if (fp != NULL) {
+    fclose(fp);
+  }
+
+  return result;
+}
+
+char* SystemProcessInterface::SystemProcesses::ProcessIterator::allocate_string(const char* str) const {
+  if (str != NULL) {
+    return os::strdup_check_oom(str, mtInternal);
+  }
+  return NULL;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::current(SystemProcess* process_info) {
+  if (!is_valid()) {
+    return OS_ERR;
+  }
+
+  char psinfo_path[PATH_MAX] = {0};
+  jio_snprintf(psinfo_path, PATH_MAX, "/proc/%s/psinfo", _entry->d_name);
+
+  FILE *fp = NULL;
+  if ((fp = fopen(psinfo_path, "r")) == NULL) {
+    return OS_ERR;
+  }
+
+  int nread = 0;
+  psinfo_t psinfo_data;
+  if ((nread = fread(&psinfo_data, 1, sizeof(psinfo_t), fp)) == -1) {
+    fclose(fp);
+    return OS_ERR;
+  }
+
+  char *exe_path = NULL;
+  if ((psinfo_data.pr_fname != NULL) &&
+      (psinfo_data.pr_psargs != NULL)) {
+    char *path_substring = strstr(psinfo_data.pr_psargs, psinfo_data.pr_fname);
+    if (path_substring != NULL) {
+      int len = path_substring - psinfo_data.pr_psargs;
+      exe_path = NEW_C_HEAP_ARRAY(char, len+1, mtInternal);
+      jio_snprintf(exe_path, len, "%s", psinfo_data.pr_psargs);
+      exe_path[len] = '\0';
+    }
+  }
+
+  process_info->set_pid(atoi(_entry->d_name));
+  process_info->set_name(allocate_string(psinfo_data.pr_fname));
+  process_info->set_path(allocate_string(exe_path));
+  process_info->set_command_line(allocate_string(psinfo_data.pr_psargs));
+
+  if (exe_path != NULL) {
+    FREE_C_HEAP_ARRAY(char, exe_path);
+  }
+
+  if (fp != NULL) {
+    fclose(fp);
+  }
+
+  return OS_OK;
+}
+
+int SystemProcessInterface::SystemProcesses::ProcessIterator::next_process() {
+  if (!is_valid()) {
+    return OS_ERR;
+  }
+
+  do {
+    _entry = os::readdir(_dir);
+    if (_entry == NULL) {
+      // Error or reached end.  Could use errno to distinguish those cases.
+      _valid = false;
+      return OS_ERR;
+    }
+  } while(!is_valid_entry(_entry));
+
+  _valid = true;
+  return OS_OK;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::ProcessIterator() {
+  _dir = NULL;
+  _entry = NULL;
+  _valid = false;
+}
+
+bool SystemProcessInterface::SystemProcesses::ProcessIterator::initialize() {
+  _dir = os::opendir("/proc");
+  _entry = NULL;
+  _valid = true;
+  next_process();
+
+  return true;
+}
+
+SystemProcessInterface::SystemProcesses::ProcessIterator::~ProcessIterator() {
+  if (_dir != NULL) {
+    os::closedir(_dir);
+  }
+}
+
+SystemProcessInterface::SystemProcesses::SystemProcesses() {
+  _iterator = NULL;
+}
+
+bool SystemProcessInterface::SystemProcesses::initialize() {
+  _iterator = new SystemProcessInterface::SystemProcesses::ProcessIterator();
+  return _iterator->initialize();
+}
+
+SystemProcessInterface::SystemProcesses::~SystemProcesses() {
+  if (_iterator != NULL) {
+    delete _iterator;
+  }
+}
+
+int SystemProcessInterface::SystemProcesses::system_processes(SystemProcess** system_processes, int* no_of_sys_processes) const {
+  assert(system_processes != NULL, "system_processes pointer is NULL!");
+  assert(no_of_sys_processes != NULL, "system_processes counter pointer is NULL!");
+  assert(_iterator != NULL, "iterator is NULL!");
+
+  // initialize pointers
+  *no_of_sys_processes = 0;
+  *system_processes = NULL;
+
+  while (_iterator->is_valid()) {
+    SystemProcess* tmp = new SystemProcess();
+    _iterator->current(tmp);
+
+    //if already existing head
+    if (*system_processes != NULL) {
+      //move "first to second"
+      tmp->set_next(*system_processes);
+    }
+    // new head
+    *system_processes = tmp;
+    // increment
+    (*no_of_sys_processes)++;
+    // step forward
+    _iterator->next_process();
+  }
+  return OS_OK;
+}
+
+int SystemProcessInterface::system_processes(SystemProcess** system_procs, int* no_of_sys_processes) const {
+  return _impl->system_processes(system_procs, no_of_sys_processes);
+}
+
+SystemProcessInterface::SystemProcessInterface() {
+  _impl = NULL;
+}
+
+bool SystemProcessInterface::initialize() {
+  _impl = new SystemProcessInterface::SystemProcesses();
+  return _impl->initialize();
+
+}
+
+SystemProcessInterface::~SystemProcessInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+CPUInformationInterface::CPUInformationInterface() {
+  _cpu_info = NULL;
+}
+
+bool CPUInformationInterface::initialize() {
+  _cpu_info = new CPUInformation();
+  _cpu_info->set_number_of_hardware_threads(VM_Version_Ext::number_of_threads());
+  _cpu_info->set_number_of_cores(VM_Version_Ext::number_of_cores());
+  _cpu_info->set_number_of_sockets(VM_Version_Ext::number_of_sockets());
+  _cpu_info->set_cpu_name(VM_Version_Ext::cpu_name());
+  _cpu_info->set_cpu_description(VM_Version_Ext::cpu_description());
+  return true;
+}
+
+CPUInformationInterface::~CPUInformationInterface() {
+  if (_cpu_info != NULL) {
+    if (_cpu_info->cpu_name() != NULL) {
+      const char* cpu_name = _cpu_info->cpu_name();
+      FREE_C_HEAP_ARRAY(char, cpu_name);
+      _cpu_info->set_cpu_name(NULL);
+    }
+    if (_cpu_info->cpu_description() != NULL) {
+      const char* cpu_desc = _cpu_info->cpu_description();
+      FREE_C_HEAP_ARRAY(char, cpu_desc);
+      _cpu_info->set_cpu_description(NULL);
+    }
+    delete _cpu_info;
+  }
+}
+
+int CPUInformationInterface::cpu_information(CPUInformation& cpu_info) {
+  if (_cpu_info == NULL) {
+    return OS_ERR;
+  }
+
+  cpu_info = *_cpu_info; // shallow copy assignment
+  return OS_OK;
+}
+
+class NetworkPerformanceInterface::NetworkPerformance : public CHeapObj<mtInternal> {
+  friend class NetworkPerformanceInterface;
+ private:
+  NetworkPerformance();
+  NONCOPYABLE(NetworkPerformance);
+  bool initialize();
+  ~NetworkPerformance();
+  int network_utilization(NetworkInterface** network_interfaces) const;
+};
+
+NetworkPerformanceInterface::NetworkPerformance::NetworkPerformance() {
+
+}
+
+bool NetworkPerformanceInterface::NetworkPerformance::initialize() {
+  return true;
+}
+
+NetworkPerformanceInterface::NetworkPerformance::~NetworkPerformance() {
+
+}
+
+int NetworkPerformanceInterface::NetworkPerformance::network_utilization(NetworkInterface** network_interfaces) const
+{
+  kstat_ctl_t* ctl = kstat_open();
+  if (ctl == NULL) {
+    return OS_ERR;
+  }
+
+  NetworkInterface* ret = NULL;
+  for (kstat_t* k = ctl->kc_chain; k != NULL; k = k->ks_next) {
+    if (strcmp(k->ks_class, "net") != 0) {
+      continue;
+    }
+    if (strcmp(k->ks_module, "link") != 0) {
+      continue;
+    }
+
+    if (kstat_read(ctl, k, NULL) == -1) {
+      return OS_ERR;
+    }
+
+    uint64_t bytes_in = UINT64_MAX;
+    uint64_t bytes_out = UINT64_MAX;
+    for (unsigned int i = 0; i < k->ks_ndata; ++i) {
+      kstat_named_t* data = &reinterpret_cast<kstat_named_t*>(k->ks_data)[i];
+      if (strcmp(data->name, "rbytes64") == 0) {
+        bytes_in = data->value.ui64;
+      }
+      else if (strcmp(data->name, "obytes64") == 0) {
+        bytes_out = data->value.ui64;
+      }
+    }
+
+    if ((bytes_in != UINT64_MAX) && (bytes_out != UINT64_MAX)) {
+      NetworkInterface* cur = new NetworkInterface(k->ks_name, bytes_in, bytes_out, ret);
+      ret = cur;
+    }
+  }
+
+  kstat_close(ctl);
+  *network_interfaces = ret;
+
+  return OS_OK;
+}
+
+NetworkPerformanceInterface::NetworkPerformanceInterface() {
+  _impl = NULL;
+}
+
+NetworkPerformanceInterface::~NetworkPerformanceInterface() {
+  if (_impl != NULL) {
+    delete _impl;
+  }
+}
+
+bool NetworkPerformanceInterface::initialize() {
+  _impl = new NetworkPerformanceInterface::NetworkPerformance();
+  return _impl->initialize();
+}
+
+int NetworkPerformanceInterface::network_utilization(NetworkInterface** network_interfaces) const {
+  return _impl->network_utilization(network_interfaces);
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_share_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_share_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_share_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_share_solaris.hpp	2024-08-17 18:29:44.541723101 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_OS_SHARE_SOLARIS_HPP
+#define OS_SOLARIS_OS_SHARE_SOLARIS_HPP
+
+// Defines the interfaces to Solaris operating systems that vary across platforms
+
+// misc
+extern "C" {
+  void signalHandler(int, siginfo_t*, void*);
+}
+void resolve_lwp_exit_calls(void);
+void handle_unexpected_exception(Thread* thread, int sig, siginfo_t* info, address pc, address adjusted_pc);
+#ifndef PRODUCT
+void continue_with_dump(void);
+#endif
+
+#define PROCFILE_LENGTH 128
+
+#endif // OS_SOLARIS_OS_SHARE_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_solaris.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_solaris.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_solaris.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_solaris.cpp	2024-08-17 18:29:44.544829226 +0200
@@ -0,0 +1,4020 @@
+/*
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// no precompiled headers
+#include "jvm.h"
+#include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "code/icBuffer.hpp"
+#include "code/vtableStubs.hpp"
+#include "compiler/compileBroker.hpp"
+#include "compiler/disassembler.hpp"
+#include "interpreter/interpreter.hpp"
+#include "jvmtifiles/jvmti.h"
+#include "logging/log.hpp"
+#include "logging/logStream.hpp"
+#include "memory/allocation.inline.hpp"
+#include "memory/universe.hpp"
+#include "oops/oop.inline.hpp"
+#include "os_share_solaris.hpp"
+#include "os_solaris.inline.hpp"
+#include "prims/jniFastGetField.hpp"
+#include "prims/jvm_misc.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/atomic.hpp"
+#include "runtime/globals.hpp"
+#include "runtime/globals_extension.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/java.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/objectMonitor.hpp"
+#include "runtime/orderAccess.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/perfMemory.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/statSampler.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadCritical.hpp"
+#include "runtime/timer.hpp"
+#include "runtime/vm_version.hpp"
+#include "semaphore_posix.hpp"
+#include "services/attachListener.hpp"
+#include "services/memTracker.hpp"
+#include "services/runtimeService.hpp"
+#include "signals_posix.hpp"
+#include "utilities/align.hpp"
+#include "utilities/decoder.hpp"
+#include "utilities/defaultStream.hpp"
+#include "utilities/events.hpp"
+#include "utilities/growableArray.hpp"
+#include "utilities/macros.hpp"
+#include "utilities/vmError.hpp"
+
+// put OS-includes here
+# include <dlfcn.h>
+# include <errno.h>
+# include <exception>
+# include <link.h>
+# include <poll.h>
+# include <pthread.h>
+# include <setjmp.h>
+# include <signal.h>
+# include <stdio.h>
+# include <alloca.h>
+# include <sys/filio.h>
+# include <sys/ipc.h>
+# include <sys/lwp.h>
+# include <sys/machelf.h>     // for elf Sym structure used by dladdr1
+# include <sys/mman.h>
+# include <sys/processor.h>
+# include <sys/procset.h>
+# include <sys/pset.h>
+# include <sys/resource.h>
+# include <sys/shm.h>
+# include <sys/socket.h>
+# include <sys/stat.h>
+# include <sys/systeminfo.h>
+# include <sys/time.h>
+# include <sys/times.h>
+# include <sys/types.h>
+# include <sys/wait.h>
+# include <sys/utsname.h>
+# include <thread.h>
+# include <unistd.h>
+# include <sys/priocntl.h>
+# include <sys/rtpriocntl.h>
+# include <sys/tspriocntl.h>
+# include <sys/iapriocntl.h>
+# include <sys/fxpriocntl.h>
+# include <sys/loadavg.h>
+# include <string.h>
+# include <stdio.h>
+
+# define _STRUCTURED_PROC 1  //  this gets us the new structured proc interfaces of 5.6 & later
+# include <sys/procfs.h>     //  see comment in <sys/procfs.h>
+
+#define MAX_PATH (2 * K)
+
+// for timer info max values which include all bits
+#define ALL_64_BITS CONST64(0xFFFFFFFFFFFFFFFF)
+
+int os::Solaris::_page_size = -1;
+
+// Here are some liblgrp types from sys/lgrp_user.h to be able to
+// compile on older systems without this header file.
+
+#ifndef MADV_ACCESS_LWP
+  #define  MADV_ACCESS_LWP   7       /* next LWP to access heavily */
+#endif
+#ifndef MADV_ACCESS_MANY
+  #define  MADV_ACCESS_MANY  8       /* many processes to access heavily */
+#endif
+
+#ifndef LGRP_RSRC_CPU
+  #define LGRP_RSRC_CPU      0       /* CPU resources */
+#endif
+#ifndef LGRP_RSRC_MEM
+  #define LGRP_RSRC_MEM      1       /* memory resources */
+#endif
+
+// guarded in sys/mman.h
+extern "C" {
+extern int getpagesizes(size_t[], int);
+}
+
+// Values for ThreadPriorityPolicy == 1
+int prio_policy1[CriticalPriority+1] = {
+  -99999,  0, 16,  32,  48,  64,
+          80, 96, 112, 124, 127, 127 };
+
+// System parameters used internally
+static clock_t clock_tics_per_sec = 100;
+
+// Track if we have called enable_extended_FILE_stdio (on Solaris 10u4+)
+static bool enabled_extended_FILE_stdio = false;
+
+// For diagnostics to print a message once. see run_periodic_checks
+static bool check_addr0_done = false;
+
+address os::Solaris::handler_start;  // start pc of thr_sighndlrinfo
+address os::Solaris::handler_end;    // end pc of thr_sighndlrinfo
+
+address os::Solaris::_main_stack_base = NULL;  // 4352906 workaround
+
+os::Solaris::pthread_setname_np_func_t os::Solaris::_pthread_setname_np = NULL;
+
+// "default" initializers for missing libc APIs
+extern "C" {
+  int memcntl(void *, size_t, int, void *, int, int);
+  int meminfo(const uint64_t *, int, const uint_t *, int, uint64_t *, uint_t *);
+}
+
+// "default" initializers for pthread-based synchronization
+extern "C" {
+  static int pthread_mutex_default_init(mutex_t *mx, int scope, void *arg) { memset(mx, 0, sizeof(mutex_t)); return 0; }
+  static int pthread_cond_default_init(cond_t *cv, int scope, void *arg){ memset(cv, 0, sizeof(cond_t)); return 0; }
+}
+
+static void unpackTime(timespec* absTime, bool isAbsolute, jlong time);
+
+static inline size_t adjust_stack_size(address base, size_t size) {
+  if ((ssize_t)size < 0) {
+    // 4759953: Compensate for ridiculous stack size.
+    size = max_intx;
+  }
+  if (size > (size_t)base) {
+    // 4812466: Make sure size doesn't allow the stack to wrap the address space.
+    size = (size_t)base;
+  }
+  return size;
+}
+
+static inline stack_t get_stack_info() {
+  stack_t st;
+  int retval = thr_stksegment(&st);
+  st.ss_size = adjust_stack_size((address)st.ss_sp, st.ss_size);
+  assert(retval == 0, "incorrect return value from thr_stksegment");
+  assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
+  assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
+  return st;
+}
+
+bool os::is_primordial_thread(void) {
+  int r = thr_main();
+  guarantee(r == 0 || r == 1, "CR6501650 or CR6493689");
+  return r == 1;
+}
+
+address os::current_stack_base() {
+  bool _is_primordial_thread = is_primordial_thread();
+
+  // Workaround 4352906, avoid calls to thr_stksegment by
+  // thr_main after the first one (it looks like we trash
+  // some data, causing the value for ss_sp to be incorrect).
+  if (!_is_primordial_thread || os::Solaris::_main_stack_base == NULL) {
+    stack_t st = get_stack_info();
+    if (_is_primordial_thread) {
+      // cache initial value of stack base
+      os::Solaris::_main_stack_base = (address)st.ss_sp;
+    }
+    return (address)st.ss_sp;
+  } else {
+    guarantee(os::Solaris::_main_stack_base != NULL, "Attempt to use null cached stack base");
+    return os::Solaris::_main_stack_base;
+  }
+}
+
+size_t os::current_stack_size() {
+  size_t size;
+
+  if (!is_primordial_thread()) {
+    size = get_stack_info().ss_size;
+  } else {
+    struct rlimit limits;
+    getrlimit(RLIMIT_STACK, &limits);
+    size = adjust_stack_size(os::Solaris::_main_stack_base, (size_t)limits.rlim_cur);
+  }
+  // base may not be page aligned
+  address base = current_stack_base();
+  address bottom = align_up(base - size, os::vm_page_size());;
+  return (size_t)(base - bottom);
+}
+
+jint os::Solaris::_os_thread_limit = 0;
+volatile jint os::Solaris::_os_thread_count = 0;
+
+julong os::available_memory() {
+  return Solaris::available_memory();
+}
+
+julong os::Solaris::available_memory() {
+  return (julong)sysconf(_SC_AVPHYS_PAGES) * os::vm_page_size();
+}
+
+julong os::Solaris::_physical_memory = 0;
+
+julong os::physical_memory() {
+  return Solaris::physical_memory();
+}
+
+static hrtime_t first_hrtime = 0;
+static const hrtime_t hrtime_hz = 1000*1000*1000;
+static volatile hrtime_t max_hrtime = 0;
+
+
+void os::Solaris::initialize_system_info() {
+  set_processor_count(sysconf(_SC_NPROCESSORS_CONF));
+  _physical_memory = (julong)sysconf(_SC_PHYS_PAGES) *
+                                     (julong)sysconf(_SC_PAGESIZE);
+}
+
+uint os::processor_id() {
+  const processorid_t id = ::getcpuid();
+  assert(id >= 0 && id < _processor_count, "Invalid processor id");
+  return (uint)id;
+}
+
+int os::active_processor_count() {
+  // User has overridden the number of active processors
+  if (ActiveProcessorCount > 0) {
+    log_trace(os)("active_processor_count: "
+                  "active processor count set by user : %d",
+                  ActiveProcessorCount);
+    return ActiveProcessorCount;
+  }
+
+  int online_cpus = sysconf(_SC_NPROCESSORS_ONLN);
+  pid_t pid = getpid();
+  psetid_t pset = PS_NONE;
+  // Are we running in a processor set or is there any processor set around?
+  if (pset_bind(PS_QUERY, P_PID, pid, &pset) == 0) {
+    uint_t pset_cpus;
+    // Query the number of cpus available to us.
+    if (pset_info(pset, NULL, &pset_cpus, NULL) == 0) {
+      assert(pset_cpus > 0 && pset_cpus <= online_cpus, "sanity check");
+      return pset_cpus;
+    }
+  }
+  // Otherwise return number of online cpus
+  return online_cpus;
+}
+
+void os::set_native_thread_name(const char *name) {
+  if (Solaris::_pthread_setname_np != NULL) {
+    // Only the first 31 bytes of 'name' are processed by pthread_setname_np
+    // but we explicitly copy into a size-limited buffer to avoid any
+    // possible overflow.
+    char buf[32];
+    snprintf(buf, sizeof(buf), "%s", name);
+    buf[sizeof(buf) - 1] = '\0';
+    Solaris::_pthread_setname_np(pthread_self(), buf);
+  }
+}
+
+void os::init_system_properties_values() {
+  // The next steps are taken in the product version:
+  //
+  // Obtain the JAVA_HOME value from the location of libjvm.so.
+  // This library should be located at:
+  // <JAVA_HOME>/jre/lib/<arch>/{client|server}/libjvm.so.
+  //
+  // If "/jre/lib/" appears at the right place in the path, then we
+  // assume libjvm.so is installed in a JDK and we use this path.
+  //
+  // Otherwise exit with message: "Could not create the Java virtual machine."
+  //
+  // The following extra steps are taken in the debugging version:
+  //
+  // If "/jre/lib/" does NOT appear at the right place in the path
+  // instead of exit check for $JAVA_HOME environment variable.
+  //
+  // If it is defined and we are able to locate $JAVA_HOME/jre/lib/<arch>,
+  // then we append a fake suffix "hotspot/libjvm.so" to this path so
+  // it looks like libjvm.so is installed there
+  // <JAVA_HOME>/jre/lib/<arch>/hotspot/libjvm.so.
+  //
+  // Otherwise exit.
+  //
+  // Important note: if the location of libjvm.so changes this
+  // code needs to be changed accordingly.
+
+// Base path of extensions installed on the system.
+#define SYS_EXT_DIR     "/usr/jdk/packages"
+#define EXTENSIONS_DIR  "/lib/ext"
+
+  // Buffer that fits several sprintfs.
+  // Note that the space for the colon and the trailing null are provided
+  // by the nulls included by the sizeof operator.
+  const size_t bufsize =
+    MAX3((size_t)MAXPATHLEN,  // For dll_dir & friends.
+         sizeof(SYS_EXT_DIR) + sizeof("/lib/"), // invariant ld_library_path
+         (size_t)MAXPATHLEN + sizeof(EXTENSIONS_DIR) + sizeof(SYS_EXT_DIR) + sizeof(EXTENSIONS_DIR)); // extensions dir
+  char *buf = NEW_C_HEAP_ARRAY(char, bufsize, mtInternal);
+
+  // sysclasspath, java_home, dll_dir
+  {
+    char *pslash;
+    os::jvm_path(buf, bufsize);
+
+    // Found the full path to libjvm.so.
+    // Now cut the path to <java_home>/jre if we can.
+    *(strrchr(buf, '/')) = '\0'; // Get rid of /libjvm.so.
+    pslash = strrchr(buf, '/');
+    if (pslash != NULL) {
+      *pslash = '\0';            // Get rid of /{client|server|hotspot}.
+    }
+    Arguments::set_dll_dir(buf);
+
+    if (pslash != NULL) {
+      pslash = strrchr(buf, '/');
+      if (pslash != NULL) {
+        *pslash = '\0';        // Get rid of /lib.
+      }
+    }
+    Arguments::set_java_home(buf);
+    if (!set_boot_path('/', ':')) {
+      vm_exit_during_initialization("Failed setting boot class path.", NULL);
+    }
+  }
+
+  // Where to look for native libraries.
+  {
+    // Use dlinfo() to determine the correct java.library.path.
+    //
+    // If we're launched by the Java launcher, and the user
+    // does not set java.library.path explicitly on the commandline,
+    // the Java launcher sets LD_LIBRARY_PATH for us and unsets
+    // LD_LIBRARY_PATH_32 and LD_LIBRARY_PATH_64.  In this case
+    // dlinfo returns LD_LIBRARY_PATH + crle settings (including
+    // /usr/lib), which is exactly what we want.
+    //
+    // If the user does set java.library.path, it completely
+    // overwrites this setting, and always has.
+    //
+    // If we're not launched by the Java launcher, we may
+    // get here with any/all of the LD_LIBRARY_PATH[_32|64]
+    // settings.  Again, dlinfo does exactly what we want.
+
+    Dl_serinfo     info_sz, *info = &info_sz;
+    Dl_serpath     *path;
+    char           *library_path;
+    char           *common_path = buf;
+
+    // Determine search path count and required buffer size.
+    if (dlinfo(RTLD_SELF, RTLD_DI_SERINFOSIZE, (void *)info) == -1) {
+      FREE_C_HEAP_ARRAY(char, buf);
+      vm_exit_during_initialization("dlinfo SERINFOSIZE request", dlerror());
+    }
+
+    // Allocate new buffer and initialize.
+    info = (Dl_serinfo*)NEW_C_HEAP_ARRAY(char, info_sz.dls_size, mtInternal);
+    info->dls_size = info_sz.dls_size;
+    info->dls_cnt = info_sz.dls_cnt;
+
+    // Obtain search path information.
+    if (dlinfo(RTLD_SELF, RTLD_DI_SERINFO, (void *)info) == -1) {
+      FREE_C_HEAP_ARRAY(char, buf);
+      FREE_C_HEAP_ARRAY(char, info);
+      vm_exit_during_initialization("dlinfo SERINFO request", dlerror());
+    }
+
+    path = &info->dls_serpath[0];
+
+    // Note: Due to a legacy implementation, most of the library path
+    // is set in the launcher. This was to accommodate linking restrictions
+    // on legacy Solaris implementations (which are no longer supported).
+    // Eventually, all the library path setting will be done here.
+    //
+    // However, to prevent the proliferation of improperly built native
+    // libraries, the new path component /usr/jdk/packages is added here.
+
+    // Construct the invariant part of ld_library_path.
+    sprintf(common_path, SYS_EXT_DIR "/lib");
+
+    // Struct size is more than sufficient for the path components obtained
+    // through the dlinfo() call, so only add additional space for the path
+    // components explicitly added here.
+    size_t library_path_size = info->dls_size + strlen(common_path);
+    library_path = NEW_C_HEAP_ARRAY(char, library_path_size, mtInternal);
+    library_path[0] = '\0';
+
+    // Construct the desired Java library path from the linker's library
+    // search path.
+    //
+    // For compatibility, it is optimal that we insert the additional path
+    // components specific to the Java VM after those components specified
+    // in LD_LIBRARY_PATH (if any) but before those added by the ld.so
+    // infrastructure.
+    if (info->dls_cnt == 0) { // Not sure this can happen, but allow for it.
+      strcpy(library_path, common_path);
+    } else {
+      int inserted = 0;
+      uint_t i;
+      for (i = 0; i < info->dls_cnt; i++, path++) {
+        uint_t flags = path->dls_flags & LA_SER_MASK;
+        if (((flags & LA_SER_LIBPATH) == 0) && !inserted) {
+          strcat(library_path, common_path);
+          strcat(library_path, os::path_separator());
+          inserted = 1;
+        }
+        strcat(library_path, path->dls_name);
+        strcat(library_path, os::path_separator());
+      }
+      // Eliminate trailing path separator.
+      library_path[strlen(library_path)-1] = '\0';
+    }
+
+    // happens before argument parsing - can't use a trace flag
+    // tty->print_raw("init_system_properties_values: native lib path: ");
+    // tty->print_raw_cr(library_path);
+
+    // Callee copies into its own buffer.
+    Arguments::set_library_path(library_path);
+
+    FREE_C_HEAP_ARRAY(char, library_path);
+    FREE_C_HEAP_ARRAY(char, info);
+  }
+
+  // Extensions directories.
+  sprintf(buf, "%s" EXTENSIONS_DIR ":" SYS_EXT_DIR EXTENSIONS_DIR, Arguments::get_java_home());
+  Arguments::set_ext_dirs(buf);
+
+  FREE_C_HEAP_ARRAY(char, buf);
+
+#undef SYS_EXT_DIR
+#undef EXTENSIONS_DIR
+}
+
+void os::breakpoint() {
+  BREAKPOINT;
+}
+
+extern "C" void breakpoint() {
+  // use debugger to set breakpoint here
+}
+
+static thread_t main_thread;
+
+// Thread start routine for all newly created threads
+extern "C" void* thread_native_entry(void* thread_addr) {
+
+  Thread* thread = (Thread*)thread_addr;
+
+  thread->record_stack_base_and_size();
+
+  // Try to randomize the cache line index of hot stack frames.
+  // This helps when threads of the same stack traces evict each other's
+  // cache lines. The threads can be either from the same JVM instance, or
+  // from different JVM instances. The benefit is especially true for
+  // processors with hyperthreading technology.
+  static int counter = 0;
+  int pid = os::current_process_id();
+  alloca(((pid ^ counter++) & 7) * 128);
+
+  int prio;
+
+  thread->initialize_thread_current();
+
+  OSThread* osthr = thread->osthread();
+
+  osthr->set_lwp_id(_lwp_self());  // Store lwp in case we are bound
+
+  log_info(os, thread)("Thread is alive (tid: " UINTX_FORMAT ").",
+    os::current_thread_id());
+
+  if (UseNUMA) {
+    int lgrp_id = os::numa_get_group_id();
+    if (lgrp_id != -1) {
+      thread->set_lgrp_id(lgrp_id);
+    }
+  }
+
+  // Our priority was set when we were created, and stored in the
+  // osthread, but couldn't be passed through to our LWP until now.
+  // So read back the priority and set it again.
+
+  if (osthr->thread_id() != -1) {
+    if (UseThreadPriorities) {
+      int prio = osthr->native_priority();
+      if (ThreadPriorityVerbose) {
+        tty->print_cr("Starting Thread " INTPTR_FORMAT ", LWP is "
+                      INTPTR_FORMAT ", setting priority: %d\n",
+                      (uintx)osthr->thread_id(), (uintx)osthr->lwp_id(), prio);
+      }
+      os::set_native_priority(thread, prio);
+    }
+  } else if (ThreadPriorityVerbose) {
+    warning("Can't set priority in _start routine, thread id hasn't been set\n");
+  }
+
+  assert(osthr->get_state() == RUNNABLE, "invalid os thread state");
+
+  // initialize signal mask for this thread
+  PosixSignals::hotspot_sigmask(thread);
+
+  os::Solaris::init_thread_fpu_state();
+
+  thread->call_run();
+
+  // Note: at this point the thread object may already have deleted itself.
+  // Do not dereference it from here on out.
+
+  // One less thread is executing
+  // When the VMThread gets here, the main thread may have already exited
+  // which frees the CodeHeap containing the Atomic::dec code
+  if (thread != VMThread::vm_thread() && VMThread::vm_thread() != NULL) {
+    Atomic::dec(&os::Solaris::_os_thread_count);
+  }
+
+  log_info(os, thread)("Thread finished (tid: " UINTX_FORMAT ").", os::current_thread_id());
+
+  if (UseDetachedThreads) {
+    thr_exit(NULL);
+    ShouldNotReachHere();
+  }
+  return NULL;
+}
+
+static OSThread* create_os_thread(Thread* thread, thread_t thread_id) {
+  // Allocate the OSThread object
+  OSThread* osthread = new OSThread(NULL, NULL);
+  if (osthread == NULL) return NULL;
+
+  // Store info on the Solaris thread into the OSThread
+  osthread->set_thread_id(thread_id);
+  osthread->set_lwp_id(_lwp_self());
+
+  if (UseNUMA) {
+    int lgrp_id = os::numa_get_group_id();
+    if (lgrp_id != -1) {
+      thread->set_lgrp_id(lgrp_id);
+    }
+  }
+
+  if (ThreadPriorityVerbose) {
+    tty->print_cr("In create_os_thread, Thread " INTPTR_FORMAT ", LWP is " INTPTR_FORMAT "\n",
+                  (uintx)osthread->thread_id(), (uintx)osthread->lwp_id());
+  }
+
+  // Initial thread state is INITIALIZED, not SUSPENDED
+  osthread->set_state(INITIALIZED);
+
+  return osthread;
+}
+
+bool os::create_attached_thread(JavaThread* thread) {
+#ifdef ASSERT
+  thread->verify_not_published();
+#endif
+  OSThread* osthread = create_os_thread(thread, thr_self());
+  if (osthread == NULL) {
+    return false;
+  }
+
+  // Initial thread state is RUNNABLE
+  osthread->set_state(RUNNABLE);
+  thread->set_osthread(osthread);
+
+  // initialize signal mask for this thread
+  // and save the caller's signal mask
+  PosixSignals::hotspot_sigmask(thread);
+
+  log_info(os, thread)("Thread attached (tid: " UINTX_FORMAT ").",
+    os::current_thread_id());
+
+  return true;
+}
+
+bool os::create_main_thread(JavaThread* thread) {
+#ifdef ASSERT
+  thread->verify_not_published();
+#endif
+  if (_starting_thread == NULL) {
+    _starting_thread = create_os_thread(thread, main_thread);
+    if (_starting_thread == NULL) {
+      return false;
+    }
+  }
+
+  // The primodial thread is runnable from the start
+  _starting_thread->set_state(RUNNABLE);
+
+  thread->set_osthread(_starting_thread);
+
+  // initialize signal mask for this thread
+  // and save the caller's signal mask
+  PosixSignals::hotspot_sigmask(thread);
+
+  return true;
+}
+
+// Helper function to trace thread attributes, similar to os::Posix::describe_pthread_attr()
+static char* describe_thr_create_attributes(char* buf, size_t buflen,
+                                            size_t stacksize, long flags) {
+  stringStream ss(buf, buflen);
+  ss.print("stacksize: " SIZE_FORMAT "k, ", stacksize / 1024);
+  ss.print("flags: ");
+  #define PRINT_FLAG(f) if (flags & f) ss.print( #f " ");
+  #define ALL(X) \
+    X(THR_SUSPENDED) \
+    X(THR_DETACHED) \
+    X(THR_BOUND) \
+    X(THR_NEW_LWP) \
+    X(THR_DAEMON)
+  ALL(PRINT_FLAG)
+  #undef ALL
+  #undef PRINT_FLAG
+  return buf;
+}
+
+// return default stack size for thr_type
+size_t os::Posix::default_stack_size(os::ThreadType thr_type) {
+  // default stack size when not specified by caller is 1M (2M for LP64)
+  size_t s = (BytesPerWord >> 2) * K * K;
+  return s;
+}
+
+bool os::create_thread(Thread* thread, ThreadType thr_type,
+                       size_t req_stack_size) {
+  // Allocate the OSThread object
+  OSThread* osthread = new OSThread(NULL, NULL);
+  if (osthread == NULL) {
+    return false;
+  }
+
+  if (ThreadPriorityVerbose) {
+    char *thrtyp;
+    switch (thr_type) {
+    case vm_thread:
+      thrtyp = (char *)"vm";
+      break;
+    case gc_thread:
+      thrtyp = (char *)"gc";
+      break;
+    case java_thread:
+      thrtyp = (char *)"java";
+      break;
+    case compiler_thread:
+      thrtyp = (char *)"compiler";
+      break;
+    case watcher_thread:
+      thrtyp = (char *)"watcher";
+      break;
+    default:
+      thrtyp = (char *)"unknown";
+      break;
+    }
+    tty->print_cr("In create_thread, creating a %s thread\n", thrtyp);
+  }
+
+  // calculate stack size if it's not specified by caller
+  size_t stack_size = os::Posix::get_initial_stack_size(thr_type, req_stack_size);
+
+  // Initial state is ALLOCATED but not INITIALIZED
+  osthread->set_state(ALLOCATED);
+
+  if (os::Solaris::_os_thread_count > os::Solaris::_os_thread_limit) {
+    // We got lots of threads. Check if we still have some address space left.
+    // Need to be at least 5Mb of unreserved address space. We do check by
+    // trying to reserve some.
+    const size_t VirtualMemoryBangSize = 20*K*K;
+    char* mem = os::reserve_memory(VirtualMemoryBangSize);
+    if (mem == NULL) {
+      delete osthread;
+      return false;
+    } else {
+      // Release the memory again
+      os::release_memory(mem, VirtualMemoryBangSize);
+    }
+  }
+
+  // Setup osthread because the child thread may need it.
+  thread->set_osthread(osthread);
+
+  // Create the Solaris thread
+  thread_t tid = 0;
+  long     flags = (UseDetachedThreads ? THR_DETACHED : 0) | THR_SUSPENDED;
+  int      status;
+
+  // Mark that we don't have an lwp or thread id yet.
+  // In case we attempt to set the priority before the thread starts.
+  osthread->set_lwp_id(-1);
+  osthread->set_thread_id(-1);
+
+  status = thr_create(NULL, stack_size, thread_native_entry, thread, flags, &tid);
+
+  char buf[64];
+  if (status == 0) {
+    log_info(os, thread)("Thread \"%s\" started (tid: " UINTX_FORMAT ", attributes: %s). ",
+      thread->name(), (uintx) tid, describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
+  } else {
+    log_warning(os, thread)("Failed to start thread \"%s\" - thr_create failed (%s) for attributes: %s.",
+      thread->name(), os::errno_name(status), describe_thr_create_attributes(buf, sizeof(buf), stack_size, flags));
+    // Log some OS information which might explain why creating the thread failed.
+    log_info(os, thread)("Number of threads approx. running in the VM: %d", Threads::number_of_threads());
+    LogStream st(Log(os, thread)::info());
+    os::Posix::print_rlimit_info(&st);
+    os::print_memory_info(&st);
+  }
+
+  if (status != 0) {
+    thread->set_osthread(NULL);
+    // Need to clean up stuff we've allocated so far
+    delete osthread;
+    return false;
+  }
+
+  Atomic::inc(&os::Solaris::_os_thread_count);
+
+  // Store info on the Solaris thread into the OSThread
+  osthread->set_thread_id(tid);
+
+  // Remember that we created this thread so we can set priority on it
+  osthread->set_vm_created();
+
+  // Most thread types will set an explicit priority before starting the thread,
+  // but for those that don't we need a valid value to read back in thread_native_entry.
+  osthread->set_native_priority(NormPriority);
+
+  // Initial thread state is INITIALIZED, not SUSPENDED
+  osthread->set_state(INITIALIZED);
+
+  // The thread is returned suspended (in state INITIALIZED), and is started higher up in the call chain
+  return true;
+}
+
+// CR 7190089: on Solaris, primordial thread's stack needs adjusting.
+// Without the adjustment, stack size is incorrect if stack is set to unlimited (ulimit -s unlimited).
+void os::Solaris::correct_stack_boundaries_for_primordial_thread(Thread* thr) {
+  assert(is_primordial_thread(), "Call only for primordial thread");
+
+  JavaThread* jt = (JavaThread *)thr;
+  assert(jt != NULL, "Sanity check");
+  size_t stack_size;
+  address base = jt->stack_base();
+  if (Arguments::created_by_java_launcher()) {
+    // Use 2MB to allow for Solaris 7 64 bit mode.
+    stack_size = JavaThread::stack_size_at_create() == 0
+      ? 2048*K : JavaThread::stack_size_at_create();
+
+    // There are rare cases when we may have already used more than
+    // the basic stack size allotment before this method is invoked.
+    // Attempt to allow for a normally sized java_stack.
+    size_t current_stack_offset = (size_t)(base - (address)&stack_size);
+    stack_size += ReservedSpace::page_align_size_down(current_stack_offset);
+  } else {
+    // 6269555: If we were not created by a Java launcher, i.e. if we are
+    // running embedded in a native application, treat the primordial thread
+    // as much like a native attached thread as possible.  This means using
+    // the current stack size from thr_stksegment(), unless it is too large
+    // to reliably setup guard pages.  A reasonable max size is 8MB.
+    size_t current_size = os::current_stack_size();
+    // This should never happen, but just in case....
+    if (current_size == 0) current_size = 2 * K * K;
+    stack_size = current_size > (8 * K * K) ? (8 * K * K) : current_size;
+  }
+  address bottom = align_up(base - stack_size, os::vm_page_size());;
+  stack_size = (size_t)(base - bottom);
+
+  assert(stack_size > 0, "Stack size calculation problem");
+
+  if (stack_size > jt->stack_size()) {
+#ifndef PRODUCT
+    struct rlimit limits;
+    getrlimit(RLIMIT_STACK, &limits);
+    size_t size = adjust_stack_size(base, (size_t)limits.rlim_cur);
+    assert(size >= jt->stack_size(), "Stack size problem in main thread");
+#endif
+    tty->print_cr("Stack size of " SIZE_FORMAT " Kb exceeds current limit of " SIZE_FORMAT " Kb.\n"
+                  "(Stack sizes are rounded up to a multiple of the system page size.)\n"
+                  "See limit(1) to increase the stack size limit.",
+                  stack_size / K, jt->stack_size() / K);
+    vm_exit(1);
+  }
+  assert(jt->stack_size() >= stack_size,
+         "Attempt to map more stack than was allocated");
+  jt->set_stack_size(stack_size);
+
+}
+
+
+
+// Free Solaris resources related to the OSThread
+void os::free_thread(OSThread* osthread) {
+  assert(osthread != NULL, "os::free_thread but osthread not set");
+
+  // We are told to free resources of the argument thread,
+  // but we can only really operate on the current thread.
+  assert(Thread::current()->osthread() == osthread,
+         "os::free_thread but not current thread");
+
+  // Restore caller's signal mask
+  sigset_t sigmask = osthread->caller_sigmask();
+  pthread_sigmask(SIG_SETMASK, &sigmask, NULL);
+
+  delete osthread;
+}
+
+void os::pd_start_thread(Thread* thread) {
+  int status = thr_continue(thread->osthread()->thread_id());
+  assert_status(status == 0, status, "thr_continue failed");
+}
+
+
+intx os::current_thread_id() {
+  return (intx)thr_self();
+}
+
+static pid_t _initial_pid = 0;
+
+int os::current_process_id() {
+  return (int)(_initial_pid ? _initial_pid : getpid());
+}
+
+// gethrtime() should be monotonic according to the documentation,
+// but some virtualized platforms are known to break this guarantee.
+// getTimeNanos() must be guaranteed not to move backwards, so we
+// are forced to add a check here.
+inline hrtime_t getTimeNanos() {
+  const hrtime_t now = gethrtime();
+  const hrtime_t prev = max_hrtime;
+  if (now <= prev) {
+    return prev;   // same or retrograde time;
+  }
+  const hrtime_t obsv = Atomic::cmpxchg(&max_hrtime, prev, now);
+  assert(obsv >= prev, "invariant");   // Monotonicity
+  // If the CAS succeeded then we're done and return "now".
+  // If the CAS failed and the observed value "obsv" is >= now then
+  // we should return "obsv".  If the CAS failed and now > obsv > prv then
+  // some other thread raced this thread and installed a new value, in which case
+  // we could either (a) retry the entire operation, (b) retry trying to install now
+  // or (c) just return obsv.  We use (c).   No loop is required although in some cases
+  // we might discard a higher "now" value in deference to a slightly lower but freshly
+  // installed obsv value.   That's entirely benign -- it admits no new orderings compared
+  // to (a) or (b) -- and greatly reduces coherence traffic.
+  // We might also condition (c) on the magnitude of the delta between obsv and now.
+  // Avoiding excessive CAS operations to hot RW locations is critical.
+  // See https://blogs.oracle.com/dave/entry/cas_and_cache_trivia_invalidate
+  return (prev == obsv) ? now : obsv;
+}
+
+double os::elapsedVTime() {
+  return (double)gethrvtime() / (double)hrtime_hz;
+}
+
+// DLL functions
+
+const char* os::dll_file_extension() { return ".so"; }
+
+// This must be hard coded because it's the system's temporary
+// directory not the java application's temp directory, ala java.io.tmpdir.
+const char* os::get_temp_directory() { return "/tmp"; }
+
+// check if addr is inside libjvm.so
+bool os::address_is_in_vm(address addr) {
+  static address libjvm_base_addr;
+  Dl_info dlinfo;
+
+  if (libjvm_base_addr == NULL) {
+    if (dladdr(CAST_FROM_FN_PTR(void *, os::address_is_in_vm), &dlinfo) != 0) {
+      libjvm_base_addr = (address)dlinfo.dli_fbase;
+    }
+    assert(libjvm_base_addr !=NULL, "Cannot obtain base address for libjvm");
+  }
+
+  if (dladdr((void *)addr, &dlinfo) != 0) {
+    if (libjvm_base_addr == (address)dlinfo.dli_fbase) return true;
+  }
+
+  return false;
+}
+
+typedef int (*dladdr1_func_type)(void *, Dl_info *, void **, int);
+static dladdr1_func_type dladdr1_func = NULL;
+
+bool os::dll_address_to_function_name(address addr, char *buf,
+                                      int buflen, int * offset,
+                                      bool demangle) {
+  // buf is not optional, but offset is optional
+  assert(buf != NULL, "sanity check");
+
+  Dl_info dlinfo;
+
+  // dladdr1_func was initialized in os::init()
+  if (dladdr1_func != NULL) {
+    // yes, we have dladdr1
+
+    // Support for dladdr1 is checked at runtime; it may be
+    // available even if the vm is built on a machine that does
+    // not have dladdr1 support.  Make sure there is a value for
+    // RTLD_DL_SYMENT.
+#ifndef RTLD_DL_SYMENT
+  #define RTLD_DL_SYMENT 1
+#endif
+#ifdef _LP64
+    Elf64_Sym * info;
+#else
+    Elf32_Sym * info;
+#endif
+    if (dladdr1_func((void *)addr, &dlinfo, (void **)&info,
+                     RTLD_DL_SYMENT) != 0) {
+      // see if we have a matching symbol that covers our address
+      if (dlinfo.dli_saddr != NULL &&
+          (char *)dlinfo.dli_saddr + info->st_size > (char *)addr) {
+        if (dlinfo.dli_sname != NULL) {
+          if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
+            jio_snprintf(buf, buflen, "%s", dlinfo.dli_sname);
+          }
+          if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
+          return true;
+        }
+      }
+      // no matching symbol so try for just file info
+      if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
+        if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
+                            buf, buflen, offset, dlinfo.dli_fname, demangle)) {
+          return true;
+        }
+      }
+    }
+    buf[0] = '\0';
+    if (offset != NULL) *offset  = -1;
+    return false;
+  }
+
+  // no, only dladdr is available
+  if (dladdr((void *)addr, &dlinfo) != 0) {
+    // see if we have a matching symbol
+    if (dlinfo.dli_saddr != NULL && dlinfo.dli_sname != NULL) {
+      if (!(demangle && Decoder::demangle(dlinfo.dli_sname, buf, buflen))) {
+        jio_snprintf(buf, buflen, dlinfo.dli_sname);
+      }
+      if (offset != NULL) *offset = addr - (address)dlinfo.dli_saddr;
+      return true;
+    }
+    // no matching symbol so try for just file info
+    if (dlinfo.dli_fname != NULL && dlinfo.dli_fbase != NULL) {
+      if (Decoder::decode((address)(addr - (address)dlinfo.dli_fbase),
+                          buf, buflen, offset, dlinfo.dli_fname, demangle)) {
+        return true;
+      }
+    }
+  }
+  buf[0] = '\0';
+  if (offset != NULL) *offset  = -1;
+  return false;
+}
+
+bool os::dll_address_to_library_name(address addr, char* buf,
+                                     int buflen, int* offset) {
+  // buf is not optional, but offset is optional
+  assert(buf != NULL, "sanity check");
+
+  Dl_info dlinfo;
+
+  if (dladdr((void*)addr, &dlinfo) != 0) {
+    if (dlinfo.dli_fname != NULL) {
+      jio_snprintf(buf, buflen, "%s", dlinfo.dli_fname);
+    }
+    if (dlinfo.dli_fbase != NULL && offset != NULL) {
+      *offset = addr - (address)dlinfo.dli_fbase;
+    }
+    return true;
+  }
+
+  buf[0] = '\0';
+  if (offset) *offset = -1;
+  return false;
+}
+
+int os::get_loaded_modules_info(os::LoadedModulesCallbackFunc callback, void *param) {
+  Dl_info dli;
+  // Sanity check?
+  if (dladdr(CAST_FROM_FN_PTR(void *, os::get_loaded_modules_info), &dli) == 0 ||
+      dli.dli_fname == NULL) {
+    return 1;
+  }
+
+  void * handle = dlopen(dli.dli_fname, RTLD_LAZY);
+  if (handle == NULL) {
+    return 1;
+  }
+
+  Link_map *map;
+  dlinfo(handle, RTLD_DI_LINKMAP, &map);
+  if (map == NULL) {
+    dlclose(handle);
+    return 1;
+  }
+
+  while (map->l_prev != NULL) {
+    map = map->l_prev;
+  }
+
+  while (map != NULL) {
+    // Iterate through all map entries and call callback with fields of interest
+    if(callback(map->l_name, (address)map->l_addr, (address)0, param)) {
+      dlclose(handle);
+      return 1;
+    }
+    map = map->l_next;
+  }
+
+  dlclose(handle);
+  return 0;
+}
+
+int _print_dll_info_cb(const char * name, address base_address, address top_address, void * param) {
+  outputStream * out = (outputStream *) param;
+  out->print_cr(INTPTR_FORMAT " \t%s", (intptr_t)base_address, name);
+  return 0;
+}
+
+void os::print_dll_info(outputStream * st) {
+  st->print_cr("Dynamic libraries:"); st->flush();
+  if (get_loaded_modules_info(_print_dll_info_cb, (void *)st)) {
+    st->print_cr("Error: Cannot print dynamic libraries.");
+  }
+}
+
+static void change_endianness(Elf32_Half& val) {
+  unsigned char *ptr = (unsigned char *)&val;
+  unsigned char swp = ptr[0];
+  ptr[0] = ptr[1];
+  ptr[1] = swp;
+}
+
+// Loads .dll/.so and
+// in case of error it checks if .dll/.so was built for the
+// same architecture as Hotspot is running on
+
+void * os::dll_load(const char *filename, char *ebuf, int ebuflen) {
+  log_info(os)("attempting shared library load of %s", filename);
+
+  void * result= ::dlopen(filename, RTLD_LAZY);
+  if (result != NULL) {
+    // Successful loading
+    Events::log(NULL, "Loaded shared library %s", filename);
+    log_info(os)("shared library load of %s was successful", filename);
+    return result;
+  }
+
+  Elf32_Ehdr elf_head;
+  const char* error_report = ::dlerror();
+  if (error_report == NULL) {
+    error_report = "dlerror returned no error description";
+  }
+  if (ebuf != NULL && ebuflen > 0) {
+    ::strncpy(ebuf, error_report, ebuflen-1);
+    ebuf[ebuflen-1]='\0';
+  }
+
+  Events::log(NULL, "Loading shared library %s failed, %s", filename, error_report);
+  log_info(os)("shared library load of %s failed, %s", filename, error_report);
+
+  int diag_msg_max_length=ebuflen-strlen(ebuf);
+  char* diag_msg_buf=ebuf+strlen(ebuf);
+
+  if (diag_msg_max_length==0) {
+    // No more space in ebuf for additional diagnostics message
+    return NULL;
+  }
+
+
+  int file_descriptor= ::open(filename, O_RDONLY | O_NONBLOCK);
+
+  if (file_descriptor < 0) {
+    // Can't open library, report dlerror() message
+    return NULL;
+  }
+
+  bool failed_to_read_elf_head=
+    (sizeof(elf_head)!=
+     (::read(file_descriptor, &elf_head,sizeof(elf_head))));
+
+  ::close(file_descriptor);
+  if (failed_to_read_elf_head) {
+    // file i/o error - report dlerror() msg
+    return NULL;
+  }
+
+  if (elf_head.e_ident[EI_DATA] != LITTLE_ENDIAN_ONLY(ELFDATA2LSB) BIG_ENDIAN_ONLY(ELFDATA2MSB)) {
+    // handle invalid/out of range endianness values
+    if (elf_head.e_ident[EI_DATA] == 0 || elf_head.e_ident[EI_DATA] > 2) {
+      return NULL;
+    }
+    change_endianness(elf_head.e_machine);
+  }
+
+  typedef struct {
+    Elf32_Half    code;         // Actual value as defined in elf.h
+    Elf32_Half    compat_class; // Compatibility of archs at VM's sense
+    unsigned char elf_class;    // 32 or 64 bit
+    unsigned char endianess;    // MSB or LSB
+    char*         name;         // String representation
+  } arch_t;
+
+  static const arch_t arch_array[]={
+    {EM_386,         EM_386,     ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
+    {EM_486,         EM_386,     ELFCLASS32, ELFDATA2LSB, (char*)"IA 32"},
+    {EM_IA_64,       EM_IA_64,   ELFCLASS64, ELFDATA2LSB, (char*)"IA 64"},
+    {EM_X86_64,      EM_X86_64,  ELFCLASS64, ELFDATA2LSB, (char*)"AMD 64"},
+    {EM_SPARC,       EM_SPARC,   ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
+    {EM_SPARC32PLUS, EM_SPARC,   ELFCLASS32, ELFDATA2MSB, (char*)"Sparc 32"},
+    {EM_SPARCV9,     EM_SPARCV9, ELFCLASS64, ELFDATA2MSB, (char*)"Sparc v9 64"},
+    {EM_PPC,         EM_PPC,     ELFCLASS32, ELFDATA2MSB, (char*)"Power PC 32"},
+    {EM_PPC64,       EM_PPC64,   ELFCLASS64, ELFDATA2MSB, (char*)"Power PC 64"},
+    {EM_ARM,         EM_ARM,     ELFCLASS32, ELFDATA2LSB, (char*)"ARM"},
+    // we only support 64 bit z architecture
+    {EM_S390,        EM_S390,    ELFCLASS64, ELFDATA2MSB, (char*)"IBM System/390"},
+    {EM_AARCH64,     EM_AARCH64, ELFCLASS64, ELFDATA2LSB, (char*)"AARCH64"}
+  };
+
+#if  (defined IA32)
+  static  Elf32_Half running_arch_code=EM_386;
+#elif   (defined AMD64)
+  static  Elf32_Half running_arch_code=EM_X86_64;
+#elif  (defined IA64)
+  static  Elf32_Half running_arch_code=EM_IA_64;
+#elif  (defined __sparc) && (defined _LP64)
+  static  Elf32_Half running_arch_code=EM_SPARCV9;
+#elif  (defined __sparc) && (!defined _LP64)
+  static  Elf32_Half running_arch_code=EM_SPARC;
+#elif  (defined __powerpc64__)
+  static  Elf32_Half running_arch_code=EM_PPC64;
+#elif  (defined __powerpc__)
+  static  Elf32_Half running_arch_code=EM_PPC;
+#elif (defined ARM)
+  static  Elf32_Half running_arch_code=EM_ARM;
+#else
+  #error Method os::dll_load requires that one of following is defined:\
+       IA32, AMD64, IA64, __sparc, __powerpc__, ARM, ARM
+#endif
+
+  // Identify compatibility class for VM's architecture and library's architecture
+  // Obtain string descriptions for architectures
+
+  arch_t lib_arch={elf_head.e_machine,0,elf_head.e_ident[EI_CLASS], elf_head.e_ident[EI_DATA], NULL};
+  int running_arch_index=-1;
+
+  for (unsigned int i=0; i < ARRAY_SIZE(arch_array); i++) {
+    if (running_arch_code == arch_array[i].code) {
+      running_arch_index    = i;
+    }
+    if (lib_arch.code == arch_array[i].code) {
+      lib_arch.compat_class = arch_array[i].compat_class;
+      lib_arch.name         = arch_array[i].name;
+    }
+  }
+
+  assert(running_arch_index != -1,
+         "Didn't find running architecture code (running_arch_code) in arch_array");
+  if (running_arch_index == -1) {
+    // Even though running architecture detection failed
+    // we may still continue with reporting dlerror() message
+    return NULL;
+  }
+
+  if (lib_arch.compat_class != arch_array[running_arch_index].compat_class) {
+    if (lib_arch.name != NULL) {
+      ::snprintf(diag_msg_buf, diag_msg_max_length-1,
+                 " (Possible cause: can't load %s .so on a %s platform)",
+                 lib_arch.name, arch_array[running_arch_index].name);
+    } else {
+      ::snprintf(diag_msg_buf, diag_msg_max_length-1,
+                 " (Possible cause: can't load this .so (machine code=0x%x) on a %s platform)",
+                 lib_arch.code, arch_array[running_arch_index].name);
+    }
+    return NULL;
+  }
+
+  if (lib_arch.endianess != arch_array[running_arch_index].endianess) {
+    ::snprintf(diag_msg_buf, diag_msg_max_length-1," (Possible cause: endianness mismatch)");
+    return NULL;
+  }
+
+  // ELF file class/capacity : 0 - invalid, 1 - 32bit, 2 - 64bit
+  if (lib_arch.elf_class > 2 || lib_arch.elf_class < 1) {
+    ::snprintf(diag_msg_buf, diag_msg_max_length-1, " (Possible cause: invalid ELF file class)");
+    return NULL;
+  }
+
+  if (lib_arch.elf_class != arch_array[running_arch_index].elf_class) {
+    ::snprintf(diag_msg_buf, diag_msg_max_length-1,
+               " (Possible cause: architecture word width mismatch, can't load %d-bit .so on a %d-bit platform)",
+               (int) lib_arch.elf_class * 32, arch_array[running_arch_index].elf_class * 32);
+    return NULL;
+  }
+
+  return NULL;
+}
+
+static inline time_t get_mtime(const char* filename) {
+  struct stat st;
+  int ret = os::stat(filename, &st);
+  assert(ret == 0, "failed to stat() file '%s': %s", filename, os::strerror(errno));
+  return st.st_mtime;
+}
+
+int os::compare_file_modified_times(const char* file1, const char* file2) {
+  time_t t1 = get_mtime(file1);
+  time_t t2 = get_mtime(file2);
+  return t1 - t2;
+}
+
+static bool _print_ascii_file(const char* filename, outputStream* st) {
+  int fd = ::open(filename, O_RDONLY);
+  if (fd == -1) {
+    return false;
+  }
+
+  char buf[32];
+  int bytes;
+  while ((bytes = ::read(fd, buf, sizeof(buf))) > 0) {
+    st->print_raw(buf, bytes);
+  }
+
+  ::close(fd);
+
+  return true;
+}
+
+void os::print_os_info_brief(outputStream* st) {
+  os::Solaris::print_distro_info(st);
+
+  os::Posix::print_uname_info(st);
+
+  os::Solaris::print_libversion_info(st);
+}
+
+void os::print_os_info(outputStream* st) {
+  st->print("OS:");
+
+  os::Solaris::print_distro_info(st);
+
+  os::Posix::print_uname_info(st);
+
+  os::Posix::print_uptime_info(st);
+
+  os::Solaris::print_libversion_info(st);
+
+  os::Posix::print_rlimit_info(st);
+
+  os::Posix::print_load_average(st);
+}
+
+void os::Solaris::print_distro_info(outputStream* st) {
+  if (!_print_ascii_file("/etc/release", st)) {
+    st->print("Solaris");
+  }
+  st->cr();
+}
+
+void os::get_summary_os_info(char* buf, size_t buflen) {
+  strncpy(buf, "Solaris", buflen);  // default to plain solaris
+  FILE* fp = fopen("/etc/release", "r");
+  if (fp != NULL) {
+    char tmp[256];
+    // Only get the first line and chop out everything but the os name.
+    if (fgets(tmp, sizeof(tmp), fp)) {
+      char* ptr = tmp;
+      // skip past whitespace characters
+      while (*ptr != '\0' && (*ptr == ' ' || *ptr == '\t' || *ptr == '\n')) ptr++;
+      if (*ptr != '\0') {
+        char* nl = strchr(ptr, '\n');
+        if (nl != NULL) *nl = '\0';
+        strncpy(buf, ptr, buflen);
+      }
+    }
+    fclose(fp);
+  }
+}
+
+void os::Solaris::print_libversion_info(outputStream* st) {
+  st->print("  (T2 libthread)");
+  st->cr();
+}
+
+static bool check_addr0(outputStream* st) {
+  jboolean status = false;
+  const int read_chunk = 200;
+  int ret = 0;
+  int nmap = 0;
+  int fd = ::open("/proc/self/map",O_RDONLY);
+  if (fd >= 0) {
+    prmap_t *p = NULL;
+    char *mbuff = (char *) calloc(read_chunk, sizeof(prmap_t));
+    if (NULL == mbuff) {
+      ::close(fd);
+      return status;
+    }
+    while ((ret = ::read(fd, mbuff, read_chunk*sizeof(prmap_t))) > 0) {
+      //check if read() has not read partial data
+      if( 0 != ret % sizeof(prmap_t)){
+        break;
+      }
+      nmap = ret / sizeof(prmap_t);
+      p = (prmap_t *)mbuff;
+      for(int i = 0; i < nmap; i++){
+        if (p->pr_vaddr == 0x0) {
+          st->print("Warning: Address: " PTR_FORMAT ", Size: " SIZE_FORMAT "K, ",p->pr_vaddr, p->pr_size/1024);
+          st->print("Mapped file: %s, ", p->pr_mapname[0] == '\0' ? "None" : p->pr_mapname);
+          st->print("Access: ");
+          st->print("%s",(p->pr_mflags & MA_READ)  ? "r" : "-");
+          st->print("%s",(p->pr_mflags & MA_WRITE) ? "w" : "-");
+          st->print("%s",(p->pr_mflags & MA_EXEC)  ? "x" : "-");
+          st->cr();
+          status = true;
+        }
+        p++;
+      }
+    }
+    free(mbuff);
+    ::close(fd);
+  }
+  return status;
+}
+
+void os::get_summary_cpu_info(char* buf, size_t buflen) {
+  // Get MHz with system call. We don't seem to already have this.
+  processor_info_t stats;
+  processorid_t id = getcpuid();
+  int clock = 0;
+  if (processor_info(id, &stats) != -1) {
+    clock = stats.pi_clock;  // pi_processor_type isn't more informative than below
+  }
+#ifdef AMD64
+  snprintf(buf, buflen, "x86 64 bit %d MHz", clock);
+#else
+  snprintf(buf, buflen, "Unknown 64 bit %d MHz", clock);
+#endif
+}
+
+void os::pd_print_cpu_info(outputStream* st, char* buf, size_t buflen) {
+  // Nothing to do for now.
+}
+
+void os::print_memory_info(outputStream* st) {
+  st->print("Memory:");
+  st->print(" %dk page", os::vm_page_size()>>10);
+  st->print(", physical " UINT64_FORMAT "k", os::physical_memory()>>10);
+  st->print("(" UINT64_FORMAT "k free)", os::available_memory() >> 10);
+  st->cr();
+  (void) check_addr0(st);
+}
+
+static int Maxsignum = 0;
+
+static char saved_jvm_path[MAXPATHLEN] = { 0 };
+
+// Find the full path to the current module, libjvm.so
+void os::jvm_path(char *buf, jint buflen) {
+  // Error checking.
+  if (buflen < MAXPATHLEN) {
+    assert(false, "must use a large-enough buffer");
+    buf[0] = '\0';
+    return;
+  }
+  // Lazy resolve the path to current module.
+  if (saved_jvm_path[0] != 0) {
+    strcpy(buf, saved_jvm_path);
+    return;
+  }
+
+  Dl_info dlinfo;
+  int ret = dladdr(CAST_FROM_FN_PTR(void *, os::jvm_path), &dlinfo);
+  assert(ret != 0, "cannot locate libjvm");
+  if (ret != 0 && dlinfo.dli_fname != NULL) {
+    if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) {
+      return;
+    }
+  } else {
+    buf[0] = '\0';
+    return;
+  }
+
+  if (Arguments::sun_java_launcher_is_altjvm()) {
+    // Support for the java launcher's '-XXaltjvm=<path>' option. Typical
+    // value for buf is "<JAVA_HOME>/jre/lib/<arch>/<vmtype>/libjvm.so".
+    // If "/jre/lib/" appears at the right place in the string, then
+    // assume we are installed in a JDK and we're done.  Otherwise, check
+    // for a JAVA_HOME environment variable and fix up the path so it
+    // looks like libjvm.so is installed there (append a fake suffix
+    // hotspot/libjvm.so).
+    const char *p = buf + strlen(buf) - 1;
+    for (int count = 0; p > buf && count < 5; ++count) {
+      for (--p; p > buf && *p != '/'; --p)
+        /* empty */ ;
+    }
+
+    if (strncmp(p, "/jre/lib/", 9) != 0) {
+      // Look for JAVA_HOME in the environment.
+      char* java_home_var = ::getenv("JAVA_HOME");
+      if (java_home_var != NULL && java_home_var[0] != 0) {
+        char* jrelib_p;
+        int   len;
+
+        // Check the current module name "libjvm.so".
+        p = strrchr(buf, '/');
+        assert(strstr(p, "/libjvm") == p, "invalid library name");
+
+        if (os::Posix::realpath(java_home_var, buf, buflen) == NULL) {
+          return;
+        }
+        // determine if this is a legacy image or modules image
+        // modules image doesn't have "jre" subdirectory
+        len = strlen(buf);
+        assert(len < buflen, "Ran out of buffer space");
+        jrelib_p = buf + len;
+        snprintf(jrelib_p, buflen-len, "/jre/lib");
+        if (0 != access(buf, F_OK)) {
+          snprintf(jrelib_p, buflen-len, "/lib");
+        }
+
+        if (0 == access(buf, F_OK)) {
+          // Use current module name "libjvm.so"
+          len = strlen(buf);
+          snprintf(buf + len, buflen-len, "/hotspot/libjvm.so");
+        } else {
+          // Go back to path of .so
+          if (os::Posix::realpath((char *)dlinfo.dli_fname, buf, buflen) == NULL) {
+            return;
+          }
+        }
+      }
+    }
+  }
+
+  strncpy(saved_jvm_path, buf, MAXPATHLEN);
+  saved_jvm_path[MAXPATHLEN - 1] = '\0';
+}
+
+
+void os::print_jni_name_prefix_on(outputStream* st, int args_size) {
+  // no prefix required, not even "_"
+}
+
+
+void os::print_jni_name_suffix_on(outputStream* st, int args_size) {
+  // no suffix required
+}
+
+// The following code is moved from os.cpp for making this
+// code platform specific, which it is by its very nature.
+
+// a counter for each possible signal value
+static int Sigexit = 0;
+static jint *pending_signals = NULL;
+static int *preinstalled_sigs = NULL;
+static struct sigaction *chainedsigactions = NULL;
+static Semaphore* sig_sem = NULL;
+
+void os::Solaris::init_signal_mem() {
+  // Initialize signal structures
+  Maxsignum = SIGRTMAX;
+  Sigexit = Maxsignum+1;
+  assert(Maxsignum >0, "Unable to obtain max signal number");
+
+  // Initialize signal structures
+  // pending_signals has one int per signal
+  // The additional signal is for SIGEXIT - exit signal to signal_thread
+  pending_signals = (jint *)os::malloc(sizeof(jint) * (Sigexit+1), mtInternal);
+  memset(pending_signals, 0, (sizeof(jint) * (Sigexit+1)));
+
+  if (UseSignalChaining) {
+    chainedsigactions = (struct sigaction *)malloc(sizeof(struct sigaction)
+                                                   * (Maxsignum + 1), mtInternal);
+    memset(chainedsigactions, 0, (sizeof(struct sigaction) * (Maxsignum + 1)));
+    preinstalled_sigs = (int *)os::malloc(sizeof(int) * (Maxsignum + 1), mtInternal);
+    memset(preinstalled_sigs, 0, (sizeof(int) * (Maxsignum + 1)));
+  }
+}
+
+////////////////////////////////////////////////////////////////////////////////
+// Virtual Memory
+
+int os::vm_page_size() {
+  assert(os::Solaris::page_size() != -1, "must call os::init");
+  return os::Solaris::page_size();
+}
+
+// Solaris allocates memory by pages.
+int os::vm_allocation_granularity() {
+  assert(os::Solaris::page_size() != -1, "must call os::init");
+  return os::Solaris::page_size();
+}
+
+static bool recoverable_mmap_error(int err) {
+  // See if the error is one we can let the caller handle. This
+  // list of errno values comes from the Solaris mmap(2) man page.
+  switch (err) {
+  case EBADF:
+  case EINVAL:
+  case ENOTSUP:
+    // let the caller deal with these errors
+    return true;
+
+  default:
+    // Any remaining errors on this OS can cause our reserved mapping
+    // to be lost. That can cause confusion where different data
+    // structures think they have the same memory mapped. The worst
+    // scenario is if both the VM and a library think they have the
+    // same memory mapped.
+    return false;
+  }
+}
+
+static void warn_fail_commit_memory(char* addr, size_t bytes, bool exec,
+                                    int err) {
+  warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
+          ", %d) failed; error='%s' (errno=%d)", p2i(addr), bytes, exec,
+          os::strerror(err), err);
+}
+
+static void warn_fail_commit_memory(char* addr, size_t bytes,
+                                    size_t alignment_hint, bool exec,
+                                    int err) {
+  warning("INFO: os::commit_memory(" PTR_FORMAT ", " SIZE_FORMAT
+          ", " SIZE_FORMAT ", %d) failed; error='%s' (errno=%d)", p2i(addr),
+          bytes, alignment_hint, exec, os::strerror(err), err);
+}
+
+int os::Solaris::commit_memory_impl(char* addr, size_t bytes, bool exec) {
+  int prot = exec ? PROT_READ|PROT_WRITE|PROT_EXEC : PROT_READ|PROT_WRITE;
+  size_t size = bytes;
+  char *res = Solaris::mmap_chunk(addr, size, MAP_PRIVATE|MAP_FIXED, prot);
+  if (res != NULL) {
+    if (UseNUMAInterleaving) {
+        numa_make_global(addr, bytes);
+    }
+    return 0;
+  }
+
+  int err = errno;  // save errno from mmap() call in mmap_chunk()
+
+  if (!recoverable_mmap_error(err)) {
+    warn_fail_commit_memory(addr, bytes, exec, err);
+    vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "committing reserved memory.");
+  }
+
+  return err;
+}
+
+bool os::pd_commit_memory(char* addr, size_t bytes, bool exec) {
+  return Solaris::commit_memory_impl(addr, bytes, exec) == 0;
+}
+
+void os::pd_commit_memory_or_exit(char* addr, size_t bytes, bool exec,
+                                  const char* mesg) {
+  assert(mesg != NULL, "mesg must be specified");
+  int err = os::Solaris::commit_memory_impl(addr, bytes, exec);
+  if (err != 0) {
+    // the caller wants all commit errors to exit with the specified mesg:
+    warn_fail_commit_memory(addr, bytes, exec, err);
+    vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg);
+  }
+}
+
+size_t os::Solaris::page_size_for_alignment(size_t alignment) {
+  assert(is_aligned(alignment, (size_t) vm_page_size()),
+         SIZE_FORMAT " is not aligned to " SIZE_FORMAT,
+         alignment, (size_t) vm_page_size());
+
+  int page_sizes_max = 9;
+  size_t _illumos_page_sizes[page_sizes_max];
+  int n = getpagesizes(_illumos_page_sizes, page_sizes_max);
+  for (int i = 0; _illumos_page_sizes[i] != 0; i++) {
+    if (is_aligned(alignment, _illumos_page_sizes[i])) {
+      return _illumos_page_sizes[i];
+    }
+  }
+
+  return (size_t) vm_page_size();
+}
+
+int os::Solaris::commit_memory_impl(char* addr, size_t bytes,
+                                    size_t alignment_hint, bool exec) {
+  int err = Solaris::commit_memory_impl(addr, bytes, exec);
+  if (err == 0 && UseLargePages && alignment_hint > 0) {
+    assert(is_aligned(bytes, alignment_hint),
+           SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, alignment_hint);
+
+    // The syscall memcntl requires an exact page size (see man memcntl for details).
+    size_t page_size = page_size_for_alignment(alignment_hint);
+    if (page_size > (size_t) vm_page_size()) {
+      (void)Solaris::setup_large_pages(addr, bytes, page_size);
+    }
+  }
+  return err;
+}
+
+bool os::pd_commit_memory(char* addr, size_t bytes, size_t alignment_hint,
+                          bool exec) {
+  return Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec) == 0;
+}
+
+void os::pd_commit_memory_or_exit(char* addr, size_t bytes,
+                                  size_t alignment_hint, bool exec,
+                                  const char* mesg) {
+  assert(mesg != NULL, "mesg must be specified");
+  int err = os::Solaris::commit_memory_impl(addr, bytes, alignment_hint, exec);
+  if (err != 0) {
+    // the caller wants all commit errors to exit with the specified mesg:
+    warn_fail_commit_memory(addr, bytes, alignment_hint, exec, err);
+    vm_exit_out_of_memory(bytes, OOM_MMAP_ERROR, "%s", mesg);
+  }
+}
+
+// Uncommit the pages in a specified region.
+void os::pd_free_memory(char* addr, size_t bytes, size_t alignment_hint) {
+  if (posix_madvise(addr, bytes, MADV_FREE) < 0) {
+    debug_only(warning("MADV_FREE failed."));
+    return;
+  }
+}
+
+bool os::pd_create_stack_guard_pages(char* addr, size_t size) {
+  return os::commit_memory(addr, size, !ExecMem);
+}
+
+bool os::remove_stack_guard_pages(char* addr, size_t size) {
+  return os::uncommit_memory(addr, size);
+}
+
+// Change the page size in a given range.
+void os::pd_realign_memory(char *addr, size_t bytes, size_t alignment_hint) {
+  assert((intptr_t)addr % alignment_hint == 0, "Address should be aligned.");
+  assert((intptr_t)(addr + bytes) % alignment_hint == 0, "End should be aligned.");
+  if (UseLargePages) {
+    size_t page_size = Solaris::page_size_for_alignment(alignment_hint);
+    if (page_size > (size_t) vm_page_size()) {
+      Solaris::setup_large_pages(addr, bytes, page_size);
+    }
+  }
+}
+
+// Tell the OS to make the range local to the first-touching LWP
+void os::numa_make_local(char *addr, size_t bytes, int lgrp_hint) {
+  assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
+  if (posix_madvise(addr, bytes, MADV_ACCESS_LWP) < 0) {
+    debug_only(warning("MADV_ACCESS_LWP failed."));
+  }
+}
+
+// Tell the OS that this range would be accessed from different LWPs.
+void os::numa_make_global(char *addr, size_t bytes) {
+  assert((intptr_t)addr % os::vm_page_size() == 0, "Address should be page-aligned.");
+  if (posix_madvise(addr, bytes, MADV_ACCESS_MANY) < 0) {
+    debug_only(warning("MADV_ACCESS_MANY failed."));
+  }
+}
+
+// Get the number of the locality groups.
+size_t os::numa_get_groups_num() {
+  size_t n = Solaris::lgrp_nlgrps(Solaris::lgrp_cookie());
+  return n != -1 ? n : 1;
+}
+
+// Get a list of leaf locality groups. A leaf lgroup is group that
+// doesn't have any children. Typical leaf group is a CPU or a CPU/memory
+// board. An LWP is assigned to one of these groups upon creation.
+size_t os::numa_get_leaf_groups(int *ids, size_t size) {
+  if ((ids[0] = Solaris::lgrp_root(Solaris::lgrp_cookie())) == -1) {
+    ids[0] = 0;
+    return 1;
+  }
+  int result_size = 0, top = 1, bottom = 0, cur = 0;
+  for (unsigned int k = 0; k < size; k++) {
+    int r = Solaris::lgrp_children(Solaris::lgrp_cookie(), ids[cur],
+                                   (Solaris::lgrp_id_t*)&ids[top], size - top);
+    if (r == -1) {
+      ids[0] = 0;
+      return 1;
+    }
+    if (!r) {
+      // That's a leaf node.
+      assert(bottom <= cur, "Sanity check");
+      // Check if the node has memory
+      if (Solaris::lgrp_resources(Solaris::lgrp_cookie(), ids[cur],
+                                  NULL, 0, LGRP_RSRC_MEM) > 0) {
+        ids[bottom++] = ids[cur];
+      }
+    }
+    top += r;
+    cur++;
+  }
+  if (bottom == 0) {
+    // Handle a situation, when the OS reports no memory available.
+    // Assume UMA architecture.
+    ids[0] = 0;
+    return 1;
+  }
+  return bottom;
+}
+
+// Detect the topology change. Typically happens during CPU plugging-unplugging.
+bool os::numa_topology_changed() {
+  int is_stale = Solaris::lgrp_cookie_stale(Solaris::lgrp_cookie());
+  if (is_stale != -1 && is_stale) {
+    Solaris::lgrp_fini(Solaris::lgrp_cookie());
+    Solaris::lgrp_cookie_t c = Solaris::lgrp_init(Solaris::LGRP_VIEW_CALLER);
+    assert(c != 0, "Failure to initialize LGRP API");
+    Solaris::set_lgrp_cookie(c);
+    return true;
+  }
+  return false;
+}
+
+// Get the group id of the current LWP.
+int os::numa_get_group_id() {
+  int lgrp_id = Solaris::lgrp_home(P_LWPID, P_MYID);
+  if (lgrp_id == -1) {
+    return 0;
+  }
+  const int size = os::numa_get_groups_num();
+  int *ids = (int*)alloca(size * sizeof(int));
+
+  // Get the ids of all lgroups with memory; r is the count.
+  int r = Solaris::lgrp_resources(Solaris::lgrp_cookie(), lgrp_id,
+                                  (Solaris::lgrp_id_t*)ids, size, LGRP_RSRC_MEM);
+  if (r <= 0) {
+    return 0;
+  }
+  return ids[os::random() % r];
+}
+
+int os::numa_get_group_id_for_address(const void* address) {
+  return 0;
+}
+
+// Request information about the page.
+bool os::get_page_info(char *start, page_info* info) {
+  const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE };
+  uint64_t addr = (uintptr_t)start;
+  uint64_t outdata[2];
+  uint_t validity = 0;
+
+  if (meminfo(&addr, 1, info_types, 2, outdata, &validity) < 0) {
+    return false;
+  }
+
+  info->size = 0;
+  info->lgrp_id = -1;
+
+  if ((validity & 1) != 0) {
+    if ((validity & 2) != 0) {
+      info->lgrp_id = outdata[0];
+    }
+    if ((validity & 4) != 0) {
+      info->size = outdata[1];
+    }
+    return true;
+  }
+  return false;
+}
+
+// Scan the pages from start to end until a page different than
+// the one described in the info parameter is encountered.
+char *os::scan_pages(char *start, char* end, page_info* page_expected,
+                     page_info* page_found) {
+  const uint_t info_types[] = { MEMINFO_VLGRP, MEMINFO_VPAGESIZE };
+  const size_t types = sizeof(info_types) / sizeof(info_types[0]);
+  uint64_t addrs[MAX_MEMINFO_CNT], outdata[types * MAX_MEMINFO_CNT + 1];
+  uint_t validity[MAX_MEMINFO_CNT];
+
+  size_t page_size = MAX2((size_t)os::vm_page_size(), page_expected->size);
+  uint64_t p = (uint64_t)start;
+  while (p < (uint64_t)end) {
+    addrs[0] = p;
+    size_t addrs_count = 1;
+    while (addrs_count < MAX_MEMINFO_CNT && addrs[addrs_count - 1] + page_size < (uint64_t)end) {
+      addrs[addrs_count] = addrs[addrs_count - 1] + page_size;
+      addrs_count++;
+    }
+
+    if (meminfo(addrs, addrs_count, info_types, types, outdata, validity) < 0) {
+      return NULL;
+    }
+
+    size_t i = 0;
+    for (; i < addrs_count; i++) {
+      if ((validity[i] & 1) != 0) {
+        if ((validity[i] & 4) != 0) {
+          if (outdata[types * i + 1] != page_expected->size) {
+            break;
+          }
+        } else if (page_expected->size != 0) {
+          break;
+        }
+
+        if ((validity[i] & 2) != 0 && page_expected->lgrp_id > 0) {
+          if (outdata[types * i] != page_expected->lgrp_id) {
+            break;
+          }
+        }
+      } else {
+        return NULL;
+      }
+    }
+
+    if (i < addrs_count) {
+      if ((validity[i] & 2) != 0) {
+        page_found->lgrp_id = outdata[types * i];
+      } else {
+        page_found->lgrp_id = -1;
+      }
+      if ((validity[i] & 4) != 0) {
+        page_found->size = outdata[types * i + 1];
+      } else {
+        page_found->size = 0;
+      }
+      return (char*)addrs[i];
+    }
+
+    p = addrs[addrs_count - 1] + page_size;
+  }
+  return end;
+}
+
+bool os::pd_uncommit_memory(char* addr, size_t bytes, bool exec) {
+  size_t size = bytes;
+  // Map uncommitted pages PROT_NONE so we fail early if we touch an
+  // uncommitted page. Otherwise, the read/write might succeed if we
+  // have enough swap space to back the physical page.
+  return
+    NULL != Solaris::mmap_chunk(addr, size,
+                                MAP_PRIVATE|MAP_FIXED|MAP_NORESERVE,
+                                PROT_NONE);
+}
+
+char* os::Solaris::mmap_chunk(char *addr, size_t size, int flags, int prot) {
+  char *b = (char *)mmap(addr, size, prot, flags, os::Solaris::_dev_zero_fd, 0);
+
+  if (b == MAP_FAILED) {
+    return NULL;
+  }
+  return b;
+}
+
+char* os::Solaris::anon_mmap(char* requested_addr, size_t bytes) {
+  char* addr = requested_addr;
+  int flags = MAP_PRIVATE | MAP_NORESERVE;
+
+  // Map uncommitted pages PROT_NONE so we fail early if we touch an
+  // uncommitted page. Otherwise, the read/write might succeed if we
+  // have enough swap space to back the physical page.
+  return mmap_chunk(addr, bytes, flags, PROT_NONE);
+}
+
+char* os::pd_reserve_memory(size_t bytes, bool exec) {
+  char* addr = Solaris::anon_mmap(NULL, bytes);
+
+  return addr;
+}
+
+char* os::pd_attempt_map_memory_to_file_at(char* requested_addr, size_t bytes, int file_desc) {
+  assert(file_desc >= 0, "file_desc is not valid");
+  char* result = pd_attempt_reserve_memory_at(requested_addr, bytes, !ExecMem);
+  if (result != NULL) {
+    if (replace_existing_mapping_with_file_mapping(result, bytes, file_desc) == NULL) {
+      vm_exit_during_initialization(err_msg("Error in mapping Java heap at the given filesystem directory"));
+    }
+  }
+  return result;
+}
+
+// Reserve memory at an arbitrary address, only if that area is
+// available (and not reserved for something else).
+
+char* os::pd_attempt_reserve_memory_at(char* requested_addr, size_t bytes, bool exec) {
+  // Assert only that the size is a multiple of the page size, since
+  // that's all that mmap requires, and since that's all we really know
+  // about at this low abstraction level.  If we need higher alignment,
+  // we can either pass an alignment to this method or verify alignment
+  // in one of the methods further up the call chain.  See bug 5044738.
+  assert(bytes % os::vm_page_size() == 0, "reserving unexpected size block");
+
+  // Since snv_84, Solaris attempts to honor the address hint - see 5003415.
+  char* addr = Solaris::anon_mmap(requested_addr, bytes);
+
+  volatile int err = errno;
+  if (addr == requested_addr) {
+    return addr;
+  }
+
+  if (addr != NULL) {
+    pd_unmap_memory(addr, bytes);
+  }
+
+  return NULL;
+}
+
+bool os::pd_release_memory(char* addr, size_t bytes) {
+  size_t size = bytes;
+  return munmap(addr, size) == 0;
+}
+
+static bool solaris_mprotect(char* addr, size_t bytes, int prot) {
+  assert(addr == (char*)align_down((uintptr_t)addr, os::vm_page_size()),
+         "addr must be page aligned");
+  Events::log(NULL, "Protecting memory [" INTPTR_FORMAT "," INTPTR_FORMAT "] with protection modes %x", p2i(addr), p2i(addr+bytes), prot);
+  int retVal = mprotect(addr, bytes, prot);
+  return retVal == 0;
+}
+
+// Protect memory (Used to pass readonly pages through
+// JNI GetArray<type>Elements with empty arrays.)
+// Also, used for serialization page and for compressed oops null pointer
+// checking.
+bool os::protect_memory(char* addr, size_t bytes, ProtType prot,
+                        bool is_committed) {
+  unsigned int p = 0;
+  switch (prot) {
+  case MEM_PROT_NONE: p = PROT_NONE; break;
+  case MEM_PROT_READ: p = PROT_READ; break;
+  case MEM_PROT_RW:   p = PROT_READ|PROT_WRITE; break;
+  case MEM_PROT_RWX:  p = PROT_READ|PROT_WRITE|PROT_EXEC; break;
+  default:
+    ShouldNotReachHere();
+  }
+  // is_committed is unused.
+  return solaris_mprotect(addr, bytes, p);
+}
+
+// guard_memory and unguard_memory only happens within stack guard pages.
+// Since ISM pertains only to the heap, guard and unguard memory should not
+/// happen with an ISM region.
+bool os::guard_memory(char* addr, size_t bytes) {
+  return solaris_mprotect(addr, bytes, PROT_NONE);
+}
+
+bool os::unguard_memory(char* addr, size_t bytes) {
+  return solaris_mprotect(addr, bytes, PROT_READ|PROT_WRITE);
+}
+
+// Large page support
+static size_t _large_page_size = 0;
+
+bool os::Solaris::mpss_sanity_check(bool warn, size_t* page_size) {
+  const unsigned int usable_count = VM_Version::page_size_count();
+  if (usable_count == 1) {
+    return false;
+  }
+
+  // Find the page sizes supported by the system
+  int page_sizes_max = 9;
+  size_t _illumos_page_sizes[page_sizes_max];
+  int n = getpagesizes(_illumos_page_sizes, page_sizes_max);
+  assert(n > 0, "illumos bug?");
+
+  if (n == 1) return false;     // Only one page size available.
+
+  // Skip sizes larger than 4M (or LargePageSizeInBytes if it was set)
+  const size_t size_limit =
+    FLAG_IS_DEFAULT(LargePageSizeInBytes) ? 4 * M : LargePageSizeInBytes;
+  int beg;
+  for (beg = 0; beg < n; ++beg) {
+    if (_illumos_page_sizes[beg] <= size_limit) {
+      _page_sizes.add(_illumos_page_sizes[beg]);
+      if (_illumos_page_sizes[beg] > *page_size) {
+        *page_size = _illumos_page_sizes[beg];
+      }
+    }
+  }
+  // make sure we add the default
+  _page_sizes.add(vm_page_size());
+  return true;
+}
+
+void os::large_page_init() {
+  if (UseLargePages) {
+    // print a warning if any large page related flag is specified on command line
+    bool warn_on_failure = !FLAG_IS_DEFAULT(UseLargePages)        ||
+                           !FLAG_IS_DEFAULT(LargePageSizeInBytes);
+
+    UseLargePages = Solaris::mpss_sanity_check(warn_on_failure, &_large_page_size);
+  }
+}
+
+bool os::Solaris::is_valid_page_size(size_t bytes) {
+  return _page_sizes.contains(bytes);
+}
+
+bool os::Solaris::setup_large_pages(caddr_t start, size_t bytes, size_t align) {
+  assert(is_valid_page_size(align), SIZE_FORMAT " is not a valid page size", align);
+  assert(is_aligned((void*) start, align),
+         PTR_FORMAT " is not aligned to " SIZE_FORMAT, p2i((void*) start), align);
+  assert(is_aligned(bytes, align),
+         SIZE_FORMAT " is not aligned to " SIZE_FORMAT, bytes, align);
+
+  // Signal to OS that we want large pages for addresses
+  // from addr, addr + bytes
+  struct memcntl_mha mpss_struct;
+  mpss_struct.mha_cmd = MHA_MAPSIZE_VA;
+  mpss_struct.mha_pagesize = align;
+  mpss_struct.mha_flags = 0;
+  // Upon successful completion, memcntl() returns 0
+  if (memcntl(start, bytes, MC_HAT_ADVISE, (caddr_t) &mpss_struct, 0, 0)) {
+    debug_only(warning("Attempt to use MPSS failed."));
+    return false;
+  }
+  return true;
+}
+
+char* os::pd_reserve_memory_special(size_t size, size_t alignment, size_t page_size, char* addr, bool exec) {
+  fatal("os::reserve_memory_special should not be called on Solaris.");
+  return NULL;
+}
+
+bool os::pd_release_memory_special(char* base, size_t bytes) {
+  fatal("os::release_memory_special should not be called on Solaris.");
+  return false;
+}
+
+size_t os::large_page_size() {
+  return _large_page_size;
+}
+
+// MPSS allows application to commit large page memory on demand; with ISM
+// the entire memory region must be allocated as shared memory.
+bool os::can_commit_large_page_memory() {
+  return true;
+}
+
+bool os::can_execute_large_page_memory() {
+  return true;
+}
+
+// Sleep forever; naked call to OS-specific sleep; use with CAUTION
+void os::infinite_sleep() {
+  while (true) {    // sleep forever ...
+    ::sleep(100);   // ... 100 seconds at a time
+  }
+}
+
+// Used to convert frequent JVM_Yield() to nops
+bool os::dont_yield() {
+  if (DontYieldALot) {
+    static hrtime_t last_time = 0;
+    hrtime_t diff = getTimeNanos() - last_time;
+
+    if (diff < DontYieldALotInterval * 1000000) {
+      return true;
+    }
+
+    last_time += diff;
+
+    return false;
+  } else {
+    return false;
+  }
+}
+
+// Note that yield semantics are defined by the scheduling class to which
+// the thread currently belongs.  Typically, yield will _not yield to
+// other equal or higher priority threads that reside on the dispatch queues
+// of other CPUs.
+
+void os::naked_yield() {
+  thr_yield();
+}
+
+// Interface for setting lwp priorities.  We are using T2 libthread,
+// which forces the use of bound threads, so all of our threads will
+// be assigned to real lwp's.  Using the thr_setprio function is
+// meaningless in this mode so we must adjust the real lwp's priority.
+// The routines below implement the getting and setting of lwp priorities.
+//
+// Note: There are three priority scales used on Solaris.  Java priorities
+//       which range from 1 to 10, libthread "thr_setprio" scale which range
+//       from 0 to 127, and the current scheduling class of the process we
+//       are running in.  This is typically from -60 to +60.
+//       The setting of the lwp priorities is done after a call to thr_setprio
+//       so Java priorities are mapped to libthread priorities and we map from
+//       the latter to lwp priorities.  We don't keep priorities stored in
+//       Java priorities since some of our worker threads want to set priorities
+//       higher than all Java threads.
+//
+// For related information:
+// (1)  man -s 2 priocntl
+// (2)  man -s 4 priocntl
+// (3)  man dispadmin
+// =    librt.so
+// =    libthread/common/rtsched.c - thrp_setlwpprio().
+// =    ps -cL <pid> ... to validate priority.
+// =    sched_get_priority_min and _max
+//              pthread_create
+//              sched_setparam
+//              pthread_setschedparam
+//
+// Assumptions:
+// +    We assume that all threads in the process belong to the same
+//              scheduling class.   IE. an homogenous process.
+// +    Must be root or in IA group to change change "interactive" attribute.
+//              Priocntl() will fail silently.  The only indication of failure is when
+//              we read-back the value and notice that it hasn't changed.
+// +    Interactive threads enter the runq at the head, non-interactive at the tail.
+// +    For RT, change timeslice as well.  Invariant:
+//              constant "priority integral"
+//              Konst == TimeSlice * (60-Priority)
+//              Given a priority, compute appropriate timeslice.
+// +    Higher numerical values have higher priority.
+
+// sched class attributes
+typedef struct {
+  int   schedPolicy;              // classID
+  int   maxPrio;
+  int   minPrio;
+} SchedInfo;
+
+
+static SchedInfo tsLimits, iaLimits, rtLimits, fxLimits;
+
+#ifdef ASSERT
+static int  ReadBackValidate = 1;
+#endif
+static int  myClass     = 0;
+static int  myMin       = 0;
+static int  myMax       = 0;
+static int  myCur       = 0;
+static bool priocntl_enable = false;
+
+static const int criticalPrio = FXCriticalPriority;
+static int java_MaxPriority_to_os_priority = 0; // Saved mapping
+
+
+// lwp_priocntl_init
+//
+// Try to determine the priority scale for our process.
+//
+// Return errno or 0 if OK.
+//
+static int lwp_priocntl_init() {
+  int rslt;
+  pcinfo_t ClassInfo;
+  pcparms_t ParmInfo;
+  int i;
+
+  if (!UseThreadPriorities) return 0;
+
+  // If ThreadPriorityPolicy is 1, switch tables
+  if (ThreadPriorityPolicy == 1) {
+    for (i = 0; i < CriticalPriority+1; i++)
+      os::java_to_os_priority[i] = prio_policy1[i];
+  }
+  if (UseCriticalJavaThreadPriority) {
+    // MaxPriority always maps to the FX scheduling class and criticalPrio.
+    // See set_native_priority() and set_lwp_class_and_priority().
+    // Save original MaxPriority mapping in case attempt to
+    // use critical priority fails.
+    java_MaxPriority_to_os_priority = os::java_to_os_priority[MaxPriority];
+    // Set negative to distinguish from other priorities
+    os::java_to_os_priority[MaxPriority] = -criticalPrio;
+  }
+
+  // Get IDs for a set of well-known scheduling classes.
+  // TODO-FIXME: GETCLINFO returns the current # of classes in the
+  // the system.  We should have a loop that iterates over the
+  // classID values, which are known to be "small" integers.
+
+  strcpy(ClassInfo.pc_clname, "TS");
+  ClassInfo.pc_cid = -1;
+  rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
+  if (rslt < 0) return errno;
+  assert(ClassInfo.pc_cid != -1, "cid for TS class is -1");
+  tsLimits.schedPolicy = ClassInfo.pc_cid;
+  tsLimits.maxPrio = ((tsinfo_t*)ClassInfo.pc_clinfo)->ts_maxupri;
+  tsLimits.minPrio = -tsLimits.maxPrio;
+
+  strcpy(ClassInfo.pc_clname, "IA");
+  ClassInfo.pc_cid = -1;
+  rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
+  if (rslt < 0) return errno;
+  assert(ClassInfo.pc_cid != -1, "cid for IA class is -1");
+  iaLimits.schedPolicy = ClassInfo.pc_cid;
+  iaLimits.maxPrio = ((iainfo_t*)ClassInfo.pc_clinfo)->ia_maxupri;
+  iaLimits.minPrio = -iaLimits.maxPrio;
+
+  strcpy(ClassInfo.pc_clname, "RT");
+  ClassInfo.pc_cid = -1;
+  rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
+  if (rslt < 0) return errno;
+  assert(ClassInfo.pc_cid != -1, "cid for RT class is -1");
+  rtLimits.schedPolicy = ClassInfo.pc_cid;
+  rtLimits.maxPrio = ((rtinfo_t*)ClassInfo.pc_clinfo)->rt_maxpri;
+  rtLimits.minPrio = 0;
+
+  strcpy(ClassInfo.pc_clname, "FX");
+  ClassInfo.pc_cid = -1;
+  rslt = priocntl(P_ALL, 0, PC_GETCID, (caddr_t)&ClassInfo);
+  if (rslt < 0) return errno;
+  assert(ClassInfo.pc_cid != -1, "cid for FX class is -1");
+  fxLimits.schedPolicy = ClassInfo.pc_cid;
+  fxLimits.maxPrio = ((fxinfo_t*)ClassInfo.pc_clinfo)->fx_maxupri;
+  fxLimits.minPrio = 0;
+
+  // Query our "current" scheduling class.
+  // This will normally be IA, TS or, rarely, FX or RT.
+  memset(&ParmInfo, 0, sizeof(ParmInfo));
+  ParmInfo.pc_cid = PC_CLNULL;
+  rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
+  if (rslt < 0) return errno;
+  myClass = ParmInfo.pc_cid;
+
+  // We now know our scheduling classId, get specific information
+  // about the class.
+  ClassInfo.pc_cid = myClass;
+  ClassInfo.pc_clname[0] = 0;
+  rslt = priocntl((idtype)0, 0, PC_GETCLINFO, (caddr_t)&ClassInfo);
+  if (rslt < 0) return errno;
+
+  if (ThreadPriorityVerbose) {
+    tty->print_cr("lwp_priocntl_init: Class=%d(%s)...", myClass, ClassInfo.pc_clname);
+  }
+
+  memset(&ParmInfo, 0, sizeof(pcparms_t));
+  ParmInfo.pc_cid = PC_CLNULL;
+  rslt = priocntl(P_PID, P_MYID, PC_GETPARMS, (caddr_t)&ParmInfo);
+  if (rslt < 0) return errno;
+
+  if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
+    myMin = rtLimits.minPrio;
+    myMax = rtLimits.maxPrio;
+  } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
+    iaparms_t *iaInfo  = (iaparms_t*)ParmInfo.pc_clparms;
+    myMin = iaLimits.minPrio;
+    myMax = iaLimits.maxPrio;
+    myMax = MIN2(myMax, (int)iaInfo->ia_uprilim);       // clamp - restrict
+  } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
+    tsparms_t *tsInfo  = (tsparms_t*)ParmInfo.pc_clparms;
+    myMin = tsLimits.minPrio;
+    myMax = tsLimits.maxPrio;
+    myMax = MIN2(myMax, (int)tsInfo->ts_uprilim);       // clamp - restrict
+  } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) {
+    fxparms_t *fxInfo = (fxparms_t*)ParmInfo.pc_clparms;
+    myMin = fxLimits.minPrio;
+    myMax = fxLimits.maxPrio;
+    myMax = MIN2(myMax, (int)fxInfo->fx_uprilim);       // clamp - restrict
+  } else {
+    // No clue - punt
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("Unknown scheduling class: %s ... \n",
+                    ClassInfo.pc_clname);
+    }
+    return EINVAL;      // no clue, punt
+  }
+
+  if (ThreadPriorityVerbose) {
+    tty->print_cr("Thread priority Range: [%d..%d]\n", myMin, myMax);
+  }
+
+  priocntl_enable = true;  // Enable changing priorities
+  return 0;
+}
+
+#define IAPRI(x)        ((iaparms_t *)((x).pc_clparms))
+#define RTPRI(x)        ((rtparms_t *)((x).pc_clparms))
+#define TSPRI(x)        ((tsparms_t *)((x).pc_clparms))
+#define FXPRI(x)        ((fxparms_t *)((x).pc_clparms))
+
+
+// scale_to_lwp_priority
+//
+// Convert from the libthread "thr_setprio" scale to our current
+// lwp scheduling class scale.
+//
+static int scale_to_lwp_priority(int rMin, int rMax, int x) {
+  int v;
+
+  if (x == 127) return rMax;            // avoid round-down
+  v = (((x*(rMax-rMin)))/128)+rMin;
+  return v;
+}
+
+
+// set_lwp_class_and_priority
+int set_lwp_class_and_priority(int ThreadID, int lwpid,
+                               int newPrio, int new_class, bool scale) {
+  int rslt;
+  int Actual, Expected, prv;
+  pcparms_t ParmInfo;                   // for GET-SET
+#ifdef ASSERT
+  pcparms_t ReadBack;                   // for readback
+#endif
+
+  // Set priority via PC_GETPARMS, update, PC_SETPARMS
+  // Query current values.
+  // TODO: accelerate this by eliminating the PC_GETPARMS call.
+  // Cache "pcparms_t" in global ParmCache.
+  // TODO: elide set-to-same-value
+
+  // If something went wrong on init, don't change priorities.
+  if (!priocntl_enable) {
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("Trying to set priority but init failed, ignoring");
+    }
+    return EINVAL;
+  }
+
+  // If lwp hasn't started yet, just return
+  // the _start routine will call us again.
+  if (lwpid <= 0) {
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("deferring the set_lwp_class_and_priority of thread "
+                    INTPTR_FORMAT " to %d, lwpid not set",
+                    (uintx)ThreadID, newPrio);
+    }
+    return 0;
+  }
+
+  if (ThreadPriorityVerbose) {
+    tty->print_cr ("set_lwp_class_and_priority("
+                   INTPTR_FORMAT "@" INTPTR_FORMAT " %d) ",
+                   (uintx)ThreadID, (uintx)lwpid, newPrio);
+  }
+
+  memset(&ParmInfo, 0, sizeof(pcparms_t));
+  ParmInfo.pc_cid = PC_CLNULL;
+  rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ParmInfo);
+  if (rslt < 0) return errno;
+
+  int cur_class = ParmInfo.pc_cid;
+  ParmInfo.pc_cid = (id_t)new_class;
+
+  if (new_class == rtLimits.schedPolicy) {
+    rtparms_t *rtInfo  = (rtparms_t*)ParmInfo.pc_clparms;
+    rtInfo->rt_pri     = scale ? scale_to_lwp_priority(rtLimits.minPrio,
+                                                       rtLimits.maxPrio, newPrio)
+                               : newPrio;
+    rtInfo->rt_tqsecs  = RT_NOCHANGE;
+    rtInfo->rt_tqnsecs = RT_NOCHANGE;
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("RT: %d->%d\n", newPrio, rtInfo->rt_pri);
+    }
+  } else if (new_class == iaLimits.schedPolicy) {
+    iaparms_t* iaInfo  = (iaparms_t*)ParmInfo.pc_clparms;
+    int maxClamped     = MIN2(iaLimits.maxPrio,
+                              cur_class == new_class
+                              ? (int)iaInfo->ia_uprilim : iaLimits.maxPrio);
+    iaInfo->ia_upri    = scale ? scale_to_lwp_priority(iaLimits.minPrio,
+                                                       maxClamped, newPrio)
+                               : newPrio;
+    iaInfo->ia_uprilim = cur_class == new_class
+                           ? IA_NOCHANGE : (pri_t)iaLimits.maxPrio;
+    iaInfo->ia_mode    = IA_NOCHANGE;
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("IA: [%d...%d] %d->%d\n",
+                    iaLimits.minPrio, maxClamped, newPrio, iaInfo->ia_upri);
+    }
+  } else if (new_class == tsLimits.schedPolicy) {
+    tsparms_t* tsInfo  = (tsparms_t*)ParmInfo.pc_clparms;
+    int maxClamped     = MIN2(tsLimits.maxPrio,
+                              cur_class == new_class
+                              ? (int)tsInfo->ts_uprilim : tsLimits.maxPrio);
+    tsInfo->ts_upri    = scale ? scale_to_lwp_priority(tsLimits.minPrio,
+                                                       maxClamped, newPrio)
+                               : newPrio;
+    tsInfo->ts_uprilim = cur_class == new_class
+                           ? TS_NOCHANGE : (pri_t)tsLimits.maxPrio;
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("TS: [%d...%d] %d->%d\n",
+                    tsLimits.minPrio, maxClamped, newPrio, tsInfo->ts_upri);
+    }
+  } else if (new_class == fxLimits.schedPolicy) {
+    fxparms_t* fxInfo  = (fxparms_t*)ParmInfo.pc_clparms;
+    int maxClamped     = MIN2(fxLimits.maxPrio,
+                              cur_class == new_class
+                              ? (int)fxInfo->fx_uprilim : fxLimits.maxPrio);
+    fxInfo->fx_upri    = scale ? scale_to_lwp_priority(fxLimits.minPrio,
+                                                       maxClamped, newPrio)
+                               : newPrio;
+    fxInfo->fx_uprilim = cur_class == new_class
+                           ? FX_NOCHANGE : (pri_t)fxLimits.maxPrio;
+    fxInfo->fx_tqsecs  = FX_NOCHANGE;
+    fxInfo->fx_tqnsecs = FX_NOCHANGE;
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("FX: [%d...%d] %d->%d\n",
+                    fxLimits.minPrio, maxClamped, newPrio, fxInfo->fx_upri);
+    }
+  } else {
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("Unknown new scheduling class %d\n", new_class);
+    }
+    return EINVAL;    // no clue, punt
+  }
+
+  rslt = priocntl(P_LWPID, lwpid, PC_SETPARMS, (caddr_t)&ParmInfo);
+  if (ThreadPriorityVerbose && rslt) {
+    tty->print_cr ("PC_SETPARMS ->%d %d\n", rslt, errno);
+  }
+  if (rslt < 0) return errno;
+
+#ifdef ASSERT
+  // Sanity check: read back what we just attempted to set.
+  // In theory it could have changed in the interim ...
+  //
+  // The priocntl system call is tricky.
+  // Sometimes it'll validate the priority value argument and
+  // return EINVAL if unhappy.  At other times it fails silently.
+  // Readbacks are prudent.
+
+  if (!ReadBackValidate) return 0;
+
+  memset(&ReadBack, 0, sizeof(pcparms_t));
+  ReadBack.pc_cid = PC_CLNULL;
+  rslt = priocntl(P_LWPID, lwpid, PC_GETPARMS, (caddr_t)&ReadBack);
+  assert(rslt >= 0, "priocntl failed");
+  Actual = Expected = 0xBAD;
+  assert(ParmInfo.pc_cid == ReadBack.pc_cid, "cid's don't match");
+  if (ParmInfo.pc_cid == rtLimits.schedPolicy) {
+    Actual   = RTPRI(ReadBack)->rt_pri;
+    Expected = RTPRI(ParmInfo)->rt_pri;
+  } else if (ParmInfo.pc_cid == iaLimits.schedPolicy) {
+    Actual   = IAPRI(ReadBack)->ia_upri;
+    Expected = IAPRI(ParmInfo)->ia_upri;
+  } else if (ParmInfo.pc_cid == tsLimits.schedPolicy) {
+    Actual   = TSPRI(ReadBack)->ts_upri;
+    Expected = TSPRI(ParmInfo)->ts_upri;
+  } else if (ParmInfo.pc_cid == fxLimits.schedPolicy) {
+    Actual   = FXPRI(ReadBack)->fx_upri;
+    Expected = FXPRI(ParmInfo)->fx_upri;
+  } else {
+    if (ThreadPriorityVerbose) {
+      tty->print_cr("set_lwp_class_and_priority: unexpected class in readback: %d\n",
+                    ParmInfo.pc_cid);
+    }
+  }
+
+  if (Actual != Expected) {
+    if (ThreadPriorityVerbose) {
+      tty->print_cr ("set_lwp_class_and_priority(%d %d) Class=%d: actual=%d vs expected=%d\n",
+                     lwpid, newPrio, ReadBack.pc_cid, Actual, Expected);
+    }
+  }
+#endif
+
+  return 0;
+}
+
+// Solaris only gives access to 128 real priorities at a time,
+// so we expand Java's ten to fill this range.  This would be better
+// if we dynamically adjusted relative priorities.
+//
+// The ThreadPriorityPolicy option allows us to select 2 different
+// priority scales.
+//
+// ThreadPriorityPolicy=0
+// Since the Solaris' default priority is MaximumPriority, we do not
+// set a priority lower than Max unless a priority lower than
+// NormPriority is requested.
+//
+// ThreadPriorityPolicy=1
+// This mode causes the priority table to get filled with
+// linear values.  NormPriority get's mapped to 50% of the
+// Maximum priority an so on.  This will cause VM threads
+// to get unfair treatment against other Solaris processes
+// which do not explicitly alter their thread priorities.
+
+int os::java_to_os_priority[CriticalPriority + 1] = {
+  -99999,         // 0 Entry should never be used
+
+  0,              // 1 MinPriority
+  32,             // 2
+  64,             // 3
+
+  96,             // 4
+  127,            // 5 NormPriority
+  127,            // 6
+
+  127,            // 7
+  127,            // 8
+  127,            // 9 NearMaxPriority
+
+  127,            // 10 MaxPriority
+
+  -criticalPrio   // 11 CriticalPriority
+};
+
+OSReturn os::set_native_priority(Thread* thread, int newpri) {
+  OSThread* osthread = thread->osthread();
+
+  // Save requested priority in case the thread hasn't been started
+  osthread->set_native_priority(newpri);
+
+  // Check for critical priority request
+  bool fxcritical = false;
+  if (newpri == -criticalPrio) {
+    fxcritical = true;
+    newpri = criticalPrio;
+  }
+
+  assert(newpri >= MinimumPriority && newpri <= MaximumPriority, "bad priority mapping");
+  if (!UseThreadPriorities) return OS_OK;
+
+  int status = 0;
+
+  if (!fxcritical) {
+    // Use thr_setprio only if we have a priority that thr_setprio understands
+    status = thr_setprio(thread->osthread()->thread_id(), newpri);
+  }
+
+  int lwp_status =
+          set_lwp_class_and_priority(osthread->thread_id(),
+                                     osthread->lwp_id(),
+                                     newpri,
+                                     fxcritical ? fxLimits.schedPolicy : myClass,
+                                     !fxcritical);
+  if (lwp_status != 0 && fxcritical) {
+    // Try again, this time without changing the scheduling class
+    newpri = java_MaxPriority_to_os_priority;
+    lwp_status = set_lwp_class_and_priority(osthread->thread_id(),
+                                            osthread->lwp_id(),
+                                            newpri, myClass, false);
+  }
+  status |= lwp_status;
+  return (status == 0) ? OS_OK : OS_ERR;
+}
+
+
+OSReturn os::get_native_priority(const Thread* const thread,
+                                 int *priority_ptr) {
+  int p;
+  if (!UseThreadPriorities) {
+    *priority_ptr = NormalPriority;
+    return OS_OK;
+  }
+  int status = thr_getprio(thread->osthread()->thread_id(), &p);
+  if (status != 0) {
+    return OS_ERR;
+  }
+  *priority_ptr = p;
+  return OS_OK;
+}
+
+////////////////////////////////////////////////////////////////////////////////
+
+void os::print_statistics() {
+}
+
+bool os::message_box(const char* title, const char* message) {
+  int i;
+  fdStream err(defaultStream::error_fd());
+  for (i = 0; i < 78; i++) err.print_raw("=");
+  err.cr();
+  err.print_raw_cr(title);
+  for (i = 0; i < 78; i++) err.print_raw("-");
+  err.cr();
+  err.print_raw_cr(message);
+  for (i = 0; i < 78; i++) err.print_raw("=");
+  err.cr();
+
+  char buf[16];
+  // Prevent process from exiting upon "read error" without consuming all CPU
+  while (::read(0, buf, sizeof(buf)) <= 0) { ::sleep(100); }
+
+  return buf[0] == 'y' || buf[0] == 'Y';
+}
+
+// This does not do anything on Solaris. This is basically a hook for being
+// able to use structured exception handling (thread-local exception filters) on, e.g., Win32.
+void os::os_exception_wrapper(java_call_t f, JavaValue* value,
+                              const methodHandle& method, JavaCallArguments* args,
+                              JavaThread* thread) {
+  f(value, method, args, thread);
+}
+
+void report_error(const char* file_name, int line_no, const char* title,
+                  const char* format, ...);
+
+// (Static) wrappers for the liblgrp API
+os::Solaris::lgrp_home_func_t os::Solaris::_lgrp_home;
+os::Solaris::lgrp_init_func_t os::Solaris::_lgrp_init;
+os::Solaris::lgrp_fini_func_t os::Solaris::_lgrp_fini;
+os::Solaris::lgrp_root_func_t os::Solaris::_lgrp_root;
+os::Solaris::lgrp_children_func_t os::Solaris::_lgrp_children;
+os::Solaris::lgrp_resources_func_t os::Solaris::_lgrp_resources;
+os::Solaris::lgrp_nlgrps_func_t os::Solaris::_lgrp_nlgrps;
+os::Solaris::lgrp_cookie_stale_func_t os::Solaris::_lgrp_cookie_stale;
+os::Solaris::lgrp_cookie_t os::Solaris::_lgrp_cookie = 0;
+
+static address resolve_symbol_lazy(const char* name) {
+  address addr = (address) dlsym(RTLD_DEFAULT, name);
+  if (addr == NULL) {
+    // RTLD_DEFAULT was not defined on some early versions of 2.5.1
+    addr = (address) dlsym(RTLD_NEXT, name);
+  }
+  return addr;
+}
+
+static address resolve_symbol(const char* name) {
+  address addr = resolve_symbol_lazy(name);
+  if (addr == NULL) {
+    fatal("resolve_symbol failed (%s)", dlerror());
+  }
+  return addr;
+}
+
+void os::Solaris::libthread_init() {
+  address func = (address)dlsym(RTLD_DEFAULT, "_thr_suspend_allmutators");
+
+  lwp_priocntl_init();
+
+  // RTLD_DEFAULT was not defined on some early versions of 5.5.1
+  if (func == NULL) {
+    func = (address) dlsym(RTLD_NEXT, "_thr_suspend_allmutators");
+    // Guarantee that this VM is running on an new enough OS (5.6 or
+    // later) that it will have a new enough libthread.so.
+    guarantee(func != NULL, "libthread.so is too old.");
+  }
+
+  int size;
+  void (*handler_info_func)(address *, int *);
+  handler_info_func = CAST_TO_FN_PTR(void (*)(address *, int *), resolve_symbol("thr_sighndlrinfo"));
+  handler_info_func(&handler_start, &size);
+  handler_end = handler_start + size;
+}
+
+
+int_fnP_mutex_tP os::Solaris::_mutex_lock;
+int_fnP_mutex_tP os::Solaris::_mutex_trylock;
+int_fnP_mutex_tP os::Solaris::_mutex_unlock;
+int_fnP_mutex_tP_i_vP os::Solaris::_mutex_init;
+int_fnP_mutex_tP os::Solaris::_mutex_destroy;
+int os::Solaris::_mutex_scope = USYNC_THREAD;
+
+int_fnP_cond_tP_mutex_tP_timestruc_tP os::Solaris::_cond_timedwait;
+int_fnP_cond_tP_mutex_tP os::Solaris::_cond_wait;
+int_fnP_cond_tP os::Solaris::_cond_signal;
+int_fnP_cond_tP os::Solaris::_cond_broadcast;
+int_fnP_cond_tP_i_vP os::Solaris::_cond_init;
+int_fnP_cond_tP os::Solaris::_cond_destroy;
+int os::Solaris::_cond_scope = USYNC_THREAD;
+bool os::Solaris::_synchronization_initialized;
+
+void os::Solaris::synchronization_init() {
+  if (UseLWPSynchronization) {
+    os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_lock")));
+    os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_trylock")));
+    os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("_lwp_mutex_unlock")));
+    os::Solaris::set_mutex_init(lwp_mutex_init);
+    os::Solaris::set_mutex_destroy(lwp_mutex_destroy);
+    os::Solaris::set_mutex_scope(USYNC_THREAD);
+
+    os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("_lwp_cond_timedwait")));
+    os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("_lwp_cond_wait")));
+    os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("_lwp_cond_signal")));
+    os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("_lwp_cond_broadcast")));
+    os::Solaris::set_cond_init(lwp_cond_init);
+    os::Solaris::set_cond_destroy(lwp_cond_destroy);
+    os::Solaris::set_cond_scope(USYNC_THREAD);
+  } else {
+    os::Solaris::set_mutex_scope(USYNC_THREAD);
+    os::Solaris::set_cond_scope(USYNC_THREAD);
+
+    if (UsePthreads) {
+      os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_lock")));
+      os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_trylock")));
+      os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_unlock")));
+      os::Solaris::set_mutex_init(pthread_mutex_default_init);
+      os::Solaris::set_mutex_destroy(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("pthread_mutex_destroy")));
+
+      os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("pthread_cond_timedwait")));
+      os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("pthread_cond_wait")));
+      os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_signal")));
+      os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_broadcast")));
+      os::Solaris::set_cond_init(pthread_cond_default_init);
+      os::Solaris::set_cond_destroy(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("pthread_cond_destroy")));
+    } else {
+      os::Solaris::set_mutex_lock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_lock")));
+      os::Solaris::set_mutex_trylock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_trylock")));
+      os::Solaris::set_mutex_unlock(CAST_TO_FN_PTR(int_fnP_mutex_tP, resolve_symbol("mutex_unlock")));
+      os::Solaris::set_mutex_init(::mutex_init);
+      os::Solaris::set_mutex_destroy(::mutex_destroy);
+
+      os::Solaris::set_cond_timedwait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP_timestruc_tP, resolve_symbol("cond_timedwait")));
+      os::Solaris::set_cond_wait(CAST_TO_FN_PTR(int_fnP_cond_tP_mutex_tP, resolve_symbol("cond_wait")));
+      os::Solaris::set_cond_signal(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("cond_signal")));
+      os::Solaris::set_cond_broadcast(CAST_TO_FN_PTR(int_fnP_cond_tP, resolve_symbol("cond_broadcast")));
+      os::Solaris::set_cond_init(::cond_init);
+      os::Solaris::set_cond_destroy(::cond_destroy);
+    }
+  }
+  _synchronization_initialized = true;
+}
+
+bool os::Solaris::liblgrp_init() {
+  void *handle = dlopen("liblgrp.so.1", RTLD_LAZY);
+  if (handle != NULL) {
+    os::Solaris::set_lgrp_home(CAST_TO_FN_PTR(lgrp_home_func_t, dlsym(handle, "lgrp_home")));
+    os::Solaris::set_lgrp_init(CAST_TO_FN_PTR(lgrp_init_func_t, dlsym(handle, "lgrp_init")));
+    os::Solaris::set_lgrp_fini(CAST_TO_FN_PTR(lgrp_fini_func_t, dlsym(handle, "lgrp_fini")));
+    os::Solaris::set_lgrp_root(CAST_TO_FN_PTR(lgrp_root_func_t, dlsym(handle, "lgrp_root")));
+    os::Solaris::set_lgrp_children(CAST_TO_FN_PTR(lgrp_children_func_t, dlsym(handle, "lgrp_children")));
+    os::Solaris::set_lgrp_resources(CAST_TO_FN_PTR(lgrp_resources_func_t, dlsym(handle, "lgrp_resources")));
+    os::Solaris::set_lgrp_nlgrps(CAST_TO_FN_PTR(lgrp_nlgrps_func_t, dlsym(handle, "lgrp_nlgrps")));
+    os::Solaris::set_lgrp_cookie_stale(CAST_TO_FN_PTR(lgrp_cookie_stale_func_t,
+                                                      dlsym(handle, "lgrp_cookie_stale")));
+
+    lgrp_cookie_t c = lgrp_init(LGRP_VIEW_CALLER);
+    set_lgrp_cookie(c);
+    return true;
+  }
+  return false;
+}
+
+// int pset_getloadavg(psetid_t pset, double loadavg[], int nelem);
+typedef long (*pset_getloadavg_type)(psetid_t pset, double loadavg[], int nelem);
+static pset_getloadavg_type pset_getloadavg_ptr = NULL;
+
+void init_pset_getloadavg_ptr(void) {
+  pset_getloadavg_ptr =
+    (pset_getloadavg_type)dlsym(RTLD_DEFAULT, "pset_getloadavg");
+  if (pset_getloadavg_ptr == NULL) {
+    log_warning(os)("pset_getloadavg function not found");
+  }
+}
+
+int os::Solaris::_dev_zero_fd = -1;
+
+// this is called _before_ the global arguments have been parsed
+void os::init(void) {
+  _initial_pid = getpid();
+
+  max_hrtime = first_hrtime = gethrtime();
+
+  init_random(1234567);
+
+  Solaris::set_page_size(sysconf(_SC_PAGESIZE));
+  if (Solaris::page_size() == -1) {
+    fatal("os_solaris.cpp: os::init: sysconf failed (%s)", os::strerror(errno));
+  }
+  _page_sizes.add(Solaris::page_size());
+
+  Solaris::initialize_system_info();
+
+  int fd = ::open("/dev/zero", O_RDWR);
+  if (fd < 0) {
+    fatal("os::init: cannot open /dev/zero (%s)", os::strerror(errno));
+  } else {
+    Solaris::set_dev_zero_fd(fd);
+
+    // Close on exec, child won't inherit.
+    fcntl(fd, F_SETFD, FD_CLOEXEC);
+  }
+
+  clock_tics_per_sec = CLK_TCK;
+
+  // check if dladdr1() exists; dladdr1 can provide more information than
+  // dladdr for os::dll_address_to_function_name. It comes with SunOS 5.9
+  // and is available on linker patches for 5.7 and 5.8.
+  // libdl.so must have been loaded, this call is just an entry lookup
+  void * hdl = dlopen("libdl.so", RTLD_NOW);
+  if (hdl) {
+    dladdr1_func = CAST_TO_FN_PTR(dladdr1_func_type, dlsym(hdl, "dladdr1"));
+  }
+
+  // main_thread points to the thread that created/loaded the JVM.
+  main_thread = thr_self();
+
+  // dynamic lookup of functions that may not be available in our lowest
+  // supported Solaris release
+  void * handle = dlopen("libc.so.1", RTLD_LAZY);
+  if (handle != NULL) {
+    Solaris::_pthread_setname_np =  // from 11.3
+        (Solaris::pthread_setname_np_func_t)dlsym(handle, "pthread_setname_np");
+  }
+
+  // Shared Posix initialization
+  os::Posix::init();
+}
+
+// To install functions for atexit system call
+extern "C" {
+  static void perfMemory_exit_helper() {
+    perfMemory_exit();
+  }
+}
+
+// this is called _after_ the global arguments have been parsed
+jint os::init_2(void) {
+  // Check and sets minimum stack sizes against command line options
+  if (Posix::set_minimum_stack_sizes() == JNI_ERR) {
+    return JNI_ERR;
+  }
+
+  Solaris::libthread_init();
+
+  if (UseNUMA) {
+    if (!Solaris::liblgrp_init()) {
+      FLAG_SET_ERGO(UseNUMA, false);
+    } else {
+      size_t lgrp_limit = os::numa_get_groups_num();
+      int *lgrp_ids = NEW_C_HEAP_ARRAY(int, lgrp_limit, mtInternal);
+      size_t lgrp_num = os::numa_get_leaf_groups(lgrp_ids, lgrp_limit);
+      FREE_C_HEAP_ARRAY(int, lgrp_ids);
+      if (lgrp_num < 2) {
+        // There's only one locality group, disable NUMA
+        UseNUMA = false;
+      }
+    }
+  }
+
+  // When NUMA requested, not-NUMA-aware allocations default to interleaving.
+  if (UseNUMA && !UseNUMAInterleaving) {
+    FLAG_SET_ERGO_IF_DEFAULT(UseNUMAInterleaving, true);
+  }
+
+  Solaris::init_signal_mem();
+  if (PosixSignals::init() == JNI_ERR) {
+    return JNI_ERR;
+  }
+
+  // initialize synchronization primitives
+  Solaris::synchronization_init();
+  DEBUG_ONLY(os::set_mutex_init_done();)
+
+  if (MaxFDLimit) {
+    // set the number of file descriptors to max. print out error
+    // if getrlimit/setrlimit fails but continue regardless.
+    struct rlimit nbr_files;
+    int status = getrlimit(RLIMIT_NOFILE, &nbr_files);
+    if (status != 0) {
+      log_info(os)("os::init_2 getrlimit failed: %s", os::strerror(errno));
+    } else {
+      nbr_files.rlim_cur = nbr_files.rlim_max;
+      status = setrlimit(RLIMIT_NOFILE, &nbr_files);
+      if (status != 0) {
+        log_info(os)("os::init_2 setrlimit failed: %s", os::strerror(errno));
+      }
+    }
+  }
+
+  // Calculate theoretical max. size of Threads to guard gainst
+  // artifical out-of-memory situations, where all available address-
+  // space has been reserved by thread stacks. Default stack size is 1Mb.
+  size_t pre_thread_stack_size = (JavaThread::stack_size_at_create()) ?
+    JavaThread::stack_size_at_create() : (1*K*K);
+  assert(pre_thread_stack_size != 0, "Must have a stack");
+  // Solaris has a maximum of 4Gb of user programs. Calculate the thread limit when
+  // we should start doing Virtual Memory banging. Currently when the threads will
+  // have used all but 200Mb of space.
+  size_t max_address_space = ((unsigned int)4 * K * K * K) - (200 * K * K);
+  Solaris::_os_thread_limit = max_address_space / pre_thread_stack_size;
+
+  // at-exit methods are called in the reverse order of their registration.
+  // In Solaris 7 and earlier, atexit functions are called on return from
+  // main or as a result of a call to exit(3C). There can be only 32 of
+  // these functions registered and atexit() does not set errno. In Solaris
+  // 8 and later, there is no limit to the number of functions registered
+  // and atexit() sets errno. In addition, in Solaris 8 and later, atexit
+  // functions are called upon dlclose(3DL) in addition to return from main
+  // and exit(3C).
+
+  if (PerfAllowAtExitRegistration) {
+    // only register atexit functions if PerfAllowAtExitRegistration is set.
+    // atexit functions can be delayed until process exit time, which
+    // can be problematic for embedded VM situations. Embedded VMs should
+    // call DestroyJavaVM() to assure that VM resources are released.
+
+    // note: perfMemory_exit_helper atexit function may be removed in
+    // the future if the appropriate cleanup code can be added to the
+    // VM_Exit VMOperation's doit method.
+    if (atexit(perfMemory_exit_helper) != 0) {
+      warning("os::init2 atexit(perfMemory_exit_helper) failed");
+    }
+  }
+
+  // Init pset_loadavg function pointer
+  init_pset_getloadavg_ptr();
+
+  // Shared Posix initialization
+  os::Posix::init_2();
+
+  return JNI_OK;
+}
+
+// Is a (classpath) directory empty?
+bool os::dir_is_empty(const char* path) {
+  DIR *dir = NULL;
+  struct dirent *ptr;
+
+  dir = opendir(path);
+  if (dir == NULL) return true;
+
+  // Scan the directory
+  bool result = true;
+  while (result && (ptr = readdir(dir)) != NULL) {
+    if (strcmp(ptr->d_name, ".") != 0 && strcmp(ptr->d_name, "..") != 0) {
+      result = false;
+    }
+  }
+  closedir(dir);
+  return result;
+}
+
+// This code originates from JDK's sysOpen and open64_w
+// from src/solaris/hpi/src/system_md.c
+
+int os::open(const char *path, int oflag, int mode) {
+  if (strlen(path) > MAX_PATH - 1) {
+    errno = ENAMETOOLONG;
+    return -1;
+  }
+  int fd;
+
+  fd = ::open64(path, oflag, mode);
+  if (fd == -1) return -1;
+
+  // If the open succeeded, the file might still be a directory
+  {
+    struct stat64 buf64;
+    int ret = ::fstat64(fd, &buf64);
+    int st_mode = buf64.st_mode;
+
+    if (ret != -1) {
+      if ((st_mode & S_IFMT) == S_IFDIR) {
+        errno = EISDIR;
+        ::close(fd);
+        return -1;
+      }
+    } else {
+      ::close(fd);
+      return -1;
+    }
+  }
+
+  // 32-bit Solaris systems suffer from:
+  //
+  // - an historical default soft limit of 256 per-process file
+  //   descriptors that is too low for many Java programs.
+  //
+  // - a design flaw where file descriptors created using stdio
+  //   fopen must be less than 256, _even_ when the first limit above
+  //   has been raised.  This can cause calls to fopen (but not calls to
+  //   open, for example) to fail mysteriously, perhaps in 3rd party
+  //   native code (although the JDK itself uses fopen).  One can hardly
+  //   criticize them for using this most standard of all functions.
+  //
+  // We attempt to make everything work anyways by:
+  //
+  // - raising the soft limit on per-process file descriptors beyond
+  //   256
+  //
+  // - As of Solaris 10u4, we can request that Solaris raise the 256
+  //   stdio fopen limit by calling function enable_extended_FILE_stdio.
+  //   This is done in init_2 and recorded in enabled_extended_FILE_stdio
+  //
+  // - If we are stuck on an old (pre 10u4) Solaris system, we can
+  //   workaround the bug by remapping non-stdio file descriptors below
+  //   256 to ones beyond 256, which is done below.
+  //
+  // See:
+  // 1085341: 32-bit stdio routines should support file descriptors >255
+  // 6533291: Work around 32-bit Solaris stdio limit of 256 open files
+  // 6431278: Netbeans crash on 32 bit Solaris: need to call
+  //          enable_extended_FILE_stdio() in VM initialisation
+  // Giri Mandalika's blog
+  // http://technopark02.blogspot.com/2005_05_01_archive.html
+  //
+#ifndef  _LP64
+  if ((!enabled_extended_FILE_stdio) && fd < 256) {
+    int newfd = ::fcntl(fd, F_DUPFD, 256);
+    if (newfd != -1) {
+      ::close(fd);
+      fd = newfd;
+    }
+  }
+#endif // 32-bit Solaris
+
+  // All file descriptors that are opened in the JVM and not
+  // specifically destined for a subprocess should have the
+  // close-on-exec flag set.  If we don't set it, then careless 3rd
+  // party native code might fork and exec without closing all
+  // appropriate file descriptors (e.g. as we do in closeDescriptors in
+  // UNIXProcess.c), and this in turn might:
+  //
+  // - cause end-of-file to fail to be detected on some file
+  //   descriptors, resulting in mysterious hangs, or
+  //
+  // - might cause an fopen in the subprocess to fail on a system
+  //   suffering from bug 1085341.
+  //
+  // (Yes, the default setting of the close-on-exec flag is a Unix
+  // design flaw)
+  //
+  // See:
+  // 1085341: 32-bit stdio routines should support file descriptors >255
+  // 4843136: (process) pipe file descriptor from Runtime.exec not being closed
+  // 6339493: (process) Runtime.exec does not close all file descriptors on Solaris 9
+  //
+#ifdef FD_CLOEXEC
+  {
+    int flags = ::fcntl(fd, F_GETFD);
+    if (flags != -1) {
+      ::fcntl(fd, F_SETFD, flags | FD_CLOEXEC);
+    }
+  }
+#endif
+
+  return fd;
+}
+
+// create binary file, rewriting existing file if required
+int os::create_binary_file(const char* path, bool rewrite_existing) {
+  int oflags = O_WRONLY | O_CREAT;
+  if (!rewrite_existing) {
+    oflags |= O_EXCL;
+  }
+  return ::open64(path, oflags, S_IREAD | S_IWRITE);
+}
+
+// return current position of file pointer
+jlong os::current_file_offset(int fd) {
+  return (jlong)::lseek64(fd, (off64_t)0, SEEK_CUR);
+}
+
+// move file pointer to the specified offset
+jlong os::seek_to_file_offset(int fd, jlong offset) {
+  return (jlong)::lseek64(fd, (off64_t)offset, SEEK_SET);
+}
+
+int os::available(int fd, jlong *bytes) {
+  assert(((JavaThread*)Thread::current())->thread_state() == _thread_in_native,
+         "Assumed _thread_in_native");
+  jlong cur, end;
+  int mode;
+  struct stat64 buf64;
+
+  if (::fstat64(fd, &buf64) >= 0) {
+    mode = buf64.st_mode;
+    if (S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) {
+      int n,ioctl_return;
+
+      RESTARTABLE(::ioctl(fd, FIONREAD, &n), ioctl_return);
+      if (ioctl_return>= 0) {
+        *bytes = n;
+        return 1;
+      }
+    }
+  }
+  if ((cur = ::lseek64(fd, 0L, SEEK_CUR)) == -1) {
+    return 0;
+  } else if ((end = ::lseek64(fd, 0L, SEEK_END)) == -1) {
+    return 0;
+  } else if (::lseek64(fd, cur, SEEK_SET) == -1) {
+    return 0;
+  }
+  *bytes = end - cur;
+  return 1;
+}
+
+// Map a block of memory.
+char* os::pd_map_memory(int fd, const char* file_name, size_t file_offset,
+                        char *addr, size_t bytes, bool read_only,
+                        bool allow_exec) {
+  int prot;
+  int flags;
+
+  if (read_only) {
+    prot = PROT_READ;
+    flags = MAP_SHARED;
+  } else {
+    prot = PROT_READ | PROT_WRITE;
+    flags = MAP_PRIVATE;
+  }
+
+  if (allow_exec) {
+    prot |= PROT_EXEC;
+  }
+
+  if (addr != NULL) {
+    flags |= MAP_FIXED;
+  }
+
+  char* mapped_address = (char*)mmap(addr, (size_t)bytes, prot, flags,
+                                     fd, file_offset);
+  if (mapped_address == MAP_FAILED) {
+    return NULL;
+  }
+  return mapped_address;
+}
+
+
+// Remap a block of memory.
+char* os::pd_remap_memory(int fd, const char* file_name, size_t file_offset,
+                          char *addr, size_t bytes, bool read_only,
+                          bool allow_exec) {
+  // same as map_memory() on this OS
+  return os::map_memory(fd, file_name, file_offset, addr, bytes, read_only,
+                        allow_exec);
+}
+
+
+// Unmap a block of memory.
+bool os::pd_unmap_memory(char* addr, size_t bytes) {
+  return munmap(addr, bytes) == 0;
+}
+
+void os::pause() {
+  char filename[MAX_PATH];
+  if (PauseAtStartupFile && PauseAtStartupFile[0]) {
+    jio_snprintf(filename, MAX_PATH, "%s", PauseAtStartupFile);
+  } else {
+    jio_snprintf(filename, MAX_PATH, "./vm.paused.%d", current_process_id());
+  }
+
+  int fd = ::open(filename, O_WRONLY | O_CREAT | O_TRUNC, 0666);
+  if (fd != -1) {
+    struct stat buf;
+    ::close(fd);
+    while (::stat(filename, &buf) == 0) {
+      (void)::poll(NULL, 0, 100);
+    }
+  } else {
+    jio_fprintf(stderr,
+                "Could not open pause file '%s', continuing immediately.\n", filename);
+  }
+}
+
+#ifndef PRODUCT
+#ifdef INTERPOSE_ON_SYSTEM_SYNCH_FUNCTIONS
+// Turn this on if you need to trace synch operations.
+// Set RECORD_SYNCH_LIMIT to a large-enough value,
+// and call record_synch_enable and record_synch_disable
+// around the computation of interest.
+
+void record_synch(char* name, bool returning);  // defined below
+
+class RecordSynch {
+  char* _name;
+ public:
+  RecordSynch(char* name) :_name(name) { record_synch(_name, false); }
+  ~RecordSynch()                       { record_synch(_name, true); }
+};
+
+#define CHECK_SYNCH_OP(ret, name, params, args, inner)          \
+extern "C" ret name params {                                    \
+  typedef ret name##_t params;                                  \
+  static name##_t* implem = NULL;                               \
+  static int callcount = 0;                                     \
+  if (implem == NULL) {                                         \
+    implem = (name##_t*) dlsym(RTLD_NEXT, #name);               \
+    if (implem == NULL)  fatal(dlerror());                      \
+  }                                                             \
+  ++callcount;                                                  \
+  RecordSynch _rs(#name);                                       \
+  inner;                                                        \
+  return implem args;                                           \
+}
+// in dbx, examine callcounts this way:
+// for n in $(eval whereis callcount | awk '{print $2}'); do print $n; done
+
+#define CHECK_POINTER_OK(p) \
+  (!Universe::is_fully_initialized() || !Universe::is_reserved_heap((oop)(p)))
+#define CHECK_MU \
+  if (!CHECK_POINTER_OK(mu)) fatal("Mutex must be in C heap only.");
+#define CHECK_CV \
+  if (!CHECK_POINTER_OK(cv)) fatal("Condvar must be in C heap only.");
+#define CHECK_P(p) \
+  if (!CHECK_POINTER_OK(p))  fatal(false,  "Pointer must be in C heap only.");
+
+#define CHECK_MUTEX(mutex_op) \
+  CHECK_SYNCH_OP(int, mutex_op, (mutex_t *mu), (mu), CHECK_MU);
+
+CHECK_MUTEX(   mutex_lock)
+CHECK_MUTEX(  _mutex_lock)
+CHECK_MUTEX( mutex_unlock)
+CHECK_MUTEX(_mutex_unlock)
+CHECK_MUTEX( mutex_trylock)
+CHECK_MUTEX(_mutex_trylock)
+
+#define CHECK_COND(cond_op) \
+  CHECK_SYNCH_OP(int, cond_op, (cond_t *cv, mutex_t *mu), (cv, mu), CHECK_MU; CHECK_CV);
+
+CHECK_COND( cond_wait);
+CHECK_COND(_cond_wait);
+CHECK_COND(_cond_wait_cancel);
+
+#define CHECK_COND2(cond_op) \
+  CHECK_SYNCH_OP(int, cond_op, (cond_t *cv, mutex_t *mu, timestruc_t* ts), (cv, mu, ts), CHECK_MU; CHECK_CV);
+
+CHECK_COND2( cond_timedwait);
+CHECK_COND2(_cond_timedwait);
+CHECK_COND2(_cond_timedwait_cancel);
+
+// do the _lwp_* versions too
+#define mutex_t lwp_mutex_t
+#define cond_t  lwp_cond_t
+CHECK_MUTEX(  _lwp_mutex_lock)
+CHECK_MUTEX(  _lwp_mutex_unlock)
+CHECK_MUTEX(  _lwp_mutex_trylock)
+CHECK_MUTEX( __lwp_mutex_lock)
+CHECK_MUTEX( __lwp_mutex_unlock)
+CHECK_MUTEX( __lwp_mutex_trylock)
+CHECK_MUTEX(___lwp_mutex_lock)
+CHECK_MUTEX(___lwp_mutex_unlock)
+
+CHECK_COND(  _lwp_cond_wait);
+CHECK_COND( __lwp_cond_wait);
+CHECK_COND(___lwp_cond_wait);
+
+CHECK_COND2(  _lwp_cond_timedwait);
+CHECK_COND2( __lwp_cond_timedwait);
+#undef mutex_t
+#undef cond_t
+
+CHECK_SYNCH_OP(int, _lwp_suspend2,       (int lwp, int *n), (lwp, n), 0);
+CHECK_SYNCH_OP(int,__lwp_suspend2,       (int lwp, int *n), (lwp, n), 0);
+CHECK_SYNCH_OP(int, _lwp_kill,           (int lwp, int n),  (lwp, n), 0);
+CHECK_SYNCH_OP(int,__lwp_kill,           (int lwp, int n),  (lwp, n), 0);
+CHECK_SYNCH_OP(int, _lwp_sema_wait,      (lwp_sema_t* p),   (p),  CHECK_P(p));
+CHECK_SYNCH_OP(int,__lwp_sema_wait,      (lwp_sema_t* p),   (p),  CHECK_P(p));
+CHECK_SYNCH_OP(int, _lwp_cond_broadcast, (lwp_cond_t* cv),  (cv), CHECK_CV);
+CHECK_SYNCH_OP(int,__lwp_cond_broadcast, (lwp_cond_t* cv),  (cv), CHECK_CV);
+
+
+// recording machinery:
+
+enum { RECORD_SYNCH_LIMIT = 200 };
+char* record_synch_name[RECORD_SYNCH_LIMIT];
+void* record_synch_arg0ptr[RECORD_SYNCH_LIMIT];
+bool record_synch_returning[RECORD_SYNCH_LIMIT];
+thread_t record_synch_thread[RECORD_SYNCH_LIMIT];
+int record_synch_count = 0;
+bool record_synch_enabled = false;
+
+// in dbx, examine recorded data this way:
+// for n in name arg0ptr returning thread; do print record_synch_$n[0..record_synch_count-1]; done
+
+void record_synch(char* name, bool returning) {
+  if (record_synch_enabled) {
+    if (record_synch_count < RECORD_SYNCH_LIMIT) {
+      record_synch_name[record_synch_count] = name;
+      record_synch_returning[record_synch_count] = returning;
+      record_synch_thread[record_synch_count] = thr_self();
+      record_synch_arg0ptr[record_synch_count] = &name;
+      record_synch_count++;
+    }
+    // put more checking code here:
+    // ...
+  }
+}
+
+void record_synch_enable() {
+  // start collecting trace data, if not already doing so
+  if (!record_synch_enabled)  record_synch_count = 0;
+  record_synch_enabled = true;
+}
+
+void record_synch_disable() {
+  // stop collecting trace data
+  record_synch_enabled = false;
+}
+
+#endif // INTERPOSE_ON_SYSTEM_SYNCH_FUNCTIONS
+#endif // PRODUCT
+
+const intptr_t thr_time_off  = (intptr_t)(&((prusage_t *)(NULL))->pr_utime);
+const intptr_t thr_time_size = (intptr_t)(&((prusage_t *)(NULL))->pr_ttime) -
+                               (intptr_t)(&((prusage_t *)(NULL))->pr_utime);
+
+
+// JVMTI & JVM monitoring and management support
+// The thread_cpu_time() and current_thread_cpu_time() are only
+// supported if is_thread_cpu_time_supported() returns true.
+// They are not supported on Solaris T1.
+
+// current_thread_cpu_time(bool) and thread_cpu_time(Thread*, bool)
+// are used by JVM M&M and JVMTI to get user+sys or user CPU time
+// of a thread.
+//
+// current_thread_cpu_time() and thread_cpu_time(Thread *)
+// returns the fast estimate available on the platform.
+
+// hrtime_t gethrvtime() return value includes
+// user time but does not include system time
+jlong os::current_thread_cpu_time() {
+  return (jlong) gethrvtime();
+}
+
+jlong os::thread_cpu_time(Thread *thread) {
+  // return user level CPU time only to be consistent with
+  // what current_thread_cpu_time returns.
+  // thread_cpu_time_info() must be changed if this changes
+  return os::thread_cpu_time(thread, false /* user time only */);
+}
+
+jlong os::current_thread_cpu_time(bool user_sys_cpu_time) {
+  if (user_sys_cpu_time) {
+    return os::thread_cpu_time(Thread::current(), user_sys_cpu_time);
+  } else {
+    return os::current_thread_cpu_time();
+  }
+}
+
+jlong os::thread_cpu_time(Thread *thread, bool user_sys_cpu_time) {
+  char proc_name[64];
+  int count;
+  prusage_t prusage;
+  jlong lwp_time;
+  int fd;
+
+  sprintf(proc_name, "/proc/%d/lwp/%d/lwpusage",
+          getpid(),
+          thread->osthread()->lwp_id());
+  fd = ::open(proc_name, O_RDONLY);
+  if (fd == -1) return -1;
+
+  do {
+    count = ::pread(fd,
+                    (void *)&prusage.pr_utime,
+                    thr_time_size,
+                    thr_time_off);
+  } while (count < 0 && errno == EINTR);
+  ::close(fd);
+  if (count < 0) return -1;
+
+  if (user_sys_cpu_time) {
+    // user + system CPU time
+    lwp_time = (((jlong)prusage.pr_stime.tv_sec +
+                 (jlong)prusage.pr_utime.tv_sec) * (jlong)1000000000) +
+                 (jlong)prusage.pr_stime.tv_nsec +
+                 (jlong)prusage.pr_utime.tv_nsec;
+  } else {
+    // user level CPU time only
+    lwp_time = ((jlong)prusage.pr_utime.tv_sec * (jlong)1000000000) +
+                (jlong)prusage.pr_utime.tv_nsec;
+  }
+
+  return (lwp_time);
+}
+
+void os::current_thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
+  info_ptr->max_value = ALL_64_BITS;      // will not wrap in less than 64 bits
+  info_ptr->may_skip_backward = false;    // elapsed time not wall time
+  info_ptr->may_skip_forward = false;     // elapsed time not wall time
+  info_ptr->kind = JVMTI_TIMER_USER_CPU;  // only user time is returned
+}
+
+void os::thread_cpu_time_info(jvmtiTimerInfo *info_ptr) {
+  info_ptr->max_value = ALL_64_BITS;      // will not wrap in less than 64 bits
+  info_ptr->may_skip_backward = false;    // elapsed time not wall time
+  info_ptr->may_skip_forward = false;     // elapsed time not wall time
+  info_ptr->kind = JVMTI_TIMER_USER_CPU;  // only user time is returned
+}
+
+bool os::is_thread_cpu_time_supported() {
+  return true;
+}
+
+// System loadavg support.  Returns -1 if load average cannot be obtained.
+// Return the load average for our processor set if the primitive exists
+// (Solaris 9 and later).  Otherwise just return system wide loadavg.
+int os::loadavg(double loadavg[], int nelem) {
+  if (pset_getloadavg_ptr != NULL) {
+    return (*pset_getloadavg_ptr)(PS_MYID, loadavg, nelem);
+  } else {
+    return ::getloadavg(loadavg, nelem);
+  }
+}
+
+//---------------------------------------------------------------------------------
+
+bool os::find(address addr, outputStream* st) {
+  Dl_info dlinfo;
+  memset(&dlinfo, 0, sizeof(dlinfo));
+  if (dladdr(addr, &dlinfo) != 0) {
+    st->print(PTR_FORMAT ": ", p2i(addr));
+    if (dlinfo.dli_sname != NULL && dlinfo.dli_saddr != NULL) {
+      st->print("%s+" PTR_FORMAT, dlinfo.dli_sname,
+                p2i(addr) - p2i(dlinfo.dli_saddr));
+    } else if (dlinfo.dli_fbase != NULL) {
+      st->print("<offset " PTR_FORMAT ">", p2i(addr) - p2i(dlinfo.dli_fbase));
+    } else {
+      st->print("<absolute address>");
+    }
+    if (dlinfo.dli_fname != NULL) {
+      st->print(" in %s", dlinfo.dli_fname);
+    }
+    if (dlinfo.dli_fbase != NULL) {
+      st->print(" at " PTR_FORMAT, p2i(dlinfo.dli_fbase));
+    }
+    st->cr();
+
+    if (Verbose) {
+      // decode some bytes around the PC
+      address begin = clamp_address_in_page(addr-40, addr, os::vm_page_size());
+      address end   = clamp_address_in_page(addr+40, addr, os::vm_page_size());
+      address       lowest = (address) dlinfo.dli_sname;
+      if (!lowest)  lowest = (address) dlinfo.dli_fbase;
+      if (begin < lowest)  begin = lowest;
+      Dl_info dlinfo2;
+      if (dladdr(end, &dlinfo2) != 0 && dlinfo2.dli_saddr != dlinfo.dli_saddr
+          && end > dlinfo2.dli_saddr && dlinfo2.dli_saddr > begin) {
+        end = (address) dlinfo2.dli_saddr;
+      }
+      Disassembler::decode(begin, end, st);
+    }
+    return true;
+  }
+  return false;
+}
+
+// Following function has been added to support HotSparc's libjvm.so running
+// under Solaris production JDK 1.2.2 / 1.3.0.  These came from
+// src/solaris/hpi/native_threads in the EVM codebase.
+//
+// NOTE: This is no longer needed in the 1.3.1 and 1.4 production release
+// libraries and should thus be removed. We will leave it behind for a while
+// until we no longer want to able to run on top of 1.3.0 Solaris production
+// JDK. See 4341971.
+
+#define STACK_SLACK 0x800
+
+extern "C" {
+  intptr_t sysThreadAvailableStackWithSlack() {
+    stack_t st;
+    intptr_t retval, stack_top;
+    retval = thr_stksegment(&st);
+    assert(retval == 0, "incorrect return value from thr_stksegment");
+    assert((address)&st < (address)st.ss_sp, "Invalid stack base returned");
+    assert((address)&st > (address)st.ss_sp-st.ss_size, "Invalid stack size returned");
+    stack_top=(intptr_t)st.ss_sp-st.ss_size;
+    return ((intptr_t)&stack_top - stack_top - STACK_SLACK);
+  }
+}
+
+// ObjectMonitor park-unpark infrastructure ...
+//
+// We implement Solaris and Linux PlatformEvents with the
+// obvious condvar-mutex-flag triple.
+// Another alternative that works quite well is pipes:
+// Each PlatformEvent consists of a pipe-pair.
+// The thread associated with the PlatformEvent
+// calls park(), which reads from the input end of the pipe.
+// Unpark() writes into the other end of the pipe.
+// The write-side of the pipe must be set NDELAY.
+// Unfortunately pipes consume a large # of handles.
+// Native solaris lwp_park() and lwp_unpark() work nicely, too.
+// Using pipes for the 1st few threads might be workable, however.
+//
+// park() is permitted to return spuriously.
+// Callers of park() should wrap the call to park() in
+// an appropriate loop.  A litmus test for the correct
+// usage of park is the following: if park() were modified
+// to immediately return 0 your code should still work,
+// albeit degenerating to a spin loop.
+//
+// In a sense, park()-unpark() just provides more polite spinning
+// and polling with the key difference over naive spinning being
+// that a parked thread needs to be explicitly unparked() in order
+// to wake up and to poll the underlying condition.
+//
+// Assumption:
+//    Only one parker can exist on an event, which is why we allocate
+//    them per-thread. Multiple unparkers can coexist.
+//
+// _Event transitions in park()
+//   -1 => -1 : illegal
+//    1 =>  0 : pass - return immediately
+//    0 => -1 : block; then set _Event to 0 before returning
+//
+// _Event transitions in unpark()
+//    0 => 1 : just return
+//    1 => 1 : just return
+//   -1 => either 0 or 1; must signal target thread
+//         That is, we can safely transition _Event from -1 to either
+//         0 or 1.
+//
+// _Event serves as a restricted-range semaphore.
+//   -1 : thread is blocked, i.e. there is a waiter
+//    0 : neutral: thread is running or ready,
+//        could have been signaled after a wait started
+//    1 : signaled - thread is running or ready
+//
+// Another possible encoding of _Event would be with
+// explicit "PARKED" == 01b and "SIGNALED" == 10b bits.
+//
+// TODO-FIXME: add DTRACE probes for:
+// 1.   Tx parks
+// 2.   Ty unparks Tx
+// 3.   Tx resumes from park
+
+
+// value determined through experimentation
+#define ROUNDINGFIX 11
+
+// utility to compute the abstime argument to timedwait.
+// TODO-FIXME: switch from compute_abstime() to unpackTime().
+
+static timestruc_t* compute_abstime(timestruc_t* abstime, jlong millis) {
+  // millis is the relative timeout time
+  // abstime will be the absolute timeout time
+  if (millis < 0)  millis = 0;
+  struct timeval now;
+  int status = gettimeofday(&now, NULL);
+  assert(status == 0, "gettimeofday");
+  jlong seconds = millis / 1000;
+  jlong max_wait_period;
+
+  if (UseLWPSynchronization) {
+    // forward port of fix for 4275818 (not sleeping long enough)
+    // There was a bug in Solaris 6, 7 and pre-patch 5 of 8 where
+    // _lwp_cond_timedwait() used a round_down algorithm rather
+    // than a round_up. For millis less than our roundfactor
+    // it rounded down to 0 which doesn't meet the spec.
+    // For millis > roundfactor we may return a bit sooner, but
+    // since we can not accurately identify the patch level and
+    // this has already been fixed in Solaris 9 and 8 we will
+    // leave it alone rather than always rounding down.
+
+    if (millis > 0 && millis < ROUNDINGFIX) millis = ROUNDINGFIX;
+    // It appears that when we go directly through Solaris _lwp_cond_timedwait()
+    // the acceptable max time threshold is smaller than for libthread on 2.5.1 and 2.6
+    max_wait_period = 21000000;
+  } else {
+    max_wait_period = 50000000;
+  }
+  millis %= 1000;
+  if (seconds > max_wait_period) {      // see man cond_timedwait(3T)
+    seconds = max_wait_period;
+  }
+  abstime->tv_sec = now.tv_sec  + seconds;
+  long       usec = now.tv_usec + millis * 1000;
+  if (usec >= 1000000) {
+    abstime->tv_sec += 1;
+    usec -= 1000000;
+  }
+  abstime->tv_nsec = usec * 1000;
+  return abstime;
+}
+
+void os::PlatformEvent::park() {           // AKA: down()
+  // Transitions for _Event:
+  //   -1 => -1 : illegal
+  //    1 =>  0 : pass - return immediately
+  //    0 => -1 : block; then set _Event to 0 before returning
+
+  // Invariant: Only the thread associated with the Event/PlatformEvent
+  // may call park().
+  assert(_nParked == 0, "invariant");
+
+  int v;
+  for (;;) {
+    v = _Event;
+    if (Atomic::cmpxchg(&_Event, v, v-1) == v) break;
+  }
+  guarantee(v >= 0, "invariant");
+  if (v == 0) {
+    // Do this the hard way by blocking ...
+    // See http://monaco.sfbay/detail.jsf?cr=5094058.
+    int status = os::Solaris::mutex_lock(_mutex);
+    assert_status(status == 0, status, "mutex_lock");
+    guarantee(_nParked == 0, "invariant");
+    ++_nParked;
+    while (_Event < 0) {
+      // for some reason, under 2.7 lwp_cond_wait() may return ETIME ...
+      // Treat this the same as if the wait was interrupted
+      // With usr/lib/lwp going to kernel, always handle ETIME
+      status = os::Solaris::cond_wait(_cond, _mutex);
+      if (status == ETIME) status = EINTR;
+      assert_status(status == 0 || status == EINTR, status, "cond_wait");
+    }
+    --_nParked;
+    _Event = 0;
+    status = os::Solaris::mutex_unlock(_mutex);
+    assert_status(status == 0, status, "mutex_unlock");
+    // Paranoia to ensure our locked and lock-free paths interact
+    // correctly with each other.
+    OrderAccess::fence();
+  }
+}
+
+int os::PlatformEvent::park(jlong millis) {
+  // Transitions for _Event:
+  //   -1 => -1 : illegal
+  //    1 =>  0 : pass - return immediately
+  //    0 => -1 : block; then set _Event to 0 before returning
+
+  guarantee(_nParked == 0, "invariant");
+  int v;
+  for (;;) {
+    v = _Event;
+    if (Atomic::cmpxchg(&_Event, v, v-1) == v) break;
+  }
+  guarantee(v >= 0, "invariant");
+  if (v != 0) return OS_OK;
+
+  int ret = OS_TIMEOUT;
+  timestruc_t abst;
+  compute_abstime(&abst, millis);
+
+  // See http://monaco.sfbay/detail.jsf?cr=5094058.
+  int status = os::Solaris::mutex_lock(_mutex);
+  assert_status(status == 0, status, "mutex_lock");
+  guarantee(_nParked == 0, "invariant");
+  ++_nParked;
+  while (_Event < 0) {
+    int status = os::Solaris::cond_timedwait(_cond, _mutex, &abst);
+    assert_status(status == 0 || status == EINTR ||
+                  status == ETIME || status == ETIMEDOUT,
+                  status, "cond_timedwait");
+    if (!FilterSpuriousWakeups) break;                // previous semantics
+    if (status == ETIME || status == ETIMEDOUT) break;
+    // We consume and ignore EINTR and spurious wakeups.
+  }
+  --_nParked;
+  if (_Event >= 0) ret = OS_OK;
+  _Event = 0;
+  status = os::Solaris::mutex_unlock(_mutex);
+  assert_status(status == 0, status, "mutex_unlock");
+  // Paranoia to ensure our locked and lock-free paths interact
+  // correctly with each other.
+  OrderAccess::fence();
+  return ret;
+}
+
+void os::PlatformEvent::unpark() {
+  // Transitions for _Event:
+  //    0 => 1 : just return
+  //    1 => 1 : just return
+  //   -1 => either 0 or 1; must signal target thread
+  //         That is, we can safely transition _Event from -1 to either
+  //         0 or 1.
+  // See also: "Semaphores in Plan 9" by Mullender & Cox
+  //
+  // Note: Forcing a transition from "-1" to "1" on an unpark() means
+  // that it will take two back-to-back park() calls for the owning
+  // thread to block. This has the benefit of forcing a spurious return
+  // from the first park() call after an unpark() call which will help
+  // shake out uses of park() and unpark() without condition variables.
+
+  if (Atomic::xchg(&_Event, 1) >= 0) return;
+
+  // If the thread associated with the event was parked, wake it.
+  // Wait for the thread assoc with the PlatformEvent to vacate.
+  int status = os::Solaris::mutex_lock(_mutex);
+  assert_status(status == 0, status, "mutex_lock");
+  int AnyWaiters = _nParked;
+  status = os::Solaris::mutex_unlock(_mutex);
+  assert_status(status == 0, status, "mutex_unlock");
+  guarantee(AnyWaiters == 0 || AnyWaiters == 1, "invariant");
+  if (AnyWaiters != 0) {
+    // Note that we signal() *after* dropping the lock for "immortal" Events.
+    // This is safe and avoids a common class of  futile wakeups.  In rare
+    // circumstances this can cause a thread to return prematurely from
+    // cond_{timed}wait() but the spurious wakeup is benign and the victim
+    // will simply re-test the condition and re-park itself.
+    // This provides particular benefit if the underlying platform does not
+    // provide wait morphing.
+    status = os::Solaris::cond_signal(_cond);
+    assert_status(status == 0, status, "cond_signal");
+  }
+}
+
+// JSR166
+// -------------------------------------------------------
+
+os::PlatformParker::PlatformParker() : _counter(0) {
+  int status;
+  status = os::Solaris::cond_init(_cond);
+  assert_status(status == 0, status, "cond_init");
+  status = os::Solaris::mutex_init(_mutex);
+  assert_status(status == 0, status, "mutex_init");
+}
+
+os::PlatformParker::~PlatformParker() {
+  int status;
+  status = os::Solaris::cond_destroy(_cond);
+  assert_status(status == 0, status, "cond_destroy");
+  status = os::Solaris::mutex_destroy(_mutex);
+  assert_status(status == 0, status, "mutex_destroy");
+}
+
+// The solaris and linux implementations of park/unpark are fairly
+// conservative for now, but can be improved. They currently use a
+// mutex/condvar pair, plus _counter.
+// Park decrements _counter if > 0, else does a condvar wait.  Unpark
+// sets count to 1 and signals condvar.  Only one thread ever waits
+// on the condvar. Contention seen when trying to park implies that someone
+// is unparking you, so don't wait. And spurious returns are fine, so there
+// is no need to track notifications.
+
+#define MAX_SECS 100000000
+
+// This code is common to linux and solaris and will be moved to a
+// common place in dolphin.
+//
+// The passed in time value is either a relative time in nanoseconds
+// or an absolute time in milliseconds. Either way it has to be unpacked
+// into suitable seconds and nanoseconds components and stored in the
+// given timespec structure.
+// Given time is a 64-bit value and the time_t used in the timespec is only
+// a signed-32-bit value (except on 64-bit Linux) we have to watch for
+// overflow if times way in the future are given. Further on Solaris versions
+// prior to 10 there is a restriction (see cond_timedwait) that the specified
+// number of seconds, in abstime, is less than current_time  + 100,000,000.
+// As it will be 28 years before "now + 100000000" will overflow we can
+// ignore overflow and just impose a hard-limit on seconds using the value
+// of "now + 100,000,000". This places a limit on the timeout of about 3.17
+// years from "now".
+//
+static void unpackTime(timespec* absTime, bool isAbsolute, jlong time) {
+  assert(time > 0, "convertTime");
+
+  struct timeval now;
+  int status = gettimeofday(&now, NULL);
+  assert(status == 0, "gettimeofday");
+
+  time_t max_secs = now.tv_sec + MAX_SECS;
+
+  if (isAbsolute) {
+    jlong secs = time / 1000;
+    if (secs > max_secs) {
+      absTime->tv_sec = max_secs;
+    } else {
+      absTime->tv_sec = secs;
+    }
+    absTime->tv_nsec = (time % 1000) * NANOSECS_PER_MILLISEC;
+  } else {
+    jlong secs = time / NANOSECS_PER_SEC;
+    if (secs >= MAX_SECS) {
+      absTime->tv_sec = max_secs;
+      absTime->tv_nsec = 0;
+    } else {
+      absTime->tv_sec = now.tv_sec + secs;
+      absTime->tv_nsec = (time % NANOSECS_PER_SEC) + now.tv_usec*1000;
+      if (absTime->tv_nsec >= NANOSECS_PER_SEC) {
+        absTime->tv_nsec -= NANOSECS_PER_SEC;
+        ++absTime->tv_sec; // note: this must be <= max_secs
+      }
+    }
+  }
+  assert(absTime->tv_sec >= 0, "tv_sec < 0");
+  assert(absTime->tv_sec <= max_secs, "tv_sec > max_secs");
+  assert(absTime->tv_nsec >= 0, "tv_nsec < 0");
+  assert(absTime->tv_nsec < NANOSECS_PER_SEC, "tv_nsec >= nanos_per_sec");
+}
+
+void Parker::park(bool isAbsolute, jlong time) {
+  // Ideally we'd do something useful while spinning, such
+  // as calling unpackTime().
+
+  // Optional fast-path check:
+  // Return immediately if a permit is available.
+  // We depend on Atomic::xchg() having full barrier semantics
+  // since we are doing a lock-free update to _counter.
+  if (Atomic::xchg(&_counter, 0) > 0) return;
+
+  // Optional fast-exit: Check interrupt before trying to wait
+  Thread* thread = Thread::current();
+  assert(thread->is_Java_thread(), "Must be JavaThread");
+  JavaThread *jt = (JavaThread *)thread;
+  if (jt->is_interrupted(false)) {
+    return;
+  }
+
+  // First, demultiplex/decode time arguments
+  timespec absTime;
+  if (time < 0 || (isAbsolute && time == 0)) { // don't wait at all
+    return;
+  }
+  if (time > 0) {
+    // Warning: this code might be exposed to the old Solaris time
+    // round-down bugs.  Grep "roundingFix" for details.
+    unpackTime(&absTime, isAbsolute, time);
+  }
+
+  // Enter safepoint region
+  // Beware of deadlocks such as 6317397.
+  // The per-thread Parker:: _mutex is a classic leaf-lock.
+  // In particular a thread must never block on the Threads_lock while
+  // holding the Parker:: mutex.  If safepoints are pending both the
+  // the ThreadBlockInVM() CTOR and DTOR may grab Threads_lock.
+  ThreadBlockInVM tbivm(jt);
+
+  // Can't access interrupt state now that we are _thread_blocked. If we've
+  // been interrupted since we checked above then _counter will be > 0.
+
+  // Don't wait if cannot get lock since interference arises from
+  // unblocking.
+  if (os::Solaris::mutex_trylock(_mutex) != 0) {
+    return;
+  }
+
+  int status;
+
+  if (_counter > 0)  { // no wait needed
+    _counter = 0;
+    status = os::Solaris::mutex_unlock(_mutex);
+    assert(status == 0, "invariant");
+    // Paranoia to ensure our locked and lock-free paths interact
+    // correctly with each other and Java-level accesses.
+    OrderAccess::fence();
+    return;
+  }
+
+  OSThreadWaitState osts(thread->osthread(), false /* not Object.wait() */);
+
+  // Do this the hard way by blocking ...
+  // See http://monaco.sfbay/detail.jsf?cr=5094058.
+  if (time == 0) {
+    status = os::Solaris::cond_wait(_cond, _mutex);
+  } else {
+    status = os::Solaris::cond_timedwait (_cond, _mutex, &absTime);
+  }
+  // Note that an untimed cond_wait() can sometimes return ETIME on older
+  // versions of the Solaris.
+  assert_status(status == 0 || status == EINTR ||
+                status == ETIME || status == ETIMEDOUT,
+                status, "cond_timedwait");
+
+  _counter = 0;
+  status = os::Solaris::mutex_unlock(_mutex);
+  assert_status(status == 0, status, "mutex_unlock");
+  // Paranoia to ensure our locked and lock-free paths interact
+  // correctly with each other and Java-level accesses.
+  OrderAccess::fence();
+}
+
+void Parker::unpark() {
+  int status = os::Solaris::mutex_lock(_mutex);
+  assert(status == 0, "invariant");
+  const int s = _counter;
+  _counter = 1;
+  status = os::Solaris::mutex_unlock(_mutex);
+  assert(status == 0, "invariant");
+
+  if (s < 1) {
+    status = os::Solaris::cond_signal(_cond);
+    assert(status == 0, "invariant");
+  }
+}
+
+// Platform Mutex/Monitor implementations
+
+os::PlatformMutex::PlatformMutex() {
+  int status = os::Solaris::mutex_init(&_mutex);
+  assert_status(status == 0, status, "mutex_init");
+}
+
+os::PlatformMutex::~PlatformMutex() {
+  int status = os::Solaris::mutex_destroy(&_mutex);
+  assert_status(status == 0, status, "mutex_destroy");
+}
+
+void os::PlatformMutex::lock() {
+  int status = os::Solaris::mutex_lock(&_mutex);
+  assert_status(status == 0, status, "mutex_lock");
+}
+
+void os::PlatformMutex::unlock() {
+  int status = os::Solaris::mutex_unlock(&_mutex);
+  assert_status(status == 0, status, "mutex_unlock");
+}
+
+bool os::PlatformMutex::try_lock() {
+  int status = os::Solaris::mutex_trylock(&_mutex);
+  assert_status(status == 0 || status == EBUSY, status, "mutex_trylock");
+  return status == 0;
+}
+
+os::PlatformMonitor::PlatformMonitor() {
+  int status = os::Solaris::cond_init(&_cond);
+  assert_status(status == 0, status, "cond_init");
+}
+
+os::PlatformMonitor::~PlatformMonitor() {
+  int status = os::Solaris::cond_destroy(&_cond);
+  assert_status(status == 0, status, "cond_destroy");
+}
+
+// Must already be locked
+int os::PlatformMonitor::wait(jlong millis) {
+  assert(millis >= 0, "negative timeout");
+  if (millis > 0) {
+    timestruc_t abst;
+    int ret = OS_TIMEOUT;
+    compute_abstime(&abst, millis);
+    int status = os::Solaris::cond_timedwait(&_cond, &_mutex, &abst);
+    assert_status(status == 0 || status == EINTR ||
+                  status == ETIME || status == ETIMEDOUT,
+                  status, "cond_timedwait");
+    // EINTR acts as spurious wakeup - which is permitted anyway
+    if (status == 0 || status == EINTR) {
+      ret = OS_OK;
+    }
+    return ret;
+  } else {
+    int status = os::Solaris::cond_wait(&_cond, &_mutex);
+    assert_status(status == 0 || status == EINTR,
+                  status, "cond_wait");
+    return OS_OK;
+  }
+}
+
+void os::PlatformMonitor::notify() {
+  int status = os::Solaris::cond_signal(&_cond);
+  assert_status(status == 0, status, "cond_signal");
+}
+
+void os::PlatformMonitor::notify_all() {
+  int status = os::Solaris::cond_broadcast(&_cond);
+  assert_status(status == 0, status, "cond_broadcast");
+}
+
+// Get the default path to the core file
+// Returns the length of the string
+int os::get_core_path(char* buffer, size_t bufferSize) {
+  const char* p = get_current_directory(buffer, bufferSize);
+
+  if (p == NULL) {
+    assert(p != NULL, "failed to get current directory");
+    return 0;
+  }
+
+  jio_snprintf(buffer, bufferSize, "%s/core or core.%d",
+                                              p, current_process_id());
+
+  return strlen(buffer);
+}
+
+bool os::supports_map_sync() {
+  return false;
+}
+
+#ifndef PRODUCT
+void TestReserveMemorySpecial_test() {
+  // No tests available for this platform
+}
+#endif
+
+bool os::start_debugging(char *buf, int buflen) {
+  int len = (int)strlen(buf);
+  char *p = &buf[len];
+
+  jio_snprintf(p, buflen-len,
+               "\n\n"
+               "Do you want to debug the problem?\n\n"
+               "To debug, run 'dbx - %d'; then switch to thread " INTX_FORMAT "\n"
+               "Enter 'yes' to launch dbx automatically (PATH must include dbx)\n"
+               "Otherwise, press RETURN to abort...",
+               os::current_process_id(), os::current_thread_id());
+
+  bool yes = os::message_box("Unexpected Error", buf);
+
+  if (yes) {
+    // yes, user asked VM to launch debugger
+    jio_snprintf(buf, sizeof(buf), "dbx - %d", os::current_process_id());
+
+    os::fork_and_exec(buf);
+    yes = false;
+  }
+  return yes;
+}
+
+void os::print_memory_mappings(char* addr, size_t bytes, outputStream* st) {}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_solaris.hpp	2024-08-17 18:29:44.545309864 +0200
@@ -0,0 +1,322 @@
+/*
+ * Copyright (c) 1997, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_OS_SOLARIS_HPP
+#define OS_SOLARIS_OS_SOLARIS_HPP
+
+// Solaris_OS defines the interface to Solaris operating systems
+
+// see thr_setprio(3T) for the basis of these numbers
+#define MinimumPriority 0
+#define NormalPriority  64
+#define MaximumPriority 127
+
+// FX/60 is critical thread class/priority on T4
+#define FXCriticalPriority 60
+
+// Information about the protection of the page at address '0' on this os.
+static bool zero_page_read_protected() { return true; }
+
+class Solaris {
+  friend class os;
+
+ private:
+
+  // Support for "new" libthread APIs for getting & setting thread context (2.8)
+#define TRS_VALID       0
+#define TRS_NONVOLATILE 1
+#define TRS_LWPID       2
+#define TRS_INVALID     3
+
+  // initialized to libthread or lwp synchronization primitives depending on UseLWPSychronization
+  static int_fnP_mutex_tP _mutex_lock;
+  static int_fnP_mutex_tP _mutex_trylock;
+  static int_fnP_mutex_tP _mutex_unlock;
+  static int_fnP_mutex_tP_i_vP _mutex_init;
+  static int_fnP_mutex_tP _mutex_destroy;
+  static int _mutex_scope;
+
+  static int_fnP_cond_tP_mutex_tP_timestruc_tP _cond_timedwait;
+  static int_fnP_cond_tP_mutex_tP _cond_wait;
+  static int_fnP_cond_tP _cond_signal;
+  static int_fnP_cond_tP _cond_broadcast;
+  static int_fnP_cond_tP_i_vP _cond_init;
+  static int_fnP_cond_tP _cond_destroy;
+  static int _cond_scope;
+
+  static bool _synchronization_initialized;
+
+  typedef uintptr_t       lgrp_cookie_t;
+  typedef id_t            lgrp_id_t;
+  typedef int             lgrp_rsrc_t;
+  typedef enum lgrp_view {
+    LGRP_VIEW_CALLER,       // what's available to the caller
+    LGRP_VIEW_OS            // what's available to operating system
+  } lgrp_view_t;
+
+  typedef lgrp_id_t (*lgrp_home_func_t)(idtype_t idtype, id_t id);
+  typedef lgrp_cookie_t (*lgrp_init_func_t)(lgrp_view_t view);
+  typedef int (*lgrp_fini_func_t)(lgrp_cookie_t cookie);
+  typedef lgrp_id_t (*lgrp_root_func_t)(lgrp_cookie_t cookie);
+  typedef int (*lgrp_children_func_t)(lgrp_cookie_t  cookie,  lgrp_id_t  parent,
+                                      lgrp_id_t *lgrp_array, uint_t lgrp_array_size);
+  typedef int (*lgrp_resources_func_t)(lgrp_cookie_t  cookie,  lgrp_id_t  lgrp,
+                                       lgrp_id_t *lgrp_array, uint_t lgrp_array_size,
+                                       lgrp_rsrc_t type);
+  typedef int (*lgrp_nlgrps_func_t)(lgrp_cookie_t cookie);
+  typedef int (*lgrp_cookie_stale_func_t)(lgrp_cookie_t cookie);
+
+  static lgrp_home_func_t _lgrp_home;
+  static lgrp_init_func_t _lgrp_init;
+  static lgrp_fini_func_t _lgrp_fini;
+  static lgrp_root_func_t _lgrp_root;
+  static lgrp_children_func_t _lgrp_children;
+  static lgrp_resources_func_t _lgrp_resources;
+  static lgrp_nlgrps_func_t _lgrp_nlgrps;
+  static lgrp_cookie_stale_func_t _lgrp_cookie_stale;
+  static lgrp_cookie_t _lgrp_cookie;
+
+  // Large Page Support
+  static bool is_valid_page_size(size_t bytes);
+  static size_t page_size_for_alignment(size_t alignment);
+  static bool setup_large_pages(caddr_t start, size_t bytes, size_t align);
+
+  typedef int (*pthread_setname_np_func_t)(pthread_t, const char*);
+  static pthread_setname_np_func_t _pthread_setname_np;
+
+ public:
+  // Large Page Support--ISM.
+  static bool largepage_range(char* addr, size_t size);
+
+  static address handler_start, handler_end; // start and end pc of thr_sighndlrinfo
+
+  static bool valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect);
+  static const ucontext_t* get_valid_uc_in_signal_handler(Thread* thread,
+                                                    const ucontext_t* uc);
+
+  static intptr_t*   ucontext_get_sp(const ucontext_t* uc);
+  // ucontext_get_fp() is only used by Solaris X86 (see note below)
+  static intptr_t*   ucontext_get_fp(const ucontext_t* uc);
+
+  static bool get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr);
+
+  static void init_thread_fpu_state(void);
+
+ protected:
+  static int _page_size;
+  // Solaris-specific interface goes here
+  static julong available_memory();
+  static julong physical_memory() { return _physical_memory; }
+  static julong _physical_memory;
+  static void initialize_system_info();
+  static int _dev_zero_fd;
+  static int get_dev_zero_fd() { return _dev_zero_fd; }
+  static void set_dev_zero_fd(int fd) { _dev_zero_fd = fd; }
+  static int commit_memory_impl(char* addr, size_t bytes, bool exec);
+  static int commit_memory_impl(char* addr, size_t bytes,
+                                size_t alignment_hint, bool exec);
+  static char* mmap_chunk(char *addr, size_t size, int flags, int prot);
+  static char* anon_mmap(char* requested_addr, size_t bytes);
+  static bool mpss_sanity_check(bool warn, size_t * page_size);
+
+  // Workaround for 4352906. thr_stksegment sometimes returns
+  // a bad value for the primordial thread's stack base when
+  // it is called more than one time.
+  // Workaround is to cache the initial value to avoid further
+  // calls to thr_stksegment.
+  // It appears that someone (Hotspot?) is trashing the user's
+  // proc_t structure (note that this is a system struct).
+  static address _main_stack_base;
+
+  static void print_distro_info(outputStream* st);
+  static void print_libversion_info(outputStream* st);
+
+ public:
+  static int page_size(void)                                        { return _page_size; }
+  static void set_page_size(int val)                                { _page_size = val; }
+
+  static void libthread_init();
+  static void synchronization_init();
+  static bool liblgrp_init();
+
+  static void init_signal_mem();
+
+  // Allows us to switch between lwp and thread -based synchronization
+  static int mutex_lock(mutex_t *mx)    { return _mutex_lock(mx); }
+  static int mutex_trylock(mutex_t *mx) { return _mutex_trylock(mx); }
+  static int mutex_unlock(mutex_t *mx)  { return _mutex_unlock(mx); }
+  static int mutex_init(mutex_t *mx)    { return _mutex_init(mx, os::Solaris::mutex_scope(), NULL); }
+  static int mutex_destroy(mutex_t *mx) { return _mutex_destroy(mx); }
+  static int mutex_scope()              { return _mutex_scope; }
+
+  static void set_mutex_lock(int_fnP_mutex_tP func)      { _mutex_lock = func; }
+  static void set_mutex_trylock(int_fnP_mutex_tP func)   { _mutex_trylock = func; }
+  static void set_mutex_unlock(int_fnP_mutex_tP func)    { _mutex_unlock = func; }
+  static void set_mutex_init(int_fnP_mutex_tP_i_vP func) { _mutex_init = func; }
+  static void set_mutex_destroy(int_fnP_mutex_tP func)   { _mutex_destroy = func; }
+  static void set_mutex_scope(int scope)                 { _mutex_scope = scope; }
+
+  static int cond_timedwait(cond_t *cv, mutex_t *mx, timestruc_t *abst) { return _cond_timedwait(cv, mx, abst); }
+  static int cond_wait(cond_t *cv, mutex_t *mx) { return _cond_wait(cv, mx); }
+  static int cond_signal(cond_t *cv)            { return _cond_signal(cv); }
+  static int cond_broadcast(cond_t *cv)         { return _cond_broadcast(cv); }
+  static int cond_init(cond_t *cv)              { return _cond_init(cv, os::Solaris::cond_scope(), NULL); }
+  static int cond_destroy(cond_t *cv)           { return _cond_destroy(cv); }
+  static int cond_scope()                       { return _cond_scope; }
+
+  static void set_cond_timedwait(int_fnP_cond_tP_mutex_tP_timestruc_tP func) { _cond_timedwait = func; }
+  static void set_cond_wait(int_fnP_cond_tP_mutex_tP func) { _cond_wait = func; }
+  static void set_cond_signal(int_fnP_cond_tP func)        { _cond_signal = func; }
+  static void set_cond_broadcast(int_fnP_cond_tP func)     { _cond_broadcast = func; }
+  static void set_cond_init(int_fnP_cond_tP_i_vP func)     { _cond_init = func; }
+  static void set_cond_destroy(int_fnP_cond_tP func)       { _cond_destroy = func; }
+  static void set_cond_scope(int scope)                    { _cond_scope = scope; }
+
+  static bool synchronization_initialized()                { return _synchronization_initialized; }
+
+  static void set_lgrp_home(lgrp_home_func_t func) { _lgrp_home = func; }
+  static void set_lgrp_init(lgrp_init_func_t func) { _lgrp_init = func; }
+  static void set_lgrp_fini(lgrp_fini_func_t func) { _lgrp_fini = func; }
+  static void set_lgrp_root(lgrp_root_func_t func) { _lgrp_root = func; }
+  static void set_lgrp_children(lgrp_children_func_t func)   { _lgrp_children = func; }
+  static void set_lgrp_resources(lgrp_resources_func_t func) { _lgrp_resources = func; }
+  static void set_lgrp_nlgrps(lgrp_nlgrps_func_t func)       { _lgrp_nlgrps = func; }
+  static void set_lgrp_cookie_stale(lgrp_cookie_stale_func_t func) { _lgrp_cookie_stale = func; }
+  static void set_lgrp_cookie(lgrp_cookie_t cookie)  { _lgrp_cookie = cookie; }
+
+  static id_t lgrp_home(idtype_t type, id_t id)      { return _lgrp_home != NULL ? _lgrp_home(type, id) : -1; }
+  static lgrp_cookie_t lgrp_init(lgrp_view_t view)   { return _lgrp_init != NULL ? _lgrp_init(view) : 0; }
+  static int lgrp_fini(lgrp_cookie_t cookie)         { return _lgrp_fini != NULL ? _lgrp_fini(cookie) : -1; }
+  static lgrp_id_t lgrp_root(lgrp_cookie_t cookie)   { return _lgrp_root != NULL ? _lgrp_root(cookie) : -1; }
+  static int lgrp_children(lgrp_cookie_t  cookie,  lgrp_id_t  parent,
+                           lgrp_id_t *lgrp_array, uint_t lgrp_array_size) {
+    return _lgrp_children != NULL ? _lgrp_children(cookie, parent, lgrp_array, lgrp_array_size) : -1;
+  }
+  static int lgrp_resources(lgrp_cookie_t  cookie,  lgrp_id_t  lgrp,
+                            lgrp_id_t *lgrp_array, uint_t lgrp_array_size,
+                            lgrp_rsrc_t type) {
+    return _lgrp_resources != NULL ? _lgrp_resources(cookie, lgrp, lgrp_array, lgrp_array_size, type) : -1;
+  }
+
+  static int lgrp_nlgrps(lgrp_cookie_t cookie)       { return _lgrp_nlgrps != NULL ? _lgrp_nlgrps(cookie) : -1; }
+  static int lgrp_cookie_stale(lgrp_cookie_t cookie) {
+    return _lgrp_cookie_stale != NULL ? _lgrp_cookie_stale(cookie) : -1;
+  }
+  static lgrp_cookie_t lgrp_cookie()                 { return _lgrp_cookie; }
+
+  static sigset_t* unblocked_signals();
+  static sigset_t* vm_signals();
+
+  // %%% Following should be promoted to os.hpp:
+  // Trace number of created threads
+  static          jint  _os_thread_limit;
+  static volatile jint  _os_thread_count;
+
+  static void correct_stack_boundaries_for_primordial_thread(Thread* thr);
+
+  // Stack repair handling
+
+  // none present
+
+};
+
+class PlatformEvent : public CHeapObj<mtSynchronizer> {
+ private:
+  double CachePad[4];   // increase odds that _mutex is sole occupant of cache line
+  volatile int _Event;
+  int _nParked;
+  int _pipev[2];
+  mutex_t _mutex[1];
+  cond_t  _cond[1];
+  double PostPad[2];
+
+ protected:
+  // Defining a protected ctor effectively gives us an abstract base class.
+  // That is, a PlatformEvent can never be instantiated "naked" but only
+  // as a part of a ParkEvent (recall that ParkEvent extends PlatformEvent).
+  // TODO-FIXME: make dtor private
+  ~PlatformEvent() { guarantee(0, "invariant"); }
+  PlatformEvent() {
+    int status;
+    status = os::Solaris::cond_init(_cond);
+    assert_status(status == 0, status, "cond_init");
+    status = os::Solaris::mutex_init(_mutex);
+    assert_status(status == 0, status, "mutex_init");
+    _Event   = 0;
+    _nParked = 0;
+    _pipev[0] = _pipev[1] = -1;
+  }
+
+ public:
+  // Exercise caution using reset() and fired() -- they may require MEMBARs
+  void reset() { _Event = 0; }
+  int  fired() { return _Event; }
+  void park();
+  int  park(jlong millis);
+  void unpark();
+};
+
+class PlatformParker {
+  NONCOPYABLE(PlatformParker);
+ protected:
+  volatile int _counter;
+  mutex_t _mutex[1];
+  cond_t  _cond[1];
+
+ public:
+  PlatformParker();
+  ~PlatformParker();
+};
+
+// Platform specific implementations that underpin VM Mutex/Monitor classes
+
+class PlatformMutex : public CHeapObj<mtSynchronizer> {
+  NONCOPYABLE(PlatformMutex);
+
+ protected:
+  mutex_t _mutex; // Native mutex for locking
+
+ public:
+  PlatformMutex();
+  ~PlatformMutex();
+  void lock();
+  void unlock();
+  bool try_lock();
+};
+
+class PlatformMonitor : public PlatformMutex {
+ private:
+  cond_t  _cond;  // Native condition variable for blocking
+
+  NONCOPYABLE(PlatformMonitor);
+
+ public:
+  PlatformMonitor();
+  ~PlatformMonitor();
+  int wait(jlong millis);
+  void notify();
+  void notify_all();
+};
+
+#endif // OS_SOLARIS_OS_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_solaris.inline.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_solaris.inline.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/os_solaris.inline.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/os_solaris.inline.hpp	2024-08-17 18:29:44.545633288 +0200
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_OS_SOLARIS_INLINE_HPP
+#define OS_SOLARIS_OS_SOLARIS_INLINE_HPP
+
+#include "runtime/os.hpp"
+#include "os_posix.inline.hpp"
+
+// System includes
+#include <sys/param.h>
+#include <dlfcn.h>
+#include <sys/socket.h>
+#include <poll.h>
+#include <sys/filio.h>
+#include <unistd.h>
+#include <netdb.h>
+#include <setjmp.h>
+
+inline bool os::uses_stack_guard_pages() {
+  return true;
+}
+
+inline bool os::must_commit_stack_guard_pages() {
+  assert(uses_stack_guard_pages(), "sanity check");
+  int r = thr_main() ;
+  guarantee (r == 0 || r == 1, "CR6501650 or CR6493689") ;
+  return r;
+}
+
+
+// Bang the shadow pages if they need to be touched to be mapped.
+inline void os::map_stack_shadow_pages(address sp) {
+}
+
+//////////////////////////////////////////////////////////////////////////////
+////////////////////////////////////////////////////////////////////////////////
+
+inline bool os::numa_has_static_binding()   { return false; }
+inline bool os::numa_has_group_homing()     { return true;  }
+
+#endif // OS_SOLARIS_OS_SOLARIS_INLINE_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/osThread_solaris.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/osThread_solaris.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/osThread_solaris.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/osThread_solaris.cpp	2024-08-17 18:29:44.540444323 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 1998, 2014, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// no precompiled headers
+#include "runtime/handles.inline.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/os.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/safepoint.hpp"
+#include "runtime/vmThread.hpp"
+
+#include <signal.h>
+
+ // ***************************************************************
+ // Platform dependent initialization and cleanup
+ // ***************************************************************
+
+void OSThread::pd_initialize() {
+  _thread_id                         = 0;
+  sigemptyset(&_caller_sigmask);
+
+  _vm_created_thread                 = false;
+}
+
+void OSThread::pd_destroy() {
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/osThread_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/osThread_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/osThread_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/osThread_solaris.hpp	2024-08-17 18:29:44.540781454 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 1997, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_OSTHREAD_SOLARIS_HPP
+#define OS_SOLARIS_OSTHREAD_SOLARIS_HPP
+
+// This is embedded via include into the class OSThread
+ public:
+  typedef thread_t thread_id_t;
+
+ private:
+  uint     _lwp_id;            // lwp ID, only used with bound threads
+  int      _native_priority;   // Saved native priority when starting
+                               // a bound thread
+  sigset_t _caller_sigmask;    // Caller's signal mask
+  bool     _vm_created_thread; // true if the VM created this thread,
+                               // false if primary thread or attached thread
+ public:
+  uint     lwp_id() const          { return _lwp_id; }
+  int      native_priority() const { return _native_priority; }
+
+  // Set and get state of _vm_created_thread flag
+  void set_vm_created()           { _vm_created_thread = true; }
+  bool is_vm_created()            { return _vm_created_thread; }
+
+  // Methods to save/restore caller's signal mask
+  sigset_t  caller_sigmask() const       { return _caller_sigmask; }
+  void    set_caller_sigmask(sigset_t sigmask)  { _caller_sigmask = sigmask; }
+
+#ifndef PRODUCT
+  // Used for debugging, return a unique integer for each thread.
+  int thread_identifier() const   { return _thread_id; }
+#endif
+#ifdef ASSERT
+  // On solaris reposition can fail in two ways:
+  // 1: a mismatched pc, because signal is delivered too late, target thread
+  //    is resumed.
+  // 2: on a timeout where signal is lost, target thread is resumed.
+  bool valid_reposition_failure() {
+    // only 1 and 2 can happen and we can handle both of them
+    return true;
+  }
+#endif
+  void set_lwp_id(uint id)           { _lwp_id = id; }
+  void set_native_priority(int prio) { _native_priority = prio; }
+
+ public:
+  pthread_t pthread_id() const {
+    // Here: same as OSThread::thread_id()
+    return _thread_id;
+  }
+  os::SuspendResume sr;
+
+ private:
+  void* _siginfo;
+  ucontext_t* _ucontext;
+
+ public:
+  void set_siginfo(void* ptr)             { _siginfo = ptr;   }
+  ucontext_t* ucontext() const { return _ucontext; }
+  void set_ucontext(ucontext_t* ptr) { _ucontext = ptr; }
+
+  // ***************************************************************
+  // Platform dependent initialization and cleanup
+  // ***************************************************************
+
+private:
+
+  void pd_initialize();
+  void pd_destroy();
+
+#endif // OS_SOLARIS_OSTHREAD_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/threadCritical_solaris.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/threadCritical_solaris.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/threadCritical_solaris.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/threadCritical_solaris.cpp	2024-08-17 18:29:44.545950604 +0200
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2001, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/threadCritical.hpp"
+
+// OS-includes here
+#include <thread.h>
+#include <synch.h>
+
+//
+// See threadCritical.hpp for details of this class.
+//
+// For some reason, we don't do locking until the
+// os::init() call completes. I'm not sure why this
+// is, and have left it that way for now. This should
+// be reviewed later.
+
+static  mutex_t  global_mut;
+static  thread_t global_mut_owner = -1;
+static  int      global_mut_count = 0;
+
+ThreadCritical::ThreadCritical() {
+  if (os::Solaris::synchronization_initialized()) {
+    thread_t owner = thr_self();
+    if (global_mut_owner != owner) {
+      if (os::Solaris::mutex_lock(&global_mut))
+        fatal("ThreadCritical::ThreadCritical: mutex_lock failed (%s)",
+              os::strerror(errno));
+      assert(global_mut_count == 0, "must have clean count");
+      assert(global_mut_owner == -1, "must have clean owner");
+    }
+    global_mut_owner = owner;
+    ++global_mut_count;
+  } else {
+    assert (Threads::number_of_threads() == 0, "valid only during initialization");
+  }
+}
+
+ThreadCritical::~ThreadCritical() {
+  if (os::Solaris::synchronization_initialized()) {
+    assert(global_mut_owner == thr_self(), "must have correct owner");
+    assert(global_mut_count > 0, "must have correct count");
+    --global_mut_count;
+    if (global_mut_count == 0) {
+      global_mut_owner = -1;
+      if (os::Solaris::mutex_unlock(&global_mut))
+        fatal("ThreadCritical::~ThreadCritical: mutex_unlock failed (%s)", os::strerror(errno));
+    }
+  } else {
+    assert (Threads::number_of_threads() == 0, "valid only during initialization");
+  }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/vmStructs_solaris.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/vmStructs_solaris.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os/solaris/vmStructs_solaris.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os/solaris/vmStructs_solaris.hpp	2024-08-17 18:29:44.546256032 +0200
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
+#define OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
+
+// These are the OS-specific fields, types and integer
+// constants required by the Serviceability Agent. This file is
+// referenced by vmStructs.cpp.
+
+#define VM_STRUCTS_OS(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field) \
+  nonstatic_field(OSThread, _thread_id, OSThread::thread_id_t)
+
+#define VM_TYPES_OS(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type) \
+  declare_unsigned_integer_type(OSThread::thread_id_t)
+
+#define VM_INT_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#define VM_LONG_CONSTANTS_OS(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#define VM_ADDRESSES_OS(declare_address, declare_preprocessor_address, declare_function)
+
+#endif // OS_SOLARIS_VMSTRUCTS_SOLARIS_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/assembler_solaris_x86.cpp	2024-08-17 18:29:44.546664846 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 1999, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "asm/macroAssembler.inline.hpp"
+#include "runtime/os.hpp"
+
+void MacroAssembler::int3() {
+  push(rax);
+  push(rdx);
+  push(rcx);
+  call(RuntimeAddress(CAST_FROM_FN_PTR(address, os::breakpoint)));
+  pop(rcx);
+  pop(rdx);
+  pop(rax);
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/atomic_solaris_x86.hpp	2024-08-17 18:29:44.547033451 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP
+
+// For Sun Studio - implementation is in solaris_x86_64.il.
+
+extern "C" {
+  int32_t _Atomic_add(int32_t add_value, volatile int32_t* dest);
+  int64_t _Atomic_add_long(int64_t add_value, volatile int64_t* dest);
+
+  int32_t _Atomic_xchg(int32_t exchange_value, volatile int32_t* dest);
+  int8_t  _Atomic_cmpxchg_byte(int8_t exchange_value, volatile int8_t* dest,
+                               int8_t compare_value);
+  int32_t _Atomic_cmpxchg(int32_t exchange_value, volatile int32_t* dest,
+                          int32_t compare_value);
+  int64_t _Atomic_cmpxchg_long(int64_t exchange_value, volatile int64_t* dest,
+                               int64_t compare_value);
+}
+
+template<size_t byte_size>
+struct Atomic::PlatformAdd {
+  template<typename D, typename I>
+  D add_and_fetch(D volatile* dest, I add_value, atomic_memory_order order) const;
+
+  template<typename D, typename I>
+  D fetch_and_add(D volatile* dest, I add_value, atomic_memory_order order) const {
+    return add_and_fetch(dest, add_value, order) - add_value;
+  }
+};
+
+// Not using add_using_helper; see comment for cmpxchg.
+template<>
+template<typename D, typename I>
+inline D Atomic::PlatformAdd<4>::add_and_fetch(D volatile* dest, I add_value,
+                                               atomic_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(I));
+  STATIC_ASSERT(4 == sizeof(D));
+  return PrimitiveConversions::cast<D>(
+    _Atomic_add(PrimitiveConversions::cast<int32_t>(add_value),
+                reinterpret_cast<int32_t volatile*>(dest)));
+}
+
+// Not using add_using_helper; see comment for cmpxchg.
+template<>
+template<typename D, typename I>
+inline D Atomic::PlatformAdd<8>::add_and_fetch(D volatile* dest, I add_value,
+                                               atomic_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(I));
+  STATIC_ASSERT(8 == sizeof(D));
+  return PrimitiveConversions::cast<D>(
+    _Atomic_add_long(PrimitiveConversions::cast<int64_t>(add_value),
+                     reinterpret_cast<int64_t volatile*>(dest)));
+}
+
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<4>::operator()(T volatile* dest,
+                                             T exchange_value,
+                                             atomic_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_xchg(PrimitiveConversions::cast<int32_t>(exchange_value),
+                 reinterpret_cast<int32_t volatile*>(dest)));
+}
+
+extern "C" int64_t _Atomic_xchg_long(int64_t exchange_value, volatile int64_t* dest);
+
+template<>
+template<typename T>
+inline T Atomic::PlatformXchg<8>::operator()(T volatile* dest,
+                                             T exchange_value,
+                                             atomic_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_xchg_long(PrimitiveConversions::cast<int64_t>(exchange_value),
+                      reinterpret_cast<int64_t volatile*>(dest)));
+}
+
+// Not using cmpxchg_using_helper here, because some configurations of
+// Solaris compiler don't deal well with passing a "defined in .il"
+// function as an argument.  We *should* switch to using gcc-style
+// inline assembly, but attempting to do so with Studio 12.4 ran into
+// segfaults.
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<1>::operator()(T volatile* dest,
+                                                T compare_value,
+                                                T exchange_value,
+                                                atomic_memory_order order) const {
+  STATIC_ASSERT(1 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_cmpxchg_byte(PrimitiveConversions::cast<int8_t>(exchange_value),
+                         reinterpret_cast<int8_t volatile*>(dest),
+                         PrimitiveConversions::cast<int8_t>(compare_value)));
+}
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<4>::operator()(T volatile* dest,
+                                                T compare_value,
+                                                T exchange_value,
+                                                atomic_memory_order order) const {
+  STATIC_ASSERT(4 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_cmpxchg(PrimitiveConversions::cast<int32_t>(exchange_value),
+                    reinterpret_cast<int32_t volatile*>(dest),
+                    PrimitiveConversions::cast<int32_t>(compare_value)));
+}
+
+template<>
+template<typename T>
+inline T Atomic::PlatformCmpxchg<8>::operator()(T volatile* dest,
+                                                T compare_value,
+                                                T exchange_value,
+                                                atomic_memory_order order) const {
+  STATIC_ASSERT(8 == sizeof(T));
+  return PrimitiveConversions::cast<T>(
+    _Atomic_cmpxchg_long(PrimitiveConversions::cast<int64_t>(exchange_value),
+                         reinterpret_cast<int64_t volatile*>(dest),
+                         PrimitiveConversions::cast<int64_t>(compare_value)));
+}
+
+#endif // OS_CPU_SOLARIS_X86_ATOMIC_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/bytes_solaris_x86.hpp	2024-08-17 18:29:44.547337911 +0200
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 1998, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP
+
+// For Sun Studio - implementation is in solaris_i486.il.
+// For gcc - implementation is just below.
+extern "C" u2 _raw_swap_u2(u2 x);
+extern "C" u4 _raw_swap_u4(u4 x);
+#ifdef AMD64
+extern "C" u8 _raw_swap_u8(u8 x);
+#else
+extern "C" u8 _raw_swap_u8(u4 x, u4 y);
+#endif // AMD64
+
+// Efficient swapping of data bytes from Java byte
+// ordering to native byte ordering and vice versa.
+inline u2   Bytes::swap_u2(u2 x) {
+  return _raw_swap_u2(x);
+}
+
+inline u4   Bytes::swap_u4(u4 x) {
+  return _raw_swap_u4(x);
+}
+
+inline u8   Bytes::swap_u8(u8 x) {
+#ifdef AMD64
+  return _raw_swap_u8(x);
+#else
+  return swap_u8_base(*(u4*)&x, *(((u4*)&x)+1));
+#endif // AMD64
+
+}
+
+#ifndef AMD64
+// Helper function for swap_u8
+inline u8   Bytes::swap_u8_base(u4 x, u4 y) {
+  return _raw_swap_u8(x, y);
+}
+#endif // !AMD64
+
+#endif // OS_CPU_SOLARIS_X86_BYTES_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/copy_solaris_x86.hpp	2024-08-17 18:29:44.547689736 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP
+
+static void pd_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
+  (void)memmove(to, from, count * HeapWordSize);
+}
+
+static void pd_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
+#ifndef AMD64
+  (void)memcpy(to, from, count * HeapWordSize);
+#else
+  switch (count) {
+  case 8:  to[7] = from[7];
+  case 7:  to[6] = from[6];
+  case 6:  to[5] = from[5];
+  case 5:  to[4] = from[4];
+  case 4:  to[3] = from[3];
+  case 3:  to[2] = from[2];
+  case 2:  to[1] = from[1];
+  case 1:  to[0] = from[0];
+  case 0:  break;
+  default:
+    (void)memcpy(to, from, count * HeapWordSize);
+    break;
+  }
+#endif // AMD64
+}
+
+static void pd_disjoint_words_atomic(const HeapWord* from, HeapWord* to, size_t count) {
+  switch (count) {
+  case 8:  to[7] = from[7];
+  case 7:  to[6] = from[6];
+  case 6:  to[5] = from[5];
+  case 5:  to[4] = from[4];
+  case 4:  to[3] = from[3];
+  case 3:  to[2] = from[2];
+  case 2:  to[1] = from[1];
+  case 1:  to[0] = from[0];
+  case 0:  break;
+  default: while (count-- > 0) {
+             *to++ = *from++;
+           }
+           break;
+  }
+}
+
+static void pd_aligned_conjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
+  (void)memmove(to, from, count * HeapWordSize);
+}
+
+static void pd_aligned_disjoint_words(const HeapWord* from, HeapWord* to, size_t count) {
+  pd_disjoint_words(from, to, count);
+}
+
+static void pd_conjoint_bytes(const void* from, void* to, size_t count) {
+#ifdef AMD64
+  (void)memmove(to, from, count);
+#else
+  _Copy_conjoint_bytes(from, to, count);
+#endif // AMD64
+}
+
+static void pd_conjoint_bytes_atomic(const void* from, void* to, size_t count) {
+  pd_conjoint_bytes(from, to, count);
+}
+
+static void pd_conjoint_jshorts_atomic(const jshort* from, jshort* to, size_t count) {
+  _Copy_conjoint_jshorts_atomic(from, to, count);
+}
+
+static void pd_conjoint_jints_atomic(const jint* from, jint* to, size_t count) {
+  _Copy_conjoint_jints_atomic(from, to, count);
+}
+
+static void pd_conjoint_jlongs_atomic(const jlong* from, jlong* to, size_t count) {
+  // Guarantee use of fild/fistp or xmm regs via some asm code, because compilers won't.
+  _Copy_conjoint_jlongs_atomic(from, to, count);
+}
+
+static void pd_conjoint_oops_atomic(const oop* from, oop* to, size_t count) {
+#ifdef AMD64
+  assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size");
+  _Copy_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count);
+#else
+  _Copy_conjoint_jints_atomic((const jint*)from, (jint*)to, count);
+#endif // AMD64
+}
+
+static void pd_arrayof_conjoint_bytes(const HeapWord* from, HeapWord* to, size_t count) {
+  _Copy_arrayof_conjoint_bytes(from, to, count);
+}
+
+static void pd_arrayof_conjoint_jshorts(const HeapWord* from, HeapWord* to, size_t count) {
+  _Copy_arrayof_conjoint_jshorts(from, to, count);
+}
+
+static void pd_arrayof_conjoint_jints(const HeapWord* from, HeapWord* to, size_t count) {
+  _Copy_arrayof_conjoint_jints(from, to, count);
+}
+
+static void pd_arrayof_conjoint_jlongs(const HeapWord* from, HeapWord* to, size_t count) {
+#ifdef AMD64
+  _Copy_arrayof_conjoint_jlongs(from, to, count);
+#else
+  pd_conjoint_jlongs_atomic((const jlong*)from, (jlong*)to, count);
+#endif // AMD64
+}
+
+static void pd_arrayof_conjoint_oops(const HeapWord* from, HeapWord* to, size_t count) {
+#ifdef AMD64
+  assert(BytesPerLong == BytesPerOop, "jlongs and oops must be the same size");
+  _Copy_arrayof_conjoint_jlongs(from, to, count);
+#else
+  assert(BytesPerInt == BytesPerOop, "jints and oops must be the same size");
+  _Copy_arrayof_conjoint_jints(from, to, count);
+#endif // AMD64
+}
+
+#endif // OS_CPU_SOLARIS_X86_COPY_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/count_trailing_zeros_solaris_x86.hpp	2024-08-17 18:29:44.547994165 +0200
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_COUNT_TRAILING_ZEROS_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_COUNT_TRAILING_ZEROS_SOLARIS_X86_HPP
+
+#include "utilities/globalDefinitions.hpp"
+
+inline unsigned count_trailing_zeros(uintx x) {
+  assert(x != 0, "precondition");
+  uintx result;
+  __asm__(" rep bsfq %1, %0" : "=r" (result) : "rm" (x));
+  return result;
+}
+
+#endif // OS_CPU_SOLARIS_X86_COUNT_TRAILING_ZEROS_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/globals_solaris_x86.hpp	2024-08-17 18:29:44.548483312 +0200
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP
+
+// Sets the default values for platform dependent flags used by the runtime system.
+// (see globals.hpp)
+
+define_pd_global(bool, DontYieldALot,            true); // Determined in the design center
+#ifdef AMD64
+define_pd_global(intx, CompilerThreadStackSize,  1024);
+define_pd_global(intx, ThreadStackSize,          1024); // 0 => use system default
+define_pd_global(intx, VMThreadStackSize,        1024);
+define_pd_global(size_t, JVMInvokeMethodSlack,   8*K);
+#else
+define_pd_global(intx, CompilerThreadStackSize,  512);
+// ThreadStackSize 320 allows a couple of test cases to run while
+// keeping the number of threads that can be created high.
+define_pd_global(intx, ThreadStackSize,          320);
+define_pd_global(intx, VMThreadStackSize,        512);
+define_pd_global(size_t, JVMInvokeMethodSlack,   10*K);
+#endif // AMD64
+
+
+// Used on 64 bit platforms for UseCompressedOops base address
+define_pd_global(size_t, HeapBaseMinAddress,     2*G);
+
+#endif // OS_CPU_SOLARIS_X86_GLOBALS_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/orderAccess_solaris_x86.hpp	2024-08-17 18:29:44.548793047 +0200
@@ -0,0 +1,62 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP
+
+// Included in orderAccess.hpp header file.
+
+// Compiler version last used for testing: solaris studio 12u3
+// Please update this information when this file changes
+
+// Implementation of class OrderAccess.
+
+// A compiler barrier, forcing the C++ compiler to invalidate all memory assumptions
+inline void compiler_barrier() {
+  __asm__ volatile ("" : : : "memory");
+}
+
+inline void OrderAccess::loadload()   { compiler_barrier(); }
+inline void OrderAccess::storestore() { compiler_barrier(); }
+inline void OrderAccess::loadstore()  { compiler_barrier(); }
+inline void OrderAccess::storeload()  { fence();            }
+
+inline void OrderAccess::acquire()    { compiler_barrier(); }
+inline void OrderAccess::release()    { compiler_barrier(); }
+
+inline void OrderAccess::fence() {
+#ifdef AMD64
+  __asm__ volatile ("lock; addl $0,0(%%rsp)" : : : "cc", "memory");
+#else
+  __asm__ volatile ("lock; addl $0,0(%%esp)" : : : "cc", "memory");
+#endif
+  compiler_barrier();
+}
+
+inline void OrderAccess::cross_modify_fence_impl() {
+  int idx = 0;
+  __asm__ volatile ("cpuid " : "+a" (idx) : : "ebx", "ecx", "edx", "memory");
+}
+
+#endif // OS_CPU_SOLARIS_X86_ORDERACCESS_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.cpp	2024-08-17 18:29:44.549583121 +0200
@@ -0,0 +1,919 @@
+/*
+ * Copyright (c) 1999, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+// no precompiled headers
+#include "jvm.h"
+#include "asm/macroAssembler.hpp"
+#include "classfile/classLoader.hpp"
+#include "classfile/systemDictionary.hpp"
+#include "classfile/vmSymbols.hpp"
+#include "code/codeCache.hpp"
+#include "code/icBuffer.hpp"
+#include "code/vtableStubs.hpp"
+#include "interpreter/interpreter.hpp"
+#include "logging/log.hpp"
+#include "memory/allocation.inline.hpp"
+#include "os_share_solaris.hpp"
+#include "prims/jniFastGetField.hpp"
+#include "prims/jvm_misc.hpp"
+#include "runtime/arguments.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/interfaceSupport.inline.hpp"
+#include "runtime/java.hpp"
+#include "runtime/javaCalls.hpp"
+#include "runtime/mutexLocker.hpp"
+#include "runtime/osThread.hpp"
+#include "runtime/safepointMechanism.hpp"
+#include "runtime/sharedRuntime.hpp"
+#include "runtime/stubRoutines.hpp"
+#include "runtime/thread.inline.hpp"
+#include "runtime/timer.hpp"
+#include "signals_posix.hpp"
+#include "utilities/align.hpp"
+#include "utilities/events.hpp"
+#include "utilities/vmError.hpp"
+
+// put OS-includes here
+# include <sys/types.h>
+# include <sys/mman.h>
+# include <pthread.h>
+# include <signal.h>
+# include <setjmp.h>
+# include <errno.h>
+# include <dlfcn.h>
+# include <stdio.h>
+# include <unistd.h>
+# include <sys/resource.h>
+# include <thread.h>
+# include <sys/stat.h>
+# include <sys/time.h>
+# include <sys/filio.h>
+# include <sys/utsname.h>
+# include <sys/systeminfo.h>
+# include <sys/socket.h>
+# include <sys/trap.h>
+# include <sys/lwp.h>
+# include <poll.h>
+# include <sys/lwp.h>
+# include <procfs.h>     //  see comment in <sys/procfs.h>
+
+#ifndef AMD64
+// QQQ seems useless at this point
+# define _STRUCTURED_PROC 1  //  this gets us the new structured proc interfaces of 5.6 & later
+#endif // AMD64
+# include <sys/procfs.h>     //  see comment in <sys/procfs.h>
+
+
+#define MAX_PATH (2 * K)
+
+// Minimum usable stack sizes required to get to user code. Space for
+// HotSpot guard pages is added later.
+#ifdef _LP64
+// The adlc generated method 'State::MachNodeGenerator(int)' used by the C2 compiler
+// threads requires a large stack with the Solaris Studio C++ compiler version 5.13
+// and product VM builds (debug builds require significantly less stack space).
+size_t os::Posix::_compiler_thread_min_stack_allowed = 325 * K;
+size_t os::Posix::_java_thread_min_stack_allowed = 48 * K;
+size_t os::Posix::_vm_internal_thread_min_stack_allowed = 224 * K;
+#else
+size_t os::Posix::_compiler_thread_min_stack_allowed = 32 * K;
+size_t os::Posix::_java_thread_min_stack_allowed = 32 * K;
+size_t os::Posix::_vm_internal_thread_min_stack_allowed = 64 * K;
+#endif // _LP64
+
+#ifdef AMD64
+#define REG_SP REG_RSP
+#define REG_PC REG_RIP
+#define REG_FP REG_RBP
+#else
+#define REG_SP UESP
+#define REG_PC EIP
+#define REG_FP EBP
+// 4900493 counter to prevent runaway LDTR refresh attempt
+
+static volatile int ldtr_refresh = 0;
+// the libthread instruction that faults because of the stale LDTR
+
+static const unsigned char movlfs[] = { 0x8e, 0xe0    // movl %eax,%fs
+                       };
+#endif // AMD64
+
+char* os::non_memory_address_word() {
+  // Must never look like an address returned by reserve_memory,
+  // even in its subfields (as defined by the CPU immediate fields,
+  // if the CPU splits constants across multiple instructions).
+  return (char*) -1;
+}
+
+//
+// Validate a ucontext retrieved from walking a uc_link of a ucontext.
+// There are issues with libthread giving out uc_links for different threads
+// on the same uc_link chain and bad or circular links.
+//
+bool os::Solaris::valid_ucontext(Thread* thread, const ucontext_t* valid, const ucontext_t* suspect) {
+  if (valid >= suspect ||
+      valid->uc_stack.ss_flags != suspect->uc_stack.ss_flags ||
+      valid->uc_stack.ss_sp    != suspect->uc_stack.ss_sp    ||
+      valid->uc_stack.ss_size  != suspect->uc_stack.ss_size) {
+    DEBUG_ONLY(tty->print_cr("valid_ucontext: failed test 1");)
+    return false;
+  }
+
+  if (thread->is_Java_thread()) {
+    if (!thread->is_in_full_stack_checked((address)suspect)) {
+      DEBUG_ONLY(tty->print_cr("valid_ucontext: uc_link not in thread stack");)
+      return false;
+    }
+    if (!thread->is_in_full_stack_checked((address) suspect->uc_mcontext.gregs[REG_SP])) {
+      DEBUG_ONLY(tty->print_cr("valid_ucontext: stackpointer not in thread stack");)
+      return false;
+    }
+  }
+  return true;
+}
+
+// We will only follow one level of uc_link since there are libthread
+// issues with ucontext linking and it is better to be safe and just
+// let caller retry later.
+const ucontext_t* os::Solaris::get_valid_uc_in_signal_handler(Thread *thread,
+  const ucontext_t *uc) {
+
+  const ucontext_t *retuc = NULL;
+
+  if (uc != NULL) {
+    if (uc->uc_link == NULL) {
+      // cannot validate without uc_link so accept current ucontext
+      retuc = uc;
+    } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) {
+      // first ucontext is valid so try the next one
+      uc = uc->uc_link;
+      if (uc->uc_link == NULL) {
+        // cannot validate without uc_link so accept current ucontext
+        retuc = uc;
+      } else if (os::Solaris::valid_ucontext(thread, uc, uc->uc_link)) {
+        // the ucontext one level down is also valid so return it
+        retuc = uc;
+      }
+    }
+  }
+  return retuc;
+}
+
+void os::Posix::ucontext_set_pc(ucontext_t* uc, address pc) {
+  uc->uc_mcontext.gregs [REG_PC]  = (greg_t) pc;
+}
+
+// Assumes ucontext is valid
+intptr_t* os::Solaris::ucontext_get_sp(const ucontext_t *uc) {
+  return (intptr_t*)uc->uc_mcontext.gregs[REG_SP];
+}
+
+// Assumes ucontext is valid
+intptr_t* os::Solaris::ucontext_get_fp(const ucontext_t *uc) {
+  return (intptr_t*)uc->uc_mcontext.gregs[REG_FP];
+}
+
+address os::Posix::ucontext_get_pc(const ucontext_t *uc) {
+  return (address) uc->uc_mcontext.gregs[REG_PC];
+}
+
+address os::fetch_frame_from_context(const void* ucVoid,
+                    intptr_t** ret_sp, intptr_t** ret_fp) {
+
+  address  epc;
+  const ucontext_t *uc = (const ucontext_t*)ucVoid;
+
+  if (uc != NULL) {
+    epc = os::Posix::ucontext_get_pc(uc);
+    if (ret_sp) *ret_sp = os::Solaris::ucontext_get_sp(uc);
+    if (ret_fp) *ret_fp = os::Solaris::ucontext_get_fp(uc);
+  } else {
+    epc = NULL;
+    if (ret_sp) *ret_sp = (intptr_t *)NULL;
+    if (ret_fp) *ret_fp = (intptr_t *)NULL;
+  }
+
+  return epc;
+}
+
+frame os::fetch_frame_from_context(const void* ucVoid) {
+  intptr_t* sp;
+  intptr_t* fp;
+  address epc = fetch_frame_from_context(ucVoid, &sp, &fp);
+  return frame(sp, fp, epc);
+}
+
+bool os::Solaris::get_frame_at_stack_banging_point(JavaThread* thread, ucontext_t* uc, frame* fr) {
+ address pc = (address) os::Solaris::ucontext_get_pc(uc);
+  if (Interpreter::contains(pc)) {
+    // interpreter performs stack banging after the fixed frame header has
+    // been generated while the compilers perform it before. To maintain
+    // semantic consistency between interpreted and compiled frames, the
+    // method returns the Java sender of the current frame.
+    *fr = os::fetch_frame_from_context(uc);
+    if (!fr->is_first_java_frame()) {
+      // get_frame_at_stack_banging_point() is only called when we
+      // have well defined stacks so java_sender() calls do not need
+      // to assert safe_for_sender() first.
+      *fr = fr->java_sender();
+    }
+  } else {
+    // more complex code with compiled code
+    assert(!Interpreter::contains(pc), "Interpreted methods should have been handled above");
+    CodeBlob* cb = CodeCache::find_blob(pc);
+    if (cb == NULL || !cb->is_nmethod() || cb->is_frame_complete_at(pc)) {
+      // Not sure where the pc points to, fallback to default
+      // stack overflow handling
+      return false;
+    } else {
+      // in compiled code, the stack banging is performed just after the return pc
+      // has been pushed on the stack
+      intptr_t* fp = os::Solaris::ucontext_get_fp(uc);
+      intptr_t* sp = os::Solaris::ucontext_get_sp(uc);
+      *fr = frame(sp + 1, fp, (address)*sp);
+      if (!fr->is_java_frame()) {
+        // See java_sender() comment above.
+        *fr = fr->java_sender();
+      }
+    }
+  }
+  assert(fr->is_java_frame(), "Safety check");
+  return true;
+}
+
+frame os::get_sender_for_C_frame(frame* fr) {
+  return frame(fr->sender_sp(), fr->link(), fr->sender_pc());
+}
+
+extern "C" intptr_t *_get_current_sp() {
+  register intptr_t *rsp __asm__ ("rsp");
+  return rsp;
+}
+
+address os::current_stack_pointer() {
+  return (address)_get_current_sp();
+}
+
+extern "C" intptr_t *_get_current_fp() {
+  register intptr_t **rbp __asm__ ("rbp");
+  return (intptr_t*) *rbp;
+}
+
+frame os::current_frame() {
+  intptr_t* fp = _get_current_fp();  // it's inlined so want current fp
+  // fp is for os::current_frame. We want the fp for our caller.
+  frame myframe((intptr_t*)os::current_stack_pointer(),
+                (intptr_t*)fp,
+                CAST_FROM_FN_PTR(address, os::current_frame));
+  frame caller_frame = os::get_sender_for_C_frame(&myframe);
+
+  if (os::is_first_C_frame(&caller_frame)) {
+    // stack is not walkable
+    frame ret; // This will be a null useless frame
+    return ret;
+  } else {
+    // return frame for our caller's caller
+    return os::get_sender_for_C_frame(&caller_frame);
+  }
+}
+
+#ifndef AMD64
+
+// Detecting SSE support by OS
+// From solaris_i486.s
+extern "C" bool sse_check();
+extern "C" bool sse_unavailable();
+
+enum { SSE_UNKNOWN, SSE_NOT_SUPPORTED, SSE_SUPPORTED};
+static int sse_status = SSE_UNKNOWN;
+
+
+static void  check_for_sse_support() {
+  if (!VM_Version::supports_sse()) {
+    sse_status = SSE_NOT_SUPPORTED;
+    return;
+  }
+  // looking for _sse_hw in libc.so, if it does not exist or
+  // the value (int) is 0, OS has no support for SSE
+  int *sse_hwp;
+  void *h;
+
+  if ((h=dlopen("/usr/lib/libc.so", RTLD_LAZY)) == NULL) {
+    //open failed, presume no support for SSE
+    sse_status = SSE_NOT_SUPPORTED;
+    return;
+  }
+  if ((sse_hwp = (int *)dlsym(h, "_sse_hw")) == NULL) {
+    sse_status = SSE_NOT_SUPPORTED;
+  } else if (*sse_hwp == 0) {
+    sse_status = SSE_NOT_SUPPORTED;
+  }
+  dlclose(h);
+
+  if (sse_status == SSE_UNKNOWN) {
+    bool (*try_sse)() = (bool (*)())sse_check;
+    sse_status = (*try_sse)() ? SSE_SUPPORTED : SSE_NOT_SUPPORTED;
+  }
+
+}
+
+#endif // AMD64
+
+bool os::supports_sse() {
+#ifdef AMD64
+  return true;
+#else
+  if (sse_status == SSE_UNKNOWN)
+    check_for_sse_support();
+  return sse_status == SSE_SUPPORTED;
+#endif // AMD64
+}
+
+bool os::is_allocatable(size_t bytes) {
+#ifdef AMD64
+  return true;
+#else
+
+  if (bytes < 2 * G) {
+    return true;
+  }
+
+  char* addr = reserve_memory(bytes, NULL);
+
+  if (addr != NULL) {
+    release_memory(addr, bytes);
+  }
+
+  return addr != NULL;
+#endif // AMD64
+
+}
+
+extern "C" JNIEXPORT int
+JVM_handle_solaris_signal(int sig, siginfo_t* info, void* ucVoid,
+                          int abort_if_unrecognized) {
+  ucontext_t* uc = (ucontext_t*) ucVoid;
+
+#ifndef AMD64
+  if (sig == SIGILL && info->si_addr == (caddr_t)sse_check) {
+    // the SSE instruction faulted. supports_sse() need return false.
+    uc->uc_mcontext.gregs[EIP] = (greg_t)sse_unavailable;
+    return true;
+  }
+#endif // !AMD64
+
+  Thread* t = Thread::current_or_null_safe();
+
+  // If crash protection is installed we may longjmp away and no destructors
+  // for objects in this scope will be run.
+  // So don't use any RAII utilities before crash protection is checked.
+  os::ThreadCrashProtection::check_crash_protection(sig, t);
+
+  if(sig == SIGPIPE || sig == SIGXFSZ) {
+    if (PosixSignals::chained_handler(sig, info, ucVoid)) {
+      return true;
+    } else {
+      // Ignoring SIGPIPE/SIGXFSZ - see bugs 4229104 or 6499219
+      return true;
+    }
+  }
+
+  JavaThread* thread = NULL;
+  VMThread* vmthread = NULL;
+
+  if (PosixSignals::are_signal_handlers_installed()) {
+    if (t != NULL ){
+      if(t->is_Java_thread()) {
+        thread = (JavaThread*)t;
+      }
+      else if(t->is_VM_thread()){
+        vmthread = (VMThread *)t;
+      }
+    }
+  }
+
+  if (sig == ASYNC_SIGNAL) {
+    if(thread || vmthread){
+      return true;
+    } else if (PosixSignals::chained_handler(sig, info, ucVoid)) {
+      return true;
+    } else {
+      // If ASYNC_SIGNAL not chained, and this is a non-vm and
+      // non-java thread
+      return true;
+    }
+  }
+
+  if (info == NULL || info->si_code <= 0 || info->si_code == SI_NOINFO) {
+    // can't decode this kind of signal
+    info = NULL;
+  } else {
+    assert(sig == info->si_signo, "bad siginfo");
+  }
+
+  // decide if this trap can be handled by a stub
+  address stub = NULL;
+
+  address pc          = NULL;
+
+  //%note os_trap_1
+  if (info != NULL && uc != NULL && thread != NULL) {
+    // factor me: getPCfromContext
+    pc = (address) uc->uc_mcontext.gregs[REG_PC];
+
+    if (StubRoutines::is_safefetch_fault(pc)) {
+      os::Posix::ucontext_set_pc(uc, StubRoutines::continuation_for_safefetch_fault(pc));
+      return true;
+    }
+
+    // Handle ALL stack overflow variations here
+    if (sig == SIGSEGV && info->si_code == SEGV_ACCERR) {
+      address addr = (address) info->si_addr;
+      if (thread->in_stack_yellow_reserved_zone(addr)) {
+        if (thread->thread_state() == _thread_in_Java) {
+          if (thread->in_stack_reserved_zone(addr)) {
+            frame fr;
+            if (os::Solaris::get_frame_at_stack_banging_point(thread, uc, &fr)) {
+              assert(fr.is_java_frame(), "Must be Java frame");
+              frame activation = SharedRuntime::look_for_reserved_stack_annotated_method(thread, fr);
+              if (activation.sp() != NULL) {
+                thread->disable_stack_reserved_zone();
+                if (activation.is_interpreted_frame()) {
+                  thread->set_reserved_stack_activation((address)(
+                    activation.fp() + frame::interpreter_frame_initial_sp_offset));
+                } else {
+                  thread->set_reserved_stack_activation((address)activation.unextended_sp());
+                }
+                return true;
+              }
+            }
+          }
+          // Throw a stack overflow exception.  Guard pages will be reenabled
+          // while unwinding the stack.
+          thread->disable_stack_yellow_reserved_zone();
+          stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::STACK_OVERFLOW);
+        } else {
+          // Thread was in the vm or native code.  Return and try to finish.
+          thread->disable_stack_yellow_reserved_zone();
+          return true;
+        }
+      } else if (thread->in_stack_red_zone(addr)) {
+        // Fatal red zone violation.  Disable the guard pages and fall through
+        // to handle_unexpected_exception way down below.
+        thread->disable_stack_red_zone();
+        tty->print_raw_cr("An irrecoverable stack overflow has occurred.");
+      }
+    }
+
+    if ((sig == SIGSEGV) && VM_Version::is_cpuinfo_segv_addr(pc)) {
+      // Verify that OS save/restore AVX registers.
+      stub = VM_Version::cpuinfo_cont_addr();
+    }
+
+    if (thread->thread_state() == _thread_in_vm ||
+         thread->thread_state() == _thread_in_native) {
+      if (sig == SIGBUS && info->si_code == BUS_OBJERR && thread->doing_unsafe_access()) {
+        address next_pc = Assembler::locate_next_instruction(pc);
+        if (UnsafeCopyMemory::contains_pc(pc)) {
+          next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
+        }
+        stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
+      }
+    }
+
+    if (thread->thread_state() == _thread_in_Java) {
+      // Support Safepoint Polling
+      if ( sig == SIGSEGV && SafepointMechanism::is_poll_address((address)info->si_addr)) {
+        stub = SharedRuntime::get_poll_stub(pc);
+      }
+      else if (sig == SIGBUS && info->si_code == BUS_OBJERR) {
+        // BugId 4454115: A read from a MappedByteBuffer can fault
+        // here if the underlying file has been truncated.
+        // Do not crash the VM in such a case.
+        CodeBlob* cb = CodeCache::find_blob_unsafe(pc);
+        if (cb != NULL) {
+          CompiledMethod* nm = cb->as_compiled_method_or_null();
+          bool is_unsafe_arraycopy = thread->doing_unsafe_access() && UnsafeCopyMemory::contains_pc(pc);
+          if ((nm != NULL && nm->has_unsafe_access()) || is_unsafe_arraycopy) {
+            address next_pc = Assembler::locate_next_instruction(pc);
+            if (is_unsafe_arraycopy) {
+              next_pc = UnsafeCopyMemory::page_error_continue_pc(pc);
+            }
+            stub = SharedRuntime::handle_unsafe_access(thread, next_pc);
+          }
+        }
+      }
+      else
+      if (sig == SIGFPE && info->si_code == FPE_INTDIV) {
+        // integer divide by zero
+        stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
+      }
+#ifndef AMD64
+      else if (sig == SIGFPE && info->si_code == FPE_FLTDIV) {
+        // floating-point divide by zero
+        stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_DIVIDE_BY_ZERO);
+      }
+      else if (sig == SIGFPE && info->si_code == FPE_FLTINV) {
+        // The encoding of D2I in i486.ad can cause an exception prior
+        // to the fist instruction if there was an invalid operation
+        // pending. We want to dismiss that exception. From the win_32
+        // side it also seems that if it really was the fist causing
+        // the exception that we do the d2i by hand with different
+        // rounding. Seems kind of weird. QQQ TODO
+        // Note that we take the exception at the NEXT floating point instruction.
+        if (pc[0] == 0xDB) {
+            assert(pc[0] == 0xDB, "not a FIST opcode");
+            assert(pc[1] == 0x14, "not a FIST opcode");
+            assert(pc[2] == 0x24, "not a FIST opcode");
+            return true;
+        } else {
+            assert(pc[-3] == 0xDB, "not an flt invalid opcode");
+            assert(pc[-2] == 0x14, "not an flt invalid opcode");
+            assert(pc[-1] == 0x24, "not an flt invalid opcode");
+        }
+      }
+      else if (sig == SIGFPE ) {
+        tty->print_cr("caught SIGFPE, info 0x%x.", info->si_code);
+      }
+#endif // !AMD64
+
+        // QQQ It doesn't seem that we need to do this on x86 because we should be able
+        // to return properly from the handler without this extra stuff on the back side.
+
+      else if (sig == SIGSEGV && info->si_code > 0 &&
+               MacroAssembler::uses_implicit_null_check(info->si_addr)) {
+        // Determination of interpreter/vtable stub/compiled code null exception
+        stub = SharedRuntime::continuation_for_implicit_exception(thread, pc, SharedRuntime::IMPLICIT_NULL);
+      }
+    }
+
+    // jni_fast_Get<Primitive>Field can trap at certain pc's if a GC kicks in
+    // and the heap gets shrunk before the field access.
+    if ((sig == SIGSEGV) || (sig == SIGBUS)) {
+      address addr = JNI_FastGetField::find_slowcase_pc(pc);
+      if (addr != (address)-1) {
+        stub = addr;
+      }
+    }
+  }
+
+  // Execution protection violation
+  //
+  // Preventative code for future versions of Solaris which may
+  // enable execution protection when running the 32-bit VM on AMD64.
+  //
+  // This should be kept as the last step in the triage.  We don't
+  // have a dedicated trap number for a no-execute fault, so be
+  // conservative and allow other handlers the first shot.
+  //
+  // Note: We don't test that info->si_code == SEGV_ACCERR here.
+  // this si_code is so generic that it is almost meaningless; and
+  // the si_code for this condition may change in the future.
+  // Furthermore, a false-positive should be harmless.
+  if (UnguardOnExecutionViolation > 0 &&
+      (sig == SIGSEGV || sig == SIGBUS) &&
+      uc->uc_mcontext.gregs[TRAPNO] == T_PGFLT) {  // page fault
+    int page_size = os::vm_page_size();
+    address addr = (address) info->si_addr;
+    address pc = (address) uc->uc_mcontext.gregs[REG_PC];
+    // Make sure the pc and the faulting address are sane.
+    //
+    // If an instruction spans a page boundary, and the page containing
+    // the beginning of the instruction is executable but the following
+    // page is not, the pc and the faulting address might be slightly
+    // different - we still want to unguard the 2nd page in this case.
+    //
+    // 15 bytes seems to be a (very) safe value for max instruction size.
+    bool pc_is_near_addr =
+      (pointer_delta((void*) addr, (void*) pc, sizeof(char)) < 15);
+    bool instr_spans_page_boundary =
+      (align_down((intptr_t) pc ^ (intptr_t) addr,
+                       (intptr_t) page_size) > 0);
+
+    if (pc == addr || (pc_is_near_addr && instr_spans_page_boundary)) {
+      static volatile address last_addr =
+        (address) os::non_memory_address_word();
+
+      // In conservative mode, don't unguard unless the address is in the VM
+      if (addr != last_addr &&
+          (UnguardOnExecutionViolation > 1 || os::address_is_in_vm(addr))) {
+
+        // Make memory rwx and retry
+        address page_start = align_down(addr, page_size);
+        bool res = os::protect_memory((char*) page_start, page_size,
+                                      os::MEM_PROT_RWX);
+
+        log_debug(os)("Execution protection violation "
+                      "at " INTPTR_FORMAT
+                      ", unguarding " INTPTR_FORMAT ": %s, errno=%d", p2i(addr),
+                      p2i(page_start), (res ? "success" : "failed"), errno);
+        stub = pc;
+
+        // Set last_addr so if we fault again at the same address, we don't end
+        // up in an endless loop.
+        //
+        // There are two potential complications here.  Two threads trapping at
+        // the same address at the same time could cause one of the threads to
+        // think it already unguarded, and abort the VM.  Likely very rare.
+        //
+        // The other race involves two threads alternately trapping at
+        // different addresses and failing to unguard the page, resulting in
+        // an endless loop.  This condition is probably even more unlikely than
+        // the first.
+        //
+        // Although both cases could be avoided by using locks or thread local
+        // last_addr, these solutions are unnecessary complication: this
+        // handler is a best-effort safety net, not a complete solution.  It is
+        // disabled by default and should only be used as a workaround in case
+        // we missed any no-execute-unsafe VM code.
+
+        last_addr = addr;
+      }
+    }
+  }
+
+  if (stub != NULL) {
+    // save all thread context in case we need to restore it
+
+    if (thread != NULL) thread->set_saved_exception_pc(pc);
+    // 12/02/99: On Sparc it appears that the full context is also saved
+    // but as yet, no one looks at or restores that saved context
+    os::Posix::ucontext_set_pc(uc, stub);
+    return true;
+  }
+
+  // signal-chaining
+  if (PosixSignals::chained_handler(sig, info, ucVoid)) {
+    return true;
+  }
+
+  if (!abort_if_unrecognized) {
+    // caller wants another chance, so give it to him
+    return false;
+  }
+
+  if (!os::Solaris::libjsig_is_loaded) {
+    struct sigaction oldAct;
+    sigaction(sig, (struct sigaction *)0, &oldAct);
+    if (oldAct.sa_sigaction != signalHandler) {
+      void* sighand = oldAct.sa_sigaction ? CAST_FROM_FN_PTR(void*,  oldAct.sa_sigaction)
+                                          : CAST_FROM_FN_PTR(void*, oldAct.sa_handler);
+      warning("Unexpected Signal %d occurred under user-defined signal handler %#lx", sig, (long)sighand);
+    }
+  }
+
+  if (pc == NULL && uc != NULL) {
+    pc = (address) uc->uc_mcontext.gregs[REG_PC];
+  }
+
+  // unmask current signal
+  sigset_t newset;
+  sigemptyset(&newset);
+  sigaddset(&newset, sig);
+  sigprocmask(SIG_UNBLOCK, &newset, NULL);
+
+  // Determine which sort of error to throw.  Out of swap may signal
+  // on the thread stack, which could get a mapping error when touched.
+  address addr = (address) info->si_addr;
+  if (sig == SIGBUS && info->si_code == BUS_OBJERR && info->si_errno == ENOMEM) {
+    vm_exit_out_of_memory(0, OOM_MMAP_ERROR, "Out of swap space to map in thread stack.");
+  }
+
+  VMError::report_and_die(t, sig, pc, info, ucVoid);
+
+  ShouldNotReachHere();
+  return false;
+}
+
+void os::print_context(outputStream *st, const void *context) {
+  if (context == NULL) return;
+
+  const ucontext_t *uc = (const ucontext_t*)context;
+  st->print_cr("Registers:");
+#ifdef AMD64
+  st->print(  "RAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RAX]);
+  st->print(", RBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBX]);
+  st->print(", RCX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RCX]);
+  st->print(", RDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDX]);
+  st->cr();
+  st->print(  "RSP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSP]);
+  st->print(", RBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RBP]);
+  st->print(", RSI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RSI]);
+  st->print(", RDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RDI]);
+  st->cr();
+  st->print(  "R8 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R8]);
+  st->print(", R9 =" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R9]);
+  st->print(", R10=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R10]);
+  st->print(", R11=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R11]);
+  st->cr();
+  st->print(  "R12=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R12]);
+  st->print(", R13=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R13]);
+  st->print(", R14=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R14]);
+  st->print(", R15=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_R15]);
+  st->cr();
+  st->print(  "RIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RIP]);
+  st->print(", RFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[REG_RFL]);
+#else
+  st->print(  "EAX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EAX]);
+  st->print(", EBX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBX]);
+  st->print(", ECX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ECX]);
+  st->print(", EDX=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDX]);
+  st->cr();
+  st->print(  "ESP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[UESP]);
+  st->print(", EBP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EBP]);
+  st->print(", ESI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[ESI]);
+  st->print(", EDI=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EDI]);
+  st->cr();
+  st->print(  "EIP=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EIP]);
+  st->print(", EFLAGS=" INTPTR_FORMAT, uc->uc_mcontext.gregs[EFL]);
+#endif // AMD64
+  st->cr();
+  st->cr();
+
+  intptr_t *sp = (intptr_t *)os::Solaris::ucontext_get_sp(uc);
+  st->print_cr("Top of Stack: (sp=" INTPTR_FORMAT ")", (intptr_t)sp);
+  print_hex_dump(st, (address)sp, (address)(sp + 8*sizeof(intptr_t)), sizeof(intptr_t));
+  st->cr();
+
+  // Note: it may be unsafe to inspect memory near pc. For example, pc may
+  // point to garbage if entry point in an nmethod is corrupted. Leave
+  // this at the end, and hope for the best.
+  address pc = os::Posix::ucontext_get_pc(uc);
+  print_instructions(st, pc, sizeof(char));
+  st->cr();
+}
+
+void os::print_register_info(outputStream *st, const void *context) {
+  if (context == NULL) return;
+
+  const ucontext_t *uc = (const ucontext_t*)context;
+
+  st->print_cr("Register to memory mapping:");
+  st->cr();
+
+  // this is horrendously verbose but the layout of the registers in the
+  // context does not match how we defined our abstract Register set, so
+  // we can't just iterate through the gregs area
+
+  // this is only for the "general purpose" registers
+
+#ifdef AMD64
+  st->print("RAX="); print_location(st, uc->uc_mcontext.gregs[REG_RAX]);
+  st->print("RBX="); print_location(st, uc->uc_mcontext.gregs[REG_RBX]);
+  st->print("RCX="); print_location(st, uc->uc_mcontext.gregs[REG_RCX]);
+  st->print("RDX="); print_location(st, uc->uc_mcontext.gregs[REG_RDX]);
+  st->print("RSP="); print_location(st, uc->uc_mcontext.gregs[REG_RSP]);
+  st->print("RBP="); print_location(st, uc->uc_mcontext.gregs[REG_RBP]);
+  st->print("RSI="); print_location(st, uc->uc_mcontext.gregs[REG_RSI]);
+  st->print("RDI="); print_location(st, uc->uc_mcontext.gregs[REG_RDI]);
+  st->print("R8 ="); print_location(st, uc->uc_mcontext.gregs[REG_R8]);
+  st->print("R9 ="); print_location(st, uc->uc_mcontext.gregs[REG_R9]);
+  st->print("R10="); print_location(st, uc->uc_mcontext.gregs[REG_R10]);
+  st->print("R11="); print_location(st, uc->uc_mcontext.gregs[REG_R11]);
+  st->print("R12="); print_location(st, uc->uc_mcontext.gregs[REG_R12]);
+  st->print("R13="); print_location(st, uc->uc_mcontext.gregs[REG_R13]);
+  st->print("R14="); print_location(st, uc->uc_mcontext.gregs[REG_R14]);
+  st->print("R15="); print_location(st, uc->uc_mcontext.gregs[REG_R15]);
+#else
+  st->print("EAX="); print_location(st, uc->uc_mcontext.gregs[EAX]);
+  st->print("EBX="); print_location(st, uc->uc_mcontext.gregs[EBX]);
+  st->print("ECX="); print_location(st, uc->uc_mcontext.gregs[ECX]);
+  st->print("EDX="); print_location(st, uc->uc_mcontext.gregs[EDX]);
+  st->print("ESP="); print_location(st, uc->uc_mcontext.gregs[UESP]);
+  st->print("EBP="); print_location(st, uc->uc_mcontext.gregs[EBP]);
+  st->print("ESI="); print_location(st, uc->uc_mcontext.gregs[ESI]);
+  st->print("EDI="); print_location(st, uc->uc_mcontext.gregs[EDI]);
+#endif
+
+  st->cr();
+}
+
+
+#ifdef AMD64
+void os::Solaris::init_thread_fpu_state(void) {
+  // Nothing to do
+}
+#else
+// From solaris_i486.s
+extern "C" void fixcw();
+
+void os::Solaris::init_thread_fpu_state(void) {
+  // Set fpu to 53 bit precision. This happens too early to use a stub.
+  fixcw();
+}
+
+// These routines are the initial value of atomic_xchg_entry(),
+// atomic_cmpxchg_entry(), atomic_inc_entry() and fence_entry()
+// until initialization is complete.
+// TODO - replace with .il implementation when compiler supports it.
+
+typedef int32_t  xchg_func_t        (int32_t,  volatile int32_t*);
+typedef int32_t  cmpxchg_func_t     (int32_t,  volatile int32_t*,  int32_t);
+typedef int64_t  cmpxchg_long_func_t(int64_t,  volatile int64_t*,  int64_t);
+typedef int32_t  add_func_t         (int32_t,  volatile int32_t*);
+
+int32_t os::atomic_xchg_bootstrap(int32_t exchange_value, volatile int32_t* dest) {
+  // try to use the stub:
+  xchg_func_t* func = CAST_TO_FN_PTR(xchg_func_t*, StubRoutines::atomic_xchg_entry());
+
+  if (func != NULL) {
+    os::atomic_xchg_func = func;
+    return (*func)(exchange_value, dest);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  int32_t old_value = *dest;
+  *dest = exchange_value;
+  return old_value;
+}
+
+int32_t os::atomic_cmpxchg_bootstrap(int32_t exchange_value, volatile int32_t* dest, int32_t compare_value) {
+  // try to use the stub:
+  cmpxchg_func_t* func = CAST_TO_FN_PTR(cmpxchg_func_t*, StubRoutines::atomic_cmpxchg_entry());
+
+  if (func != NULL) {
+    os::atomic_cmpxchg_func = func;
+    return (*func)(exchange_value, dest, compare_value);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  int32_t old_value = *dest;
+  if (old_value == compare_value)
+    *dest = exchange_value;
+  return old_value;
+}
+
+int64_t os::atomic_cmpxchg_long_bootstrap(int64_t exchange_value, volatile int64_t* dest, int64_t compare_value) {
+  // try to use the stub:
+  cmpxchg_long_func_t* func = CAST_TO_FN_PTR(cmpxchg_long_func_t*, StubRoutines::atomic_cmpxchg_long_entry());
+
+  if (func != NULL) {
+    os::atomic_cmpxchg_long_func = func;
+    return (*func)(exchange_value, dest, compare_value);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  int64_t old_value = *dest;
+  if (old_value == compare_value)
+    *dest = exchange_value;
+  return old_value;
+}
+
+int32_t os::atomic_add_bootstrap(int32_t add_value, volatile int32_t* dest) {
+  // try to use the stub:
+  add_func_t* func = CAST_TO_FN_PTR(add_func_t*, StubRoutines::atomic_add_entry());
+
+  if (func != NULL) {
+    os::atomic_add_func = func;
+    return (*func)(add_value, dest);
+  }
+  assert(Threads::number_of_threads() == 0, "for bootstrap only");
+
+  return (*dest) += add_value;
+}
+
+xchg_func_t*         os::atomic_xchg_func         = os::atomic_xchg_bootstrap;
+cmpxchg_func_t*      os::atomic_cmpxchg_func      = os::atomic_cmpxchg_bootstrap;
+cmpxchg_long_func_t* os::atomic_cmpxchg_long_func = os::atomic_cmpxchg_long_bootstrap;
+add_func_t*          os::atomic_add_func          = os::atomic_add_bootstrap;
+
+extern "C" void _solaris_raw_setup_fpu(address ptr);
+void os::setup_fpu() {
+  address fpu_cntrl = StubRoutines::addr_fpu_cntrl_wrd_std();
+  _solaris_raw_setup_fpu(fpu_cntrl);
+}
+#endif // AMD64
+
+#ifndef PRODUCT
+void os::verify_stack_alignment() {
+#ifdef AMD64
+  assert(((intptr_t)os::current_stack_pointer() & (StackAlignmentInBytes-1)) == 0, "incorrect stack alignment");
+#endif
+}
+#endif
+
+int os::extra_bang_size_in_bytes() {
+  // JDK-8050147 requires the full cache line bang for x86.
+  return VM_Version::L1_line_size();
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.hpp	2024-08-17 18:29:44.549901813 +0200
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP
+
+  //
+  // NOTE: we are back in class os here, not Solaris
+  //
+#ifdef AMD64
+  static void setup_fpu() {}
+#else
+  static int32_t  (*atomic_xchg_func)        (int32_t,  volatile int32_t*);
+  static int32_t  (*atomic_cmpxchg_func)     (int32_t,  volatile int32_t*, int32_t);
+  static int64_t  (*atomic_cmpxchg_long_func)(int64_t,  volatile int64_t*, int64_t);
+  static int32_t  (*atomic_add_func)         (int32_t,  volatile int32_t*);
+
+  static int32_t  atomic_xchg_bootstrap        (int32_t,  volatile int32_t*);
+  static int32_t  atomic_cmpxchg_bootstrap     (int32_t,  volatile int32_t*, int32_t);
+  static int64_t  atomic_cmpxchg_long_bootstrap(int64_t,  volatile int64_t*, int64_t);
+  static int32_t  atomic_add_bootstrap         (int32_t,  volatile int32_t*);
+
+  static void setup_fpu();
+#endif // AMD64
+
+  static bool supports_sse();
+
+  static jlong rdtsc();
+
+  static bool is_allocatable(size_t bytes);
+
+  // Used to register dynamic code cache area with the OS
+  // Note: Currently only used in 64 bit Windows implementations
+  static bool register_code_area(char *low, char *high) { return true; }
+
+#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/os_solaris_x86.inline.hpp	2024-08-17 18:29:44.550199837 +0200
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP
+#define OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP
+
+#include "runtime/os.hpp"
+
+// See http://www.technovelty.org/code/c/reading-rdtsc.htl for details
+inline jlong os::rdtsc() {
+  uint64_t res;
+  uint32_t ts1, ts2;
+  __asm__ __volatile__ ("rdtsc" : "=a" (ts1), "=d" (ts2));
+  res = ((uint64_t)ts1 | (uint64_t)ts2 << 32);
+  return (jlong)res;
+}
+
+#endif // OS_CPU_SOLARIS_X86_OS_SOLARIS_X86_INLINE_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/prefetch_solaris_x86.inline.hpp	2024-08-17 18:29:44.550503096 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2003, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP
+#define OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP
+
+#include "runtime/prefetch.hpp"
+
+inline void Prefetch::read (const void *loc, intx interval) {
+#ifdef AMD64
+  __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval));
+#endif // AMD64
+}
+
+inline void Prefetch::write(void *loc, intx interval) {
+#ifdef AMD64
+  __asm__ ("prefetcht0 (%0,%1,1)" : : "r" (loc), "r" (interval));
+#endif // AMD64
+}
+
+#endif // OS_CPU_SOLARIS_X86_PREFETCH_SOLARIS_X86_INLINE_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.il	2024-08-17 18:29:44.550836407 +0200
@@ -0,0 +1,115 @@
+//
+// Copyright (c) 2004, 2015, Oracle and/or its affiliates. All rights reserved.
+// DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+//
+// This code is free software; you can redistribute it and/or modify it
+// under the terms of the GNU General Public License version 2 only, as
+// published by the Free Software Foundation.
+//
+// This code is distributed in the hope that it will be useful, but WITHOUT
+// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+// FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+// version 2 for more details (a copy is included in the LICENSE file that
+// accompanied this code).
+//
+// You should have received a copy of the GNU General Public License version
+// 2 along with this work; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+//
+// Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+// or visit www.oracle.com if you need additional information or have any
+// questions.
+//
+//
+
+  // The argument size of each inline directive is ignored by the compiler
+  // and is set to the number of arguments as documentation.
+
+  // Get the raw thread ID from %gs:0
+      .inline _raw_thread_id,0
+      movq     %fs:0, %rax
+      .end
+
+  // Support for os::rdtsc()
+      .inline _raw_rdtsc,0
+      rdtsc
+      salq     $32, %rdx
+      orq      %rdx, %rax
+      .end
+
+  // Implementation of jint _Atomic_add(jint add_value, volatile jint* dest)
+  // used by Atomic::add(volatile jint* dest, jint add_value)
+      .inline _Atomic_add,2
+      movl     %edi, %eax      // save add_value for return
+      lock
+      xaddl    %edi, (%rsi)
+      addl     %edi, %eax
+      .end
+
+  // Implementation of jlong _Atomic_add(jlong add_value, volatile jlong* dest)
+  // used by Atomic::add(volatile jlong* dest, jint add_value)
+      .inline _Atomic_add_long,2
+      movq     %rdi, %rax      // save add_value for return
+      lock
+      xaddq    %rdi, (%rsi)
+      addq     %rdi, %rax
+      .end
+
+  // Implementation of jint _Atomic_xchg(jint exchange_value, volatile jint* dest)
+  // used by Atomic::xchg(volatile jint* dest, jint exchange_value)
+      .inline _Atomic_xchg,2
+      xchgl    (%rsi), %edi
+      movl     %edi, %eax
+      .end
+
+  // Implementation of jlong _Atomic_xchg(jlong exchange_value, volatile jlong* dest)
+  // used by Atomic::xchg(volatile jlong* dest, jlong exchange_value)
+      .inline _Atomic_xchg_long,2
+      xchgq    (%rsi), %rdi
+      movq     %rdi, %rax
+      .end
+
+  // Support for jbyte Atomic::cmpxchg(volatile jbyte *dest,
+  //                                   jbyte compare_value,
+  //                                   jbyte exchange_value)
+      .inline _Atomic_cmpxchg_byte,3
+      movb     %dl, %al      // compare_value
+      lock
+      cmpxchgb %dil, (%rsi)
+      .end
+
+  // Support for jint Atomic::cmpxchg(volatile jint *dest,
+  //                                  int compare_value,
+  //                                  jint exchange_value)
+      .inline _Atomic_cmpxchg,3
+      movl     %edx, %eax      // compare_value
+      lock
+      cmpxchgl %edi, (%rsi)
+      .end
+
+  // Support for jlong Atomic::cmpxchg(volatile jlong* dest,
+  //                                   jlong compare_value,
+  //                                   jlong exchange_value)
+      .inline _Atomic_cmpxchg_long,3
+      movq     %rdx, %rax      // compare_value
+      lock
+      cmpxchgq %rdi, (%rsi)
+      .end
+
+  // Support for u2 Bytes::swap_u2(u2 x)
+      .inline _raw_swap_u2,1
+      movw     %di, %ax
+      rorw     $8, %ax
+      .end
+
+  // Support for u4 Bytes::swap_u4(u4 x)
+      .inline _raw_swap_u4,1
+      movl     %edi, %eax
+      bswapl   %eax
+      .end
+
+  // Support for u8 Bytes::swap_u8(u8 x)
+      .inline _raw_swap_u8,1
+      movq     %rdi, %rax
+      bswapq   %rax
+      .end
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/solaris_x86_64.S	2024-08-17 18:29:44.551317909 +0200
@@ -0,0 +1,386 @@
+/
+/ Copyright (c) 2004, 2013, Oracle and/or its affiliates. All rights reserved.
+/ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+/
+/ This code is free software; you can redistribute it and/or modify it
+/ under the terms of the GNU General Public License version 2 only, as
+/ published by the Free Software Foundation.
+/
+/ This code is distributed in the hope that it will be useful, but WITHOUT
+/ ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+/ FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+/ version 2 for more details (a copy is included in the LICENSE file that
+/ accompanied this code).
+/
+/ You should have received a copy of the GNU General Public License version
+/ 2 along with this work; if not, write to the Free Software Foundation,
+/ Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+/
+/ Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+/ or visit www.oracle.com if you need additional information or have any
+/ questions.
+/
+
+        .globl fs_load
+        .globl fs_thread
+
+        // NOTE WELL!  The _Copy functions are called directly
+        // from server-compiler-generated code via CallLeafNoFP,
+        // which means that they *must* either not use floating
+        // point or use it in the same manner as does the server
+        // compiler.
+
+        .globl _Copy_arrayof_conjoint_bytes
+        .globl _Copy_conjoint_jshorts_atomic
+        .globl _Copy_arrayof_conjoint_jshorts
+        .globl _Copy_conjoint_jints_atomic
+        .globl _Copy_arrayof_conjoint_jints
+        .globl _Copy_conjoint_jlongs_atomic
+        .globl _Copy_arrayof_conjoint_jlongs
+
+        .section .text,"ax"
+
+        / Fast thread accessors, used by threadLS_solaris_amd64.cpp
+        .align   16
+fs_load:
+        movq %fs:(%rdi),%rax
+        ret
+
+        .align   16
+fs_thread:
+        movq %fs:0x0,%rax
+        ret
+
+        .globl  SpinPause
+        .align  16
+SpinPause:
+        rep
+        nop
+        movq    $1, %rax
+        ret
+
+
+        / Support for void Copy::arrayof_conjoint_bytes(void* from,
+        /                                               void* to,
+        /                                               size_t count)
+        / rdi - from
+        / rsi - to
+        / rdx - count, treated as ssize_t
+        /
+        .align   16
+_Copy_arrayof_conjoint_bytes:
+        movq     %rdx,%r8             / byte count
+        shrq     $3,%rdx              / qword count
+        cmpq     %rdi,%rsi
+        leaq     -1(%rdi,%r8,1),%rax  / from + bcount*1 - 1
+        jbe      acb_CopyRight
+        cmpq     %rax,%rsi
+        jbe      acb_CopyLeft 
+acb_CopyRight:
+        leaq     -8(%rdi,%rdx,8),%rax / from + qcount*8 - 8
+        leaq     -8(%rsi,%rdx,8),%rcx / to + qcount*8 - 8
+        negq     %rdx
+        jmp      7f
+        .align   16
+1:      movq     8(%rax,%rdx,8),%rsi
+        movq     %rsi,8(%rcx,%rdx,8)
+        addq     $1,%rdx
+        jnz      1b
+2:      testq    $4,%r8               / check for trailing dword
+        jz       3f
+        movl     8(%rax),%esi         / copy trailing dword
+        movl     %esi,8(%rcx)
+        addq     $4,%rax
+        addq     $4,%rcx              / original %rsi is trashed, so we
+                                      /  can't use it as a base register
+3:      testq    $2,%r8               / check for trailing word
+        jz       4f
+        movw     8(%rax),%si          / copy trailing word
+        movw     %si,8(%rcx)
+        addq     $2,%rcx
+4:      testq    $1,%r8               / check for trailing byte
+        jz       5f
+        movb     -1(%rdi,%r8,1),%al   / copy trailing byte
+        movb     %al,8(%rcx)
+5:      ret
+        .align   16
+6:      movq     -24(%rax,%rdx,8),%rsi
+        movq     %rsi,-24(%rcx,%rdx,8)
+        movq     -16(%rax,%rdx,8),%rsi
+        movq     %rsi,-16(%rcx,%rdx,8)
+        movq     -8(%rax,%rdx,8),%rsi
+        movq     %rsi,-8(%rcx,%rdx,8)
+        movq     (%rax,%rdx,8),%rsi
+        movq     %rsi,(%rcx,%rdx,8)
+7:      addq     $4,%rdx
+        jle      6b
+        subq     $4,%rdx
+        jl       1b
+        jmp      2b
+acb_CopyLeft:
+        testq    $1,%r8               / check for trailing byte
+        jz       1f
+        movb     -1(%rdi,%r8,1),%cl   / copy trailing byte
+        movb     %cl,-1(%rsi,%r8,1)
+        subq     $1,%r8               / adjust for possible trailing word
+1:      testq    $2,%r8               / check for trailing word
+        jz       2f
+        movw     -2(%rdi,%r8,1),%cx   / copy trailing word
+        movw     %cx,-2(%rsi,%r8,1)
+2:      testq    $4,%r8               / check for trailing dword
+        jz       5f
+        movl     (%rdi,%rdx,8),%ecx   / copy trailing dword
+        movl     %ecx,(%rsi,%rdx,8)
+        jmp      5f
+        .align   16
+3:      movq     -8(%rdi,%rdx,8),%rcx
+        movq     %rcx,-8(%rsi,%rdx,8)
+        subq     $1,%rdx
+        jnz      3b
+        ret
+        .align   16
+4:      movq     24(%rdi,%rdx,8),%rcx
+        movq     %rcx,24(%rsi,%rdx,8)
+        movq     16(%rdi,%rdx,8),%rcx
+        movq     %rcx,16(%rsi,%rdx,8)
+        movq     8(%rdi,%rdx,8),%rcx
+        movq     %rcx,8(%rsi,%rdx,8)
+        movq     (%rdi,%rdx,8),%rcx
+        movq     %rcx,(%rsi,%rdx,8)
+5:      subq     $4,%rdx
+        jge      4b
+        addq     $4,%rdx
+        jg       3b
+        ret
+
+        / Support for void Copy::arrayof_conjoint_jshorts(void* from,
+        /                                                 void* to,
+        /                                                 size_t count)
+        / Equivalent to
+        /   conjoint_jshorts_atomic
+        /
+        / If 'from' and/or 'to' are aligned on 4- or 2-byte boundaries, we
+        / let the hardware handle it.  The tow or four words within dwords
+        / or qwords that span cache line boundaries will still be loaded
+        / and stored atomically.
+        /
+        / rdi - from
+        / rsi - to
+        / rdx - count, treated as ssize_t
+        /
+        .align   16
+_Copy_arrayof_conjoint_jshorts:
+_Copy_conjoint_jshorts_atomic:
+        movq     %rdx,%r8             / word count
+        shrq     $2,%rdx              / qword count
+        cmpq     %rdi,%rsi
+        leaq     -2(%rdi,%r8,2),%rax  / from + wcount*2 - 2
+        jbe      acs_CopyRight
+        cmpq     %rax,%rsi
+        jbe      acs_CopyLeft 
+acs_CopyRight:
+        leaq     -8(%rdi,%rdx,8),%rax / from + qcount*8 - 8
+        leaq     -8(%rsi,%rdx,8),%rcx / to + qcount*8 - 8
+        negq     %rdx
+        jmp      6f
+1:      movq     8(%rax,%rdx,8),%rsi
+        movq     %rsi,8(%rcx,%rdx,8)
+        addq     $1,%rdx
+        jnz      1b
+2:      testq    $2,%r8               / check for trailing dword
+        jz       3f
+        movl     8(%rax),%esi         / copy trailing dword
+        movl     %esi,8(%rcx)
+        addq     $4,%rcx              / original %rsi is trashed, so we
+                                      /  can't use it as a base register
+3:      testq    $1,%r8               / check for trailing word
+        jz       4f
+        movw     -2(%rdi,%r8,2),%si   / copy trailing word
+        movw     %si,8(%rcx)
+4:      ret
+        .align   16
+5:      movq     -24(%rax,%rdx,8),%rsi
+        movq     %rsi,-24(%rcx,%rdx,8)
+        movq     -16(%rax,%rdx,8),%rsi
+        movq     %rsi,-16(%rcx,%rdx,8)
+        movq     -8(%rax,%rdx,8),%rsi
+        movq     %rsi,-8(%rcx,%rdx,8)
+        movq     (%rax,%rdx,8),%rsi
+        movq     %rsi,(%rcx,%rdx,8)
+6:      addq     $4,%rdx
+        jle      5b
+        subq     $4,%rdx
+        jl       1b
+        jmp      2b
+acs_CopyLeft:
+        testq    $1,%r8               / check for trailing word
+        jz       1f
+        movw     -2(%rdi,%r8,2),%cx   / copy trailing word
+        movw     %cx,-2(%rsi,%r8,2)
+1:      testq    $2,%r8               / check for trailing dword
+        jz       4f
+        movl     (%rdi,%rdx,8),%ecx   / copy trailing dword
+        movl     %ecx,(%rsi,%rdx,8)
+        jmp      4f
+2:      movq     -8(%rdi,%rdx,8),%rcx
+        movq     %rcx,-8(%rsi,%rdx,8)
+        subq     $1,%rdx
+        jnz      2b
+        ret
+        .align   16
+3:      movq     24(%rdi,%rdx,8),%rcx
+        movq     %rcx,24(%rsi,%rdx,8)
+        movq     16(%rdi,%rdx,8),%rcx
+        movq     %rcx,16(%rsi,%rdx,8)
+        movq     8(%rdi,%rdx,8),%rcx
+        movq     %rcx,8(%rsi,%rdx,8)
+        movq     (%rdi,%rdx,8),%rcx
+        movq     %rcx,(%rsi,%rdx,8)
+4:      subq     $4,%rdx
+        jge      3b
+        addq     $4,%rdx
+        jg       2b
+        ret
+
+        / Support for void Copy::arrayof_conjoint_jints(jint* from,
+        /                                               jint* to,
+        /                                               size_t count)
+        / Equivalent to
+        /   conjoint_jints_atomic
+        /
+        / If 'from' and/or 'to' are aligned on 4-byte boundaries, we let
+        / the hardware handle it.  The two dwords within qwords that span
+        / cache line boundaries will still be loaded and stored atomically.
+        /
+        / rdi - from
+        / rsi - to
+        / rdx - count, treated as ssize_t
+        /
+        .align   16
+_Copy_arrayof_conjoint_jints:
+_Copy_conjoint_jints_atomic:
+        movq     %rdx,%r8             / dword count
+        shrq     %rdx                 / qword count
+        cmpq     %rdi,%rsi
+        leaq     -4(%rdi,%r8,4),%rax  / from + dcount*4 - 4
+        jbe      aci_CopyRight
+        cmpq     %rax,%rsi
+        jbe      aci_CopyLeft 
+aci_CopyRight:
+        leaq     -8(%rdi,%rdx,8),%rax / from + qcount*8 - 8
+        leaq     -8(%rsi,%rdx,8),%rcx / to + qcount*8 - 8
+        negq     %rdx
+        jmp      5f
+        .align   16
+1:      movq     8(%rax,%rdx,8),%rsi
+        movq     %rsi,8(%rcx,%rdx,8)
+        addq     $1,%rdx
+        jnz       1b
+2:      testq    $1,%r8               / check for trailing dword
+        jz       3f
+        movl     8(%rax),%esi         / copy trailing dword
+        movl     %esi,8(%rcx)
+3:      ret
+        .align   16
+4:      movq     -24(%rax,%rdx,8),%rsi
+        movq     %rsi,-24(%rcx,%rdx,8)
+        movq     -16(%rax,%rdx,8),%rsi
+        movq     %rsi,-16(%rcx,%rdx,8)
+        movq     -8(%rax,%rdx,8),%rsi
+        movq     %rsi,-8(%rcx,%rdx,8)
+        movq     (%rax,%rdx,8),%rsi
+        movq     %rsi,(%rcx,%rdx,8)
+5:      addq     $4,%rdx
+        jle      4b
+        subq     $4,%rdx
+        jl       1b
+        jmp      2b
+aci_CopyLeft:
+        testq    $1,%r8               / check for trailing dword
+        jz       3f
+        movl     -4(%rdi,%r8,4),%ecx  / copy trailing dword
+        movl     %ecx,-4(%rsi,%r8,4)
+        jmp      3f
+1:      movq     -8(%rdi,%rdx,8),%rcx
+        movq     %rcx,-8(%rsi,%rdx,8)
+        subq     $1,%rdx
+        jnz      1b
+        ret
+        .align   16
+2:      movq     24(%rdi,%rdx,8),%rcx
+        movq     %rcx,24(%rsi,%rdx,8)
+        movq     16(%rdi,%rdx,8),%rcx
+        movq     %rcx,16(%rsi,%rdx,8)
+        movq     8(%rdi,%rdx,8),%rcx
+        movq     %rcx,8(%rsi,%rdx,8)
+        movq     (%rdi,%rdx,8),%rcx
+        movq     %rcx,(%rsi,%rdx,8)
+3:      subq     $4,%rdx
+        jge      2b
+        addq     $4,%rdx
+        jg       1b
+        ret
+
+        / Support for void Copy::arrayof_conjoint_jlongs(jlong* from,
+        /                                                jlong* to,
+        /                                                size_t count)
+        / Equivalent to
+        /   conjoint_jlongs_atomic
+        /   arrayof_conjoint_oops
+        /   conjoint_oops_atomic
+        /
+        / rdi - from
+        / rsi - to
+        / rdx - count, treated as ssize_t
+        /
+        .align   16
+_Copy_arrayof_conjoint_jlongs:
+_Copy_conjoint_jlongs_atomic:
+        cmpq     %rdi,%rsi
+        leaq     -8(%rdi,%rdx,8),%rax / from + count*8 - 8
+        jbe      acl_CopyRight
+        cmpq     %rax,%rsi
+        jbe      acl_CopyLeft 
+acl_CopyRight:
+        leaq     -8(%rsi,%rdx,8),%rcx / to + count*8 - 8
+        negq     %rdx
+        jmp      3f
+1:      movq     8(%rax,%rdx,8),%rsi
+        movq     %rsi,8(%rcx,%rdx,8)
+        addq     $1,%rdx
+        jnz      1b
+        ret
+        .align   16
+2:      movq     -24(%rax,%rdx,8),%rsi
+        movq     %rsi,-24(%rcx,%rdx,8)
+        movq     -16(%rax,%rdx,8),%rsi
+        movq     %rsi,-16(%rcx,%rdx,8)
+        movq     -8(%rax,%rdx,8),%rsi
+        movq     %rsi,-8(%rcx,%rdx,8)
+        movq     (%rax,%rdx,8),%rsi
+        movq     %rsi,(%rcx,%rdx,8)
+3:      addq     $4,%rdx
+        jle      2b
+        subq     $4,%rdx
+        jl       1b
+        ret
+4:      movq     -8(%rdi,%rdx,8),%rcx
+        movq     %rcx,-8(%rsi,%rdx,8)
+        subq     $1,%rdx
+        jnz      4b
+        ret
+        .align   16
+5:      movq     24(%rdi,%rdx,8),%rcx
+        movq     %rcx,24(%rsi,%rdx,8)
+        movq     16(%rdi,%rdx,8),%rcx
+        movq     %rcx,16(%rsi,%rdx,8)
+        movq     8(%rdi,%rdx,8),%rcx
+        movq     %rcx,8(%rsi,%rdx,8)
+        movq     (%rdi,%rdx,8),%rcx
+        movq     %rcx,(%rsi,%rdx,8)
+acl_CopyLeft:
+        subq     $4,%rdx
+        jge      5b
+        addq     $4,%rdx
+        jg       4b
+        ret
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.cpp	2024-08-17 18:29:44.551645103 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2003, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/frame.inline.hpp"
+#include "runtime/thread.inline.hpp"
+
+frame JavaThread::pd_last_frame() {
+  assert(has_last_Java_frame(), "must have last_Java_sp() when suspended");
+  vmassert(_anchor.last_Java_pc() != NULL, "not walkable");
+  return frame(_anchor.last_Java_sp(), _anchor.last_Java_fp(), _anchor.last_Java_pc());
+}
+
+// For Forte Analyzer AsyncGetCallTrace profiling support - thread is
+// currently interrupted by SIGPROF
+bool JavaThread::pd_get_top_frame_for_signal_handler(frame* fr_addr,
+  void* ucontext, bool isInJava) {
+  assert(Thread::current() == this, "caller must be current thread");
+  return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame_for_profiling(frame* fr_addr,
+  void* ucontext, bool isInJava) {
+  return pd_get_top_frame(fr_addr, ucontext, isInJava);
+}
+
+bool JavaThread::pd_get_top_frame(frame* fr_addr,
+  void* ucontext, bool isInJava) {
+  assert(this->is_Java_thread(), "must be JavaThread");
+  JavaThread* jt = (JavaThread *)this;
+
+  // There is small window where last_Java_frame is not walkable or safe
+  if (jt->has_last_Java_frame() && jt->frame_anchor()->walkable()) {
+    *fr_addr = jt->pd_last_frame();
+    return true;
+  }
+
+  ucontext_t* uc = (ucontext_t*) ucontext;
+
+  // We always want to use the initial frame we create from the ucontext as
+  // it certainly signals where we currently are. However that frame may not
+  // be safe for calling sender. In that case if we have a last_Java_frame
+  // then the forte walker will switch to that frame as the virtual sender
+  // for the frame we create here which is not sender safe.
+
+  intptr_t* ret_fp;
+  intptr_t* ret_sp;
+  address addr = os::fetch_frame_from_context(uc, &ret_sp, &ret_fp);
+
+  // Something would really have to be screwed up to get a NULL pc
+
+  if (addr == NULL) {
+    // ucontext wasn't useful
+    return false;
+  }
+
+  // If sp and fp are nonsense just leave them out
+
+  if (!jt->is_in_full_stack((address)ret_sp)) {
+    ret_sp = NULL;
+    ret_fp = NULL;
+  } else {
+    // sp is reasonable is fp reasonable?
+    if (!jt->is_in_stack_range_incl((address)ret_fp, (address)ret_sp)) {
+      ret_fp = NULL;
+    }
+  }
+
+  frame ret_frame(ret_sp, ret_fp, addr);
+
+  *fr_addr = ret_frame;
+  return true;
+
+}
+
+void JavaThread::cache_global_variables() { }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/thread_solaris_x86.hpp	2024-08-17 18:29:44.551952767 +0200
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 1999, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_THREAD_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_THREAD_SOLARIS_X86_HPP
+
+ private:
+  void pd_initialize()                           { _anchor.clear(); }
+
+  frame pd_last_frame();
+
+ public:
+
+  void set_base_of_stack_pointer(intptr_t* base_sp)  {}
+
+  static ByteSize last_Java_fp_offset()          {
+    return byte_offset_of(JavaThread, _anchor) + JavaFrameAnchor::last_Java_fp_offset();
+  }
+
+  intptr_t* base_of_stack_pointer()                  { return NULL; }
+  void record_base_of_stack_pointer()            {}
+
+  bool pd_get_top_frame_for_signal_handler(frame* fr_addr, void* ucontext,
+    bool isInJava);
+  bool pd_get_top_frame_for_profiling(frame* fr_addr, void* ucontext,
+    bool isInJava);
+private:
+  bool pd_get_top_frame(frame* fr_addr, void* ucontext,
+    bool isInJava);
+public:
+
+  // These routines are only used on cpu architectures that
+  // have separate register stacks (Itanium).
+  static bool register_stack_overflow() { return false; }
+  static void enable_register_stack_guard() {}
+  static void disable_register_stack_guard() {}
+
+#endif // OS_CPU_SOLARIS_X86_THREAD_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/vm_version_solaris_x86.cpp	2024-08-17 18:29:44.552555938 +0200
@@ -0,0 +1,28 @@
+/*
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "runtime/os.hpp"
+#include "runtime/vm_version.hpp"
+
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/os_cpu/solaris_x86/vmStructs_solaris_x86.hpp	2024-08-17 18:29:44.552261395 +0200
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2000, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP
+#define OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP
+
+// These are the OS and CPU-specific fields, types and integer
+// constants required by the Serviceability Agent. This file is
+// referenced by vmStructs.cpp.
+
+#define VM_STRUCTS_OS_CPU(nonstatic_field, static_field, unchecked_nonstatic_field, volatile_nonstatic_field, nonproduct_nonstatic_field, c2_nonstatic_field, unchecked_c1_static_field, unchecked_c2_static_field)
+
+#define VM_TYPES_OS_CPU(declare_type, declare_toplevel_type, declare_oop_type, declare_integer_type, declare_unsigned_integer_type, declare_c1_toplevel_type, declare_c2_type, declare_c2_toplevel_type)
+
+#define VM_INT_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#define VM_LONG_CONSTANTS_OS_CPU(declare_constant, declare_preprocessor_constant, declare_c1_constant, declare_c2_constant, declare_c2_preprocessor_constant)
+
+#endif // OS_CPU_SOLARIS_X86_VMSTRUCTS_SOLARIS_X86_HPP
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/c1/c1_LIR.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/c1/c1_LIR.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/c1/c1_LIR.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/c1/c1_LIR.cpp	2024-08-17 18:29:44.470695928 +0200
@@ -450,6 +450,8 @@
     case lir_monaddr:        // input and result always valid, info always invalid
     case lir_null_check:     // input and info always valid, result always invalid
     case lir_move:           // input and result always valid, may have info
+    case lir_pack64:         // input and result always valid
+    case lir_unpack64:       // input and result always valid
     {
       assert(op->as_Op1() != NULL, "must be");
       LIR_Op1* op1 = (LIR_Op1*)op;
@@ -1672,6 +1674,8 @@
      case lir_convert:               s = "convert";       break;
      case lir_alloc_object:          s = "alloc_obj";     break;
      case lir_monaddr:               s = "mon_addr";      break;
+     case lir_pack64:                s = "pack64";        break;
+     case lir_unpack64:              s = "unpack64";      break;
      // LIR_Op2
      case lir_cmp:                   s = "cmp";           break;
      case lir_cmp_l2i:               s = "cmp_l2i";       break;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/c1/c1_LIR.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/c1/c1_LIR.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/c1/c1_LIR.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/c1/c1_LIR.hpp	2024-08-17 18:29:44.471641828 +0200
@@ -939,6 +939,8 @@
       , lir_monaddr
       , lir_roundfp
       , lir_safepoint
+      , lir_pack64
+      , lir_unpack64
       , lir_unwind
       , lir_load_klass
   , end_op1
@@ -2145,6 +2147,9 @@
   void logical_or  (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_or,   left, right, dst)); }
   void logical_xor (LIR_Opr left, LIR_Opr right, LIR_Opr dst) { append(new LIR_Op2(lir_logic_xor,  left, right, dst)); }
 
+  void   pack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_pack64,   src, dst, T_LONG, lir_patch_none, NULL)); }
+  void unpack64(LIR_Opr src, LIR_Opr dst) { append(new LIR_Op1(lir_unpack64, src, dst, T_LONG, lir_patch_none, NULL)); }
+
   void null_check(LIR_Opr opr, CodeEmitInfo* info, bool deoptimize_on_null = false);
   void throw_exception(LIR_Opr exceptionPC, LIR_Opr exceptionOop, CodeEmitInfo* info) {
     append(new LIR_Op2(lir_throw, exceptionPC, exceptionOop, LIR_OprFact::illegalOpr, info));
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/cds/classListParser.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/cds/classListParser.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/cds/classListParser.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/cds/classListParser.cpp	2024-08-17 18:29:44.472268677 +0200
@@ -446,7 +446,7 @@
 // This function is used for loading classes for customized class loaders
 // during archive dumping.
 InstanceKlass* ClassListParser::load_class_from_source(Symbol* class_name, TRAPS) {
-#if !(defined(_LP64) && (defined(LINUX) || defined(__APPLE__) || defined(_WINDOWS)))
+#if !(defined(_LP64) && (defined(LINUX)|| defined(SOLARIS) || defined(__APPLE__) || defined(_WINDOWS)))
   // The only supported platforms are: (1) Linux/64-bit and (2) Solaris/64-bit and
   // (3) MacOSX/64-bit and (4) Windowss/64-bit
   // This #if condition should be in sync with the areCustomLoadersSupportedForCDS
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/abstract_vm_version.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/abstract_vm_version.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/abstract_vm_version.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/abstract_vm_version.cpp	2024-08-17 18:29:44.472925388 +0200
@@ -166,6 +166,7 @@
 
 #define OS       LINUX_ONLY("linux")             \
                  WINDOWS_ONLY("windows")         \
+                 SOLARIS_ONLY("solaris")         \
                  AIX_ONLY("aix")                 \
                  BSD_ONLY("bsd")
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/globals.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/globals.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/globals.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/globals.hpp	2024-08-17 18:29:44.474657894 +0200
@@ -682,6 +682,10 @@
   product_pd(bool, DontYieldALot,                                           \
           "Throw away obvious excess yield calls")                          \
                                                                             \
+  develop(bool, UseDetachedThreads, true,                                   \
+          "Use detached threads that are recycled upon termination "        \
+          "(for Solaris only)")                                             \
+                                                                            \
   product(bool, DisablePrimordialThreadGuardPages, false, EXPERIMENTAL,     \
                "Disable the use of stack guard pages if the JVM is loaded " \
                "on the primordial process thread")                          \
@@ -723,6 +727,10 @@
           "(Deprecated) When true prevents OS-level spurious, or premature,"\
           " wakeups from Object.wait (Ignored for Windows)")                \
                                                                             \
+  develop(bool, UsePthreads, false,                                         \
+          "Use pthread-based instead of libthread-based synchronization "   \
+          "(SPARC only)")                                                   \
+                                                                            \
   product(bool, ReduceSignalUsage, false,                                   \
           "Reduce the use of OS signals in Java and/or the VM")             \
                                                                             \
@@ -1619,8 +1627,10 @@
   product(intx, ThreadPriorityPolicy, 0,                                    \
           "0 : Normal.                                                     "\
           "    VM chooses priorities that are appropriate for normal       "\
-          "    applications.                                               "\
-          "    On Windows applications are allowed to use higher native    "\
+          "    applications. On Solaris NORM_PRIORITY and above are mapped "\
+          "    to normal native priority. Java priorities below "           \
+          "    NORM_PRIORITY map to lower native priority values. On       "\
+          "    Windows applications are allowed to use higher native       "\
           "    priorities. However, with ThreadPriorityPolicy=0, VM will   "\
           "    not use the highest possible native priority,               "\
           "    THREAD_PRIORITY_TIME_CRITICAL, as it may interfere with     "\
@@ -1969,7 +1979,8 @@
            "do not map the archive")                                        \
            range(0, 2)                                                      \
                                                                             \
-  product(size_t, ArrayAllocatorMallocLimit, (size_t)-1, EXPERIMENTAL,      \
+  product(size_t, ArrayAllocatorMallocLimit,                                \
+          SOLARIS_ONLY(64*K) NOT_SOLARIS((size_t)-1), EXPERIMENTAL,         \
           "Allocation less than this value will be allocated "              \
           "using malloc. Larger allocations will use mmap.")                \
                                                                             \
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/init.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/init.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/init.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/init.cpp	2024-08-17 18:29:44.475105865 +0200
@@ -159,6 +159,12 @@
   stubRoutines_init2(); // note: StubRoutines need 2-phase init
   MethodHandles::generate_adapters();
 
+#if INCLUDE_NMT
+  // Solaris stack is walkable only after stubRoutines are set up.
+  // On Other platforms, the stack is always walkable.
+  NMT_stack_walkable = true;
+#endif // INCLUDE_NMT
+
   // All the flags that get adjusted by VM_Version_init and os::init_2
   // have been set so dump the flags now.
   if (PrintFlagsFinal || PrintFlagsRanges) {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/os.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/os.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/os.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/os.hpp	2024-08-17 18:29:44.475760921 +0200
@@ -477,7 +477,7 @@
 
   static void free_thread(OSThread* osthread);
 
-  // thread id on Linux/64bit is 64bit, on Windows it's 32bit
+  // thread id on Linux/64bit is 64bit, on Windows and Solaris, it's 32bit
   static intx current_thread_id();
   static int current_process_id();
 
@@ -833,8 +833,10 @@
   // JVMTI & JVM monitoring and management support
   // The thread_cpu_time() and current_thread_cpu_time() are only
   // supported if is_thread_cpu_time_supported() returns true.
+  // They are not supported on Solaris T1.
 
   // Thread CPU Time - return the fast estimate on a platform
+  // On Solaris - call gethrvtime (fast) - user time only
   // On Linux   - fast clock_gettime where available - user+sys
   //            - otherwise: very slow /proc fs - user+sys
   // On Windows - GetThreadTimes - user+sys
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/semaphore.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/semaphore.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/semaphore.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/semaphore.hpp	2024-08-17 18:29:44.476162309 +0200
@@ -28,7 +28,7 @@
 #include "memory/allocation.hpp"
 #include "utilities/globalDefinitions.hpp"
 
-#if defined(LINUX) || defined(AIX)
+#if defined(LINUX) || defined(SOLARIS) || defined(AIX)
 # include "semaphore_posix.hpp"
 #elif defined(BSD)
 # include "semaphore_bsd.hpp"
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/thread.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/thread.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/runtime/thread.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/runtime/thread.cpp	2024-08-17 18:29:44.477575783 +0200
@@ -311,6 +311,12 @@
   set_stack_base(os::current_stack_base());
   set_stack_size(os::current_stack_size());
 
+#ifdef SOLARIS
+  if (os::is_primordial_thread()) {
+    os::Solaris::correct_stack_boundaries_for_primordial_thread(this);
+  }
+#endif
+
   // Set stack limits after thread is initialized.
   if (is_Java_thread()) {
     JavaThread::cast(this)->stack_overflow_state()->initialize(stack_base(), stack_end());
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/services/dtraceAttacher.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/services/dtraceAttacher.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/services/dtraceAttacher.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/services/dtraceAttacher.cpp	2024-08-17 18:29:44.552907639 +0200
@@ -0,0 +1,133 @@
+/*
+ * Copyright (c) 2006, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "precompiled.hpp"
+#include "code/codeCache.hpp"
+#include "memory/resourceArea.hpp"
+#include "runtime/deoptimization.hpp"
+#include "runtime/flags/jvmFlag.hpp"
+#include "runtime/vmThread.hpp"
+#include "runtime/vmOperations.hpp"
+#include "services/dtraceAttacher.hpp"
+#include "runtime/flags/jvmFlagAccess.hpp"
+
+#ifdef SOLARIS
+
+static void set_bool_flag(const char* name, bool value) {
+  JVMFlag* flag = JVMFlag::find_flag(name);
+  JVMFlagAccess::set_bool(flag, &value, JVMFlagOrigin::ATTACH_ON_DEMAND);
+}
+
+// Enable only the "fine grained" flags. Do *not* touch
+// the overall "ExtendedDTraceProbes" flag.
+void DTrace::enable_dprobes(int probes) {
+  bool changed = false;
+  if (!DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) {
+    set_bool_flag("DTraceAllocProbes", true);
+    changed = true;
+  }
+  if (!DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) {
+    set_bool_flag("DTraceMethodProbes", true);
+    changed = true;
+  }
+  if (!DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) {
+    set_bool_flag("DTraceMonitorProbes", true);
+    changed = true;
+  }
+
+  if (changed) {
+    // one or more flags changed, need to deoptimize
+    CodeCache::mark_all_nmethods_for_deoptimization();
+    Deoptimization::deoptimize_all_marked();
+  }
+}
+
+// Disable only the "fine grained" flags. Do *not* touch
+// the overall "ExtendedDTraceProbes" flag.
+void DTrace::disable_dprobes(int probes) {
+  bool changed = false;
+  if (DTraceAllocProbes && (probes & DTRACE_ALLOC_PROBES)) {
+    set_bool_flag("DTraceAllocProbes", false);
+    changed = true;
+  }
+  if (DTraceMethodProbes && (probes & DTRACE_METHOD_PROBES)) {
+    set_bool_flag("DTraceMethodProbes", false);
+    changed = true;
+  }
+  if (DTraceMonitorProbes && (probes & DTRACE_MONITOR_PROBES)) {
+    set_bool_flag("DTraceMonitorProbes", false);
+    changed = true;
+  }
+  if (changed) {
+    // one or more flags changed, need to deoptimize
+    CodeCache::mark_all_nmethods_for_deoptimization();
+    Deoptimization::deoptimize_all_marked();
+  }
+}
+
+// Do clean-up on "all door clients detached" event.
+void DTrace::detach_all_clients() {
+  /*
+   * We restore the state of the fine grained flags
+   * to be consistent with overall ExtendedDTraceProbes.
+   * This way, we will honour command line setting or the
+   * last explicit modification of ExtendedDTraceProbes by
+   * a call to set_extended_dprobes.
+   */
+  if (ExtendedDTraceProbes) {
+    enable_dprobes(DTRACE_ALL_PROBES);
+  } else {
+    disable_dprobes(DTRACE_ALL_PROBES);
+  }
+}
+
+void DTrace::set_extended_dprobes(bool flag) {
+  // explicit setting of ExtendedDTraceProbes flag
+  set_bool_flag("ExtendedDTraceProbes", flag);
+
+  // make sure that the fine grained flags reflect the change.
+  if (flag) {
+    enable_dprobes(DTRACE_ALL_PROBES);
+  } else {
+    /*
+     * FIXME: Revisit this: currently all-client-detach detection
+     * does not work and hence disabled. The following scheme does
+     * not work. So, we have to disable fine-grained flags here.
+     *
+     * disable_dprobes call has to be delayed till next "detach all "event.
+     * This is to be  done so that concurrent DTrace clients that may
+     * have enabled one or more fine grained dprobes and may be running
+     * still. On "detach all" clients event, we would sync ExtendedDTraceProbes
+     * with  fine grained flags which would take care of disabling fine grained flags.
+     */
+    disable_dprobes(DTRACE_ALL_PROBES);
+  }
+}
+
+void DTrace::set_monitor_dprobes(bool flag) {
+  // explicit setting of DTraceMonitorProbes flag
+  set_bool_flag("DTraceMonitorProbes", flag);
+}
+
+#endif /* SOLARIS */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/services/memTracker.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/services/memTracker.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/services/memTracker.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/services/memTracker.cpp	2024-08-17 18:29:44.478090874 +0200
@@ -46,6 +46,12 @@
 #include <windows.h>
 #endif
 
+#ifdef SOLARIS
+  volatile bool NMT_stack_walkable = false;
+#else
+  volatile bool NMT_stack_walkable = true;
+#endif
+
 volatile NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown;
 NMT_TrackingLevel MemTracker::_cmdline_tracking_level = NMT_unknown;
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/services/memTracker.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/services/memTracker.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/services/memTracker.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/services/memTracker.hpp	2024-08-17 18:29:44.478595971 +0200
@@ -87,9 +87,11 @@
 #include "services/threadStackTracker.hpp"
 #include "services/virtualMemoryTracker.hpp"
 
-#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail) ? \
+extern volatile bool NMT_stack_walkable;
+
+#define CURRENT_PC ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ? \
                     NativeCallStack(0) : NativeCallStack::empty_stack())
-#define CALLER_PC  ((MemTracker::tracking_level() == NMT_detail) ?  \
+#define CALLER_PC  ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ?  \
                     NativeCallStack(1) : NativeCallStack::empty_stack())
 
 class MemBaseline;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/debug.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/debug.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/debug.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/debug.cpp	2024-08-17 18:29:44.479276850 +0200
@@ -636,11 +636,12 @@
   tty->print_cr("  findm(intptr_t pc) - finds Method*");
   tty->print_cr("  find(intptr_t x)   - finds & prints nmethod/stub/bytecode/oop based on pointer into it");
   tty->print_cr("  pns(void* sp, void* fp, void* pc)  - print native (i.e. mixed) stack trace. E.g.");
-  tty->print_cr("                   pns($sp, $rbp, $pc) on Linux/amd64 or");
+  tty->print_cr("                   pns($sp, $rbp, $pc) on Linux/amd64 and Solaris/amd64 or");
   tty->print_cr("                   pns($sp, $ebp, $pc) on Linux/x86 or");
   tty->print_cr("                   pns($sp, $fp, $pc)  on Linux/AArch64 or");
   tty->print_cr("                   pns($sp, 0, $pc)    on Linux/ppc64 or");
   tty->print_cr("                   pns($sp, $s8, $pc)  on Linux/mips or");
+  tty->print_cr("                   pns($sp + 0x7ff, 0, $pc) on Solaris/SPARC");
   tty->print_cr("                 - in gdb do 'set overload-resolution off' before calling pns()");
   tty->print_cr("                 - in dbx do 'frame 1' before calling pns()");
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/globalDefinitions_gcc.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	2024-08-17 18:29:44.479874055 +0200
@@ -39,15 +39,36 @@
 #include <stdlib.h>
 #include <wchar.h>
 
+#ifdef SOLARIS
+#include <ieeefp.h>
+#endif // SOLARIS
+
 #include <math.h>
 #include <time.h>
 #include <fcntl.h>
 #include <dlfcn.h>
 #include <pthread.h>
 
+#ifdef SOLARIS
+#include <thread.h>
+#endif // SOLARIS
+
 #include <limits.h>
 #include <errno.h>
 
+#ifdef SOLARIS
+#include <sys/trap.h>
+#include <sys/regset.h>
+#include <sys/procset.h>
+#include <ucontext.h>
+#include <setjmp.h>
+#include <inttypes.h>
+#endif // SOLARIS
+
+# ifdef SOLARIS_MUTATOR_LIBTHREAD
+# include <sys/procfs.h>
+# endif
+
 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
 #include <inttypes.h>
 #include <signal.h>
@@ -61,6 +82,34 @@
 #include <sys/time.h>
 #endif // LINUX || _ALLBSD_SOURCE
 
+// 4810578: varargs unsafe on 32-bit integer/64-bit pointer architectures
+// When __cplusplus is defined, NULL is defined as 0 (32-bit constant) in
+// system header files.  On 32-bit architectures, there is no problem.
+// On 64-bit architectures, defining NULL as a 32-bit constant can cause
+// problems with varargs functions: C++ integral promotion rules say for
+// varargs, we pass the argument 0 as an int.  So, if NULL was passed to a
+// varargs function it will remain 32-bits.  Depending on the calling
+// convention of the machine, if the argument is passed on the stack then
+// only 32-bits of the "NULL" pointer may be initialized to zero.  The
+// other 32-bits will be garbage.  If the varargs function is expecting a
+// pointer when it extracts the argument, then we have a problem.
+//
+// Solution: For 64-bit architectures, redefine NULL as 64-bit constant 0.
+//
+// Note: this fix doesn't work well on Linux because NULL will be overwritten
+// whenever a system header file is included. Linux handles NULL correctly
+// through a special type '__null'.
+#ifdef SOLARIS
+  #ifdef _LP64
+    #undef NULL
+    #define NULL 0L
+  #else
+    #ifndef NULL
+      #define NULL 0
+    #endif
+  #endif
+#endif
+
 // NULL vs NULL_WORD:
 // On Linux NULL is defined as a special type '__null'. Assigning __null to
 // integer variable will cause gcc warning. Use NULL_WORD in places where a
@@ -108,8 +157,52 @@
 typedef uint32_t juint;
 typedef uint64_t julong;
 
+
+#ifdef SOLARIS
+// ANSI C++ fixes
+// NOTE:In the ANSI committee's continuing attempt to make each version
+// of C++ incompatible with the previous version, you can no longer cast
+// pointers to functions without specifying linkage unless you want to get
+// warnings.
+//
+// This also means that pointers to functions can no longer be "hidden"
+// in opaque types like void * because at the invocation point warnings
+// will be generated. While this makes perfect sense from a type safety
+// point of view it causes a lot of warnings on old code using C header
+// files. Here are some typedefs to make the job of silencing warnings
+// a bit easier.
+//
+// The final kick in the teeth is that you can only have extern "C" linkage
+// specified at file scope. So these typedefs are here rather than in the
+// .hpp for the class (os:Solaris usually) that needs them.
+
+extern "C" {
+   typedef int (*int_fnP_thread_t_iP_uP_stack_tP_gregset_t)(thread_t, int*, unsigned *, stack_t*, gregset_t);
+   typedef int (*int_fnP_thread_t_i_gregset_t)(thread_t, int, gregset_t);
+   typedef int (*int_fnP_thread_t_i)(thread_t, int);
+   typedef int (*int_fnP_thread_t)(thread_t);
+
+   typedef int (*int_fnP_cond_tP_mutex_tP_timestruc_tP)(cond_t *cv, mutex_t *mx, timestruc_t *abst);
+   typedef int (*int_fnP_cond_tP_mutex_tP)(cond_t *cv, mutex_t *mx);
+
+   // typedef for missing API in libc
+   typedef int (*int_fnP_mutex_tP_i_vP)(mutex_t *, int, void *);
+   typedef int (*int_fnP_mutex_tP)(mutex_t *);
+   typedef int (*int_fnP_cond_tP_i_vP)(cond_t *cv, int scope, void *arg);
+   typedef int (*int_fnP_cond_tP)(cond_t *cv);
+};
+#endif // SOLARIS
+
 // checking for nanness
-#if defined(__APPLE__)
+#ifdef SOLARIS
+#ifdef SPARC
+inline int g_isnan(float  f) { return isnanf(f); }
+#else
+// isnanf() broken on Intel Solaris use isnand()
+inline int g_isnan(float  f) { return isnand(f); }
+#endif
+inline int g_isnan(double f) { return isnand(f); }
+#elif defined(__APPLE__)
 inline int g_isnan(double f) { return isnan(f); }
 #elif defined(LINUX) || defined(_ALLBSD_SOURCE)
 inline int g_isnan(float  f) { return isnan(f); }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/macros.hpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/macros.hpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/macros.hpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/macros.hpp	2024-08-17 18:29:44.480355653 +0200
@@ -407,6 +407,14 @@
 #define NOT_AIX(code) code
 #endif
 
+#ifdef SOLARIS
+#define SOLARIS_ONLY(code) code
+#define NOT_SOLARIS(code)
+#else
+#define SOLARIS_ONLY(code)
+#define NOT_SOLARIS(code) code
+#endif
+
 #ifdef _WINDOWS
 #define WINDOWS_ONLY(code) code
 #define NOT_WINDOWS(code)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/ostream.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/ostream.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/ostream.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/ostream.cpp	2024-08-17 18:29:44.480964060 +0200
@@ -1065,7 +1065,7 @@
 
 #ifndef PRODUCT
 
-#if defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE)
+#if defined(SOLARIS) || defined(LINUX) || defined(AIX) || defined(_ALLBSD_SOURCE)
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <netinet/in.h>
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/vmError.cpp jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/vmError.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/hotspot/share/utilities/vmError.cpp	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/hotspot/share/utilities/vmError.cpp	2024-08-17 18:29:44.481864627 +0200
@@ -98,7 +98,7 @@
   "JAVA_HOME", "JAVA_TOOL_OPTIONS", "_JAVA_OPTIONS", "CLASSPATH",
   "PATH", "USERNAME",
 
-  // Env variables that are defined on Linux/BSD
+  // Env variables that are defined on Solaris/Linux/BSD
   "LD_LIBRARY_PATH", "LD_PRELOAD", "SHELL", "DISPLAY",
   "HOSTTYPE", "OSTYPE", "ARCH", "MACHTYPE",
   "LANG", "LC_ALL", "LC_CTYPE", "TZ",
@@ -1724,6 +1724,8 @@
       out.print_raw   ("#   Executing ");
 #if defined(LINUX) || defined(_ALLBSD_SOURCE)
       out.print_raw   ("/bin/sh -c ");
+#elif defined(SOLARIS)
+      out.print_raw   ("/usr/bin/sh -c ");
 #elif defined(_WINDOWS)
       out.print_raw   ("cmd /C ");
 #endif
@@ -1785,6 +1787,8 @@
     tty->print("#   Executing ");
 #if defined(LINUX)
     tty->print  ("/bin/sh -c ");
+#elif defined(SOLARIS)
+    tty->print  ("/usr/bin/sh -c ");
 #endif
     tty->print_cr("\"%s\"...", cmd);
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/classes/sun/net/sdp/SdpSupport.java jdk18u-jdk-18.0.2.1-ga/src/java.base/share/classes/sun/net/sdp/SdpSupport.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/classes/sun/net/sdp/SdpSupport.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/classes/sun/net/sdp/SdpSupport.java	2024-08-17 18:29:44.482481720 +0200
@@ -40,7 +40,7 @@
 
 public final class SdpSupport {
     private static final String os = GetPropertyAction.privilegedGetProperty("os.name");
-    private static final boolean isSupported = os.equals("Linux");
+    private static final boolean isSupported = (os.equals("SunOS") || (os.equals("Linux")));
     private static final JavaIOFileDescriptorAccess fdAccess =
         SharedSecrets.getJavaIOFileDescriptorAccess();
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/classes/sun/nio/ch/Net.java jdk18u-jdk-18.0.2.1-ga/src/java.base/share/classes/sun/nio/ch/Net.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/classes/sun/nio/ch/Net.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/classes/sun/nio/ch/Net.java	2024-08-17 18:29:44.483161624 +0200
@@ -502,7 +502,7 @@
     private static native boolean isReusePortAvailable0();
 
     /*
-     * Returns 1 for Windows and -1 for Linux/Mac OS
+     * Returns 1 for Windows and -1 for Solaris/Linux/Mac OS
      */
     private static native int isExclusiveBindAvailable();
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template jdk18u-jdk-18.0.2.1-ga/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template	2024-08-17 18:29:44.483631207 +0200
@@ -43,6 +43,8 @@
 #define SO_REUSEPORT 0
 #elif defined(__linux__)
 #define SO_REUSEPORT 15
+#elif defined(__solaris__)
+#define SO_REUSEPORT 0x100e
 #elif defined(AIX) || defined(MACOSX)
 #define SO_REUSEPORT 0x0200
 #else
@@ -50,6 +52,10 @@
 #endif
 #endif
 
+/* On Solaris, "sun" is defined as a macro. Undefine to make package
+   declaration valid */
+#undef sun
+
 /* To be able to name the Java constants the same as the C constants without
    having the preprocessor rewrite those identifiers, add PREFIX_ to all
    identifiers matching a C constant. The PREFIX_ is filtered out in the
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/conf/security/java.security jdk18u-jdk-18.0.2.1-ga/src/java.base/share/conf/security/java.security
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/conf/security/java.security	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/conf/security/java.security	2024-08-17 18:29:44.484380386 +0200
@@ -77,7 +77,11 @@
 #ifdef macosx
 security.provider.tbd=Apple
 #endif
+#ifdef solaris
+security.provider.tbd=SunPKCS11 ${java.home}/conf/security/sunpkcs11-solaris.cfg
+#else
 security.provider.tbd=SunPKCS11
+#endif
 
 #
 # A list of preferred providers for specific algorithms. These providers will
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/native/libjli/jli_util.h jdk18u-jdk-18.0.2.1-ga/src/java.base/share/native/libjli/jli_util.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/native/libjli/jli_util.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/native/libjli/jli_util.h	2024-08-17 18:29:44.484876165 +0200
@@ -100,6 +100,9 @@
 #define JLI_StrNCaseCmp(p1, p2, p3)     strncasecmp((p1), (p2), (p3))
 #define JLI_Snprintf                    snprintf
 #define JLI_Open                        open
+#ifdef __solaris__
+#define JLI_Lseek                       llseek
+#endif
 #ifdef __linux__
 #define _LARGFILE64_SOURCE
 #define JLI_Lseek                       lseek64
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/native/libnet/net_util.c jdk18u-jdk-18.0.2.1-ga/src/java.base/share/native/libnet/net_util.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/native/libnet/net_util.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/native/libnet/net_util.c	2024-08-17 18:29:44.485351293 +0200
@@ -82,6 +82,7 @@
     /* check if SO_REUSEPORT is supported on this platform */
     REUSEPORT_available = reuseport_supported();
     platformInit();
+    parseExclusiveBindProperty(env);
 
     return JNI_VERSION_1_2;
 }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/native/libnet/net_util.h jdk18u-jdk-18.0.2.1-ga/src/java.base/share/native/libnet/net_util.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/share/native/libnet/net_util.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/share/native/libnet/net_util.h	2024-08-17 18:29:44.485767821 +0200
@@ -147,6 +147,8 @@
 
 void platformInit();
 
+void parseExclusiveBindProperty(JNIEnv *env);
+
 JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(SOCKETADDRESS *sa);
 
 JNIEXPORT jboolean JNICALL
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	2024-08-17 18:29:44.553461047 +0200
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+
+/**
+ * Creates this platform's default AsynchronousChannelProvider
+ */
+
+public class DefaultAsynchronousChannelProvider {
+
+    /**
+     * Prevent instantiation.
+     */
+    private DefaultAsynchronousChannelProvider() { }
+
+    /**
+     * Returns the default AsynchronousChannelProvider.
+     */
+    public static AsynchronousChannelProvider create() {
+        return new SolarisAsynchronousChannelProvider();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java	2024-08-17 18:29:44.553791419 +0200
@@ -0,0 +1,54 @@
+/*
+ * Copyright (c) 2015, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+
+/**
+ * Creates this platform's default SelectorProvider
+ */
+
+@SuppressWarnings("removal")
+public class DefaultSelectorProvider {
+    private static final SelectorProviderImpl INSTANCE;
+    static {
+        PrivilegedAction<SelectorProviderImpl> pa = DevPollSelectorProvider::new;
+        INSTANCE = AccessController.doPrivileged(pa);
+    }
+
+    /**
+     * Prevent instantiation.
+     */
+    private DefaultSelectorProvider() { }
+
+    /**
+     * Returns the default SelectorProvider implementation.
+     */
+    public static SelectorProviderImpl get() {
+        return INSTANCE;
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	2024-08-17 18:29:44.554147678 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+
+/**
+ * Manipulates a native array of pollfd structs on Solaris:
+ *
+ * typedef struct pollfd {
+ *    int fd;
+ *    short events;
+ *    short revents;
+ * } pollfd_t;
+ *
+ * @author Mike McCloskey
+ * @since 1.4
+ */
+
+class DevPollArrayWrapper {
+
+    // special event to remove a file descriptor from the driver
+    static final short POLLREMOVE   = 0x0800;
+
+    // struct pollfd constants
+    static final short SIZE_POLLFD   = 8;
+    static final short FD_OFFSET     = 0;
+    static final short EVENT_OFFSET  = 4;
+    static final short REVENT_OFFSET = 6;
+
+    // maximum number of pollfd structure to poll or update at a time
+    // dpwrite/ioctl(DP_POLL) allows up to file descriptor limit minus 1
+    static final int NUM_POLLFDS = Math.min(IOUtil.fdLimit()-1, 1024);
+
+    // The pollfd array for results from devpoll driver
+    private final AllocatedNativeObject pollArray;
+
+    // Base address of the native pollArray
+    private final long pollArrayAddress;
+
+    // The fd of the devpoll driver
+    private int wfd;
+
+    DevPollArrayWrapper() throws IOException {
+        this.wfd = init();
+
+        int allocationSize = NUM_POLLFDS * SIZE_POLLFD;
+        this.pollArray = new AllocatedNativeObject(allocationSize, true);
+        this.pollArrayAddress = pollArray.address();
+    }
+
+    void close() throws IOException {
+        FileDispatcherImpl.closeIntFD(wfd);
+        pollArray.free();
+    }
+
+    void register(int fd, int ops) throws IOException {
+        register(wfd, fd, ops);
+    }
+
+    void registerMultiple(int numfds) throws IOException {
+        registerMultiple(wfd, pollArrayAddress, numfds);
+    }
+
+    int poll(long timeout) throws IOException {
+        return poll0(pollArrayAddress, NUM_POLLFDS, timeout, wfd);
+    }
+
+    int getDescriptor(int i) {
+        int offset = SIZE_POLLFD * i + FD_OFFSET;
+        return pollArray.getInt(offset);
+    }
+
+    short getEventOps(int i) {
+        int offset = SIZE_POLLFD * i + EVENT_OFFSET;
+        return pollArray.getShort(offset);
+    }
+
+    short getReventOps(int i) {
+        int offset = SIZE_POLLFD * i + REVENT_OFFSET;
+        return pollArray.getShort(offset);
+    }
+
+    /**
+     * Updates the pollfd structure at the given index
+     */
+    void putPollFD(int index, int fd, short event) {
+        int structIndex = SIZE_POLLFD * index;
+        pollArray.putInt(structIndex + FD_OFFSET, fd);
+        pollArray.putShort(structIndex + EVENT_OFFSET, event);
+        pollArray.putShort(structIndex + REVENT_OFFSET, (short)0);
+    }
+
+    private native int init() throws IOException;
+    private native void register(int wfd, int fd, int mask) throws IOException;
+    private native void registerMultiple(int wfd, long address, int len)
+        throws IOException;
+    private native int poll0(long pollAddress, int numfds, long timeout, int wfd)
+        throws IOException;
+
+    static {
+        IOUtil.load();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	2024-08-17 18:29:44.554587509 +0200
@@ -0,0 +1,263 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import static sun.nio.ch.DevPollArrayWrapper.NUM_POLLFDS;
+import static sun.nio.ch.DevPollArrayWrapper.POLLREMOVE;
+
+/**
+ * Solaris /dev/poll based Selector implementation
+ */
+
+class DevPollSelectorImpl
+    extends SelectorImpl
+{
+    // provides access to /dev/poll driver
+    private final DevPollArrayWrapper pollWrapper;
+
+    // file descriptors used for interrupt
+    private final int fd0;
+    private final int fd1;
+
+    // maps file descriptor to selection key, synchronize on selector
+    private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
+
+    // pending new registrations/updates, queued by setEventOps
+    private final Object updateLock = new Object();
+    private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+
+    // interrupt triggering and clearing
+    private final Object interruptLock = new Object();
+    private boolean interruptTriggered;
+
+    DevPollSelectorImpl(SelectorProvider sp) throws IOException {
+        super(sp);
+        this.pollWrapper = new DevPollArrayWrapper();
+        try {
+            long fds = IOUtil.makePipe(false);
+            this.fd0 = (int) (fds >>> 32);
+            this.fd1 = (int) fds;
+        } catch (IOException ioe) {
+            pollWrapper.close();
+            throw ioe;
+        }
+
+        // register one end of the socket pair for wakeups
+        pollWrapper.register(fd0, Net.POLLIN);
+    }
+
+    private void ensureOpen() {
+        if (!isOpen())
+            throw new ClosedSelectorException();
+    }
+
+    @Override
+    protected int doSelect(Consumer<SelectionKey> action, long timeout)
+        throws IOException
+    {
+        assert Thread.holdsLock(this);
+
+        long to = timeout;
+        boolean blocking = (to != 0);
+        boolean timedPoll = (to > 0);
+
+        int numEntries;
+        processUpdateQueue();
+        processDeregisterQueue();
+        try {
+            begin(blocking);
+
+            do {
+                long startTime = timedPoll ? System.nanoTime() : 0;
+                numEntries = pollWrapper.poll(to);
+                if (numEntries == IOStatus.INTERRUPTED && timedPoll) {
+                    // timed poll interrupted so need to adjust timeout
+                    long adjust = System.nanoTime() - startTime;
+                    to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
+                    if (to <= 0) {
+                        // timeout expired so no retry
+                        numEntries = 0;
+                    }
+                }
+            } while (numEntries == IOStatus.INTERRUPTED);
+            assert IOStatus.check(numEntries);
+
+        } finally {
+            end(blocking);
+        }
+        processDeregisterQueue();
+        return processEvents(numEntries, action);
+    }
+
+    /**
+     * Process changes to the interest ops.
+     */
+    private void processUpdateQueue() throws IOException {
+        assert Thread.holdsLock(this);
+
+        synchronized (updateLock) {
+            SelectionKeyImpl ski;
+
+            // Translate the queued updates to changes to the set of monitored
+            // file descriptors. The changes are written to the /dev/poll driver
+            // in bulk.
+            int index = 0;
+            while ((ski = updateKeys.pollFirst()) != null) {
+                if (ski.isValid()) {
+                    int fd = ski.getFDVal();
+                    // add to fdToKey if needed
+                    SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+                    assert (previous == null) || (previous == ski);
+
+                    int newEvents = ski.translateInterestOps();
+                    int registeredEvents = ski.registeredEvents();
+                    if (newEvents != registeredEvents) {
+                        if (registeredEvents != 0)
+                            pollWrapper.putPollFD(index++, fd, POLLREMOVE);
+                        if (newEvents != 0)
+                            pollWrapper.putPollFD(index++, fd, (short)newEvents);
+                        ski.registeredEvents(newEvents);
+
+                        // write to /dev/poll
+                        if (index > (NUM_POLLFDS-2)) {
+                            pollWrapper.registerMultiple(index);
+                            index = 0;
+                        }
+                    }
+                }
+            }
+
+            // write any remaining changes
+            if (index > 0)
+                pollWrapper.registerMultiple(index);
+        }
+    }
+
+    /**
+     * Process the polled events.
+     * If the interrupt fd has been selected, drain it and clear the interrupt.
+     */
+    private int processEvents(int numEntries, Consumer<SelectionKey> action)
+        throws IOException
+    {
+        assert Thread.holdsLock(this);
+
+        boolean interrupted = false;
+        int numKeysUpdated = 0;
+        for (int i=0; i<numEntries; i++) {
+            int fd = pollWrapper.getDescriptor(i);
+            if (fd == fd0) {
+                interrupted = true;
+            } else {
+                SelectionKeyImpl ski = fdToKey.get(fd);
+                if (ski != null) {
+                    int rOps = pollWrapper.getReventOps(i);
+                    numKeysUpdated += processReadyEvents(rOps, ski, action);
+                }
+            }
+        }
+
+        if (interrupted) {
+            clearInterrupt();
+        }
+
+        return numKeysUpdated;
+    }
+
+    @Override
+    protected void implClose() throws IOException {
+        assert !isOpen();
+        assert Thread.holdsLock(this);
+
+        // prevent further wakeup
+        synchronized (interruptLock) {
+            interruptTriggered = true;
+        }
+
+        pollWrapper.close();
+        FileDispatcherImpl.closeIntFD(fd0);
+        FileDispatcherImpl.closeIntFD(fd1);
+    }
+
+
+    @Override
+    protected void implDereg(SelectionKeyImpl ski) throws IOException {
+        assert !ski.isValid();
+        assert Thread.holdsLock(this);
+
+        int fd = ski.getFDVal();
+        if (fdToKey.remove(fd) != null) {
+            if (ski.registeredEvents() != 0) {
+                pollWrapper.register(fd, POLLREMOVE);
+                ski.registeredEvents(0);
+            }
+        } else {
+            assert ski.registeredEvents() == 0;
+        }
+    }
+
+    @Override
+    public void setEventOps(SelectionKeyImpl ski) {
+        ensureOpen();
+        synchronized (updateLock) {
+            updateKeys.addLast(ski);
+        }
+    }
+
+    @Override
+    public Selector wakeup() {
+        synchronized (interruptLock) {
+            if (!interruptTriggered) {
+                try {
+                    IOUtil.write1(fd1, (byte)0);
+                } catch (IOException ioe) {
+                    throw new InternalError(ioe);
+                }
+                interruptTriggered = true;
+            }
+        }
+        return this;
+    }
+
+    private void clearInterrupt() throws IOException {
+        synchronized (interruptLock) {
+            IOUtil.drain(fd0);
+            interruptTriggered = false;
+        }
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java	2024-08-17 18:29:44.554896033 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2001, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.*;
+import java.nio.channels.spi.*;
+
+public class DevPollSelectorProvider
+    extends SelectorProviderImpl
+{
+    public AbstractSelector openSelector() throws IOException {
+        return new DevPollSelectorImpl(this);
+    }
+
+    public Channel inheritedChannel() throws IOException {
+        return InheritedChannel.getChannel();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	2024-08-17 18:29:44.555347064 +0200
@@ -0,0 +1,308 @@
+/*
+ * Copyright (c) 2012, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.ClosedSelectorException;
+import java.nio.channels.SelectionKey;
+import java.nio.channels.Selector;
+import java.nio.channels.spi.SelectorProvider;
+import java.util.ArrayDeque;
+import java.util.Deque;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.concurrent.TimeUnit;
+import java.util.function.Consumer;
+
+import static sun.nio.ch.SolarisEventPort.PORT_SOURCE_FD;
+import static sun.nio.ch.SolarisEventPort.PORT_SOURCE_USER;
+import static sun.nio.ch.SolarisEventPort.SIZEOF_PORT_EVENT;
+import static sun.nio.ch.SolarisEventPort.OFFSETOF_EVENTS;
+import static sun.nio.ch.SolarisEventPort.OFFSETOF_SOURCE;
+import static sun.nio.ch.SolarisEventPort.OFFSETOF_OBJECT;
+import static sun.nio.ch.SolarisEventPort.port_create;
+import static sun.nio.ch.SolarisEventPort.port_close;
+import static sun.nio.ch.SolarisEventPort.port_associate;
+import static sun.nio.ch.SolarisEventPort.port_dissociate;
+import static sun.nio.ch.SolarisEventPort.port_getn;
+import static sun.nio.ch.SolarisEventPort.port_send;
+
+/**
+ * Selector implementation based on the Solaris event port mechanism.
+ */
+
+class EventPortSelectorImpl
+    extends SelectorImpl
+{
+    // maximum number of events to retrive in one call to port_getn
+    static final int MAX_EVENTS = Math.min(IOUtil.fdLimit()-1, 1024);
+
+    // port file descriptor
+    private final int pfd;
+
+    // the poll array (populated by port_getn)
+    private final long pollArrayAddress;
+    private final AllocatedNativeObject pollArray;
+
+    // maps file descriptor to selection key, synchronize on selector
+    private final Map<Integer, SelectionKeyImpl> fdToKey = new HashMap<>();
+
+    // the last update operation, incremented by processUpdateQueue
+    private int lastUpdate;
+
+    // pending new registrations/updates, queued by setEventOps and
+    // updateSelectedKeys
+    private final Object updateLock = new Object();
+    private final Deque<SelectionKeyImpl> updateKeys = new ArrayDeque<>();
+
+    // interrupt triggering and clearing
+    private final Object interruptLock = new Object();
+    private boolean interruptTriggered;
+
+    EventPortSelectorImpl(SelectorProvider sp) throws IOException {
+        super(sp);
+
+        this.pfd = port_create();
+
+        int allocationSize = MAX_EVENTS * SIZEOF_PORT_EVENT;
+        this.pollArray = new AllocatedNativeObject(allocationSize, false);
+        this.pollArrayAddress = pollArray.address();
+    }
+
+    private void ensureOpen() {
+        if (!isOpen())
+            throw new ClosedSelectorException();
+    }
+
+    @Override
+    protected int doSelect(Consumer<SelectionKey> action, long timeout)
+        throws IOException
+    {
+        assert Thread.holdsLock(this);
+
+        long to = timeout;
+        boolean blocking = (to != 0);
+        boolean timedPoll = (to > 0);
+
+        int numEvents;
+        processUpdateQueue();
+        processDeregisterQueue();
+        try {
+            begin(blocking);
+
+            do {
+                long startTime = timedPoll ? System.nanoTime() : 0;
+                numEvents = port_getn(pfd, pollArrayAddress, MAX_EVENTS, to);
+                if (numEvents == IOStatus.INTERRUPTED && timedPoll) {
+                    // timed poll interrupted so need to adjust timeout
+                    long adjust = System.nanoTime() - startTime;
+                    to -= TimeUnit.MILLISECONDS.convert(adjust, TimeUnit.NANOSECONDS);
+                    if (to <= 0) {
+                        // timeout also expired so no retry
+                        numEvents = 0;
+                    }
+                }
+            } while (numEvents == IOStatus.INTERRUPTED);
+            assert IOStatus.check(numEvents);
+
+        } finally {
+            end(blocking);
+        }
+        processDeregisterQueue();
+        return processPortEvents(numEvents, action);
+    }
+
+    /**
+     * Process new registrations and changes to the interest ops.
+     */
+    private void processUpdateQueue() throws IOException {
+        assert Thread.holdsLock(this);
+
+        // bump lastUpdate to ensure that the interest ops are changed at most
+        // once per bulk update
+        lastUpdate++;
+
+        synchronized (updateLock) {
+            SelectionKeyImpl ski;
+            while ((ski = updateKeys.pollFirst()) != null) {
+                if (ski.isValid()) {
+                    int fd = ski.getFDVal();
+                    // add to fdToKey if needed
+                    SelectionKeyImpl previous = fdToKey.putIfAbsent(fd, ski);
+                    assert (previous == null) || (previous == ski);
+
+                    int newEvents = ski.translateInterestOps();
+                    if (newEvents != ski.registeredEvents()) {
+                        if (newEvents == 0) {
+                            port_dissociate(pfd, PORT_SOURCE_FD, fd);
+                        } else {
+                            port_associate(pfd, PORT_SOURCE_FD, fd, newEvents);
+                        }
+                        ski.registeredEvents(newEvents);
+                    }
+                }
+            }
+        }
+    }
+
+    /**
+     * Process the polled events and re-queue the selected keys so the file
+     * descriptors are re-associated at the next select operation.
+     */
+    private int processPortEvents(int numEvents, Consumer<SelectionKey> action)
+        throws IOException
+    {
+        assert Thread.holdsLock(this);
+
+        int numKeysUpdated = 0;
+        boolean interrupted = false;
+
+        // Process the polled events while holding the update lock. This allows
+        // keys to be queued for ready file descriptors so they can be
+        // re-associated at the next select. The selected-key can be updated
+        // in this pass.
+        synchronized (updateLock) {
+            for (int i = 0; i < numEvents; i++) {
+                short source = getSource(i);
+                if (source == PORT_SOURCE_FD) {
+                    int fd = getDescriptor(i);
+                    SelectionKeyImpl ski = fdToKey.get(fd);
+                    if (ski != null) {
+                        ski.registeredEvents(0);
+                        updateKeys.addLast(ski);
+
+                        // update selected-key set if no action specified
+                        if (action == null) {
+                            int rOps = getEventOps(i);
+                            numKeysUpdated += processReadyEvents(rOps, ski, null);
+                        }
+
+                    }
+                } else if (source == PORT_SOURCE_USER) {
+                    interrupted = true;
+                } else {
+                    assert false;
+                }
+            }
+        }
+
+        // if an action specified then iterate over the polled events again so
+        // that the action is performed without holding the update lock.
+        if (action != null) {
+            for (int i = 0; i < numEvents; i++) {
+                short source = getSource(i);
+                if (source == PORT_SOURCE_FD) {
+                    int fd = getDescriptor(i);
+                    SelectionKeyImpl ski = fdToKey.get(fd);
+                    if (ski != null) {
+                        int rOps = getEventOps(i);
+                        numKeysUpdated += processReadyEvents(rOps, ski, action);
+                    }
+                }
+            }
+        }
+
+        if (interrupted) {
+            clearInterrupt();
+        }
+        return numKeysUpdated;
+    }
+
+    @Override
+    protected void implClose() throws IOException {
+        assert !isOpen();
+        assert Thread.holdsLock(this);
+
+        // prevent further wakeup
+        synchronized (interruptLock) {
+            interruptTriggered = true;
+        }
+
+        port_close(pfd);
+        pollArray.free();
+    }
+
+    @Override
+    protected void implDereg(SelectionKeyImpl ski) throws IOException {
+        assert !ski.isValid();
+        assert Thread.holdsLock(this);
+
+        int fd = ski.getFDVal();
+        if (fdToKey.remove(fd) != null) {
+            if (ski.registeredEvents() != 0) {
+                port_dissociate(pfd, PORT_SOURCE_FD, fd);
+                ski.registeredEvents(0);
+            }
+        } else {
+            assert ski.registeredEvents() == 0;
+        }
+    }
+
+    @Override
+    public void setEventOps(SelectionKeyImpl ski) {
+        ensureOpen();
+        synchronized (updateLock) {
+            updateKeys.addLast(ski);
+        }
+    }
+
+    @Override
+    public Selector wakeup() {
+        synchronized (interruptLock) {
+            if (!interruptTriggered) {
+                try {
+                    port_send(pfd, 0);
+                } catch (IOException ioe) {
+                    throw new InternalError(ioe);
+                }
+                interruptTriggered = true;
+            }
+        }
+        return this;
+    }
+
+    private void clearInterrupt() throws IOException {
+        synchronized (interruptLock) {
+            interruptTriggered = false;
+        }
+    }
+
+    private short getSource(int i) {
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_SOURCE;
+        return pollArray.getShort(offset);
+    }
+
+    private int getEventOps(int i) {
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_EVENTS;
+        return pollArray.getInt(offset);
+    }
+
+    private int getDescriptor(int i) {
+        //assert Unsafe.getUnsafe().addressSize() == 8;
+        int offset = SIZEOF_PORT_EVENT * i + OFFSETOF_OBJECT;
+        return (int) pollArray.getLong(offset);
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java	2024-08-17 18:29:44.555658856 +0200
@@ -0,0 +1,42 @@
+/*
+ * Copyright (c) 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.io.IOException;
+import java.nio.channels.*;
+import java.nio.channels.spi.*;
+
+public class EventPortSelectorProvider
+    extends SelectorProviderImpl
+{
+    public AbstractSelector openSelector() throws IOException {
+        return new EventPortSelectorImpl(this);
+    }
+
+    public Channel inheritedChannel() throws IOException {
+        return InheritedChannel.getChannel();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	2024-08-17 18:29:44.556005931 +0200
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.*;
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.ThreadFactory;
+import java.io.IOException;
+
+public class SolarisAsynchronousChannelProvider
+    extends AsynchronousChannelProvider
+{
+    private static volatile SolarisEventPort defaultEventPort;
+
+    private SolarisEventPort defaultEventPort() throws IOException {
+        if (defaultEventPort == null) {
+            synchronized (SolarisAsynchronousChannelProvider.class) {
+                if (defaultEventPort == null) {
+                    defaultEventPort =
+                        new SolarisEventPort(this, ThreadPool.getDefault()).start();
+                }
+            }
+        }
+        return defaultEventPort;
+    }
+
+    public SolarisAsynchronousChannelProvider() {
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(int nThreads, ThreadFactory factory)
+        throws IOException
+    {
+        return new SolarisEventPort(this, ThreadPool.create(nThreads, factory)).start();
+    }
+
+    @Override
+    public AsynchronousChannelGroup openAsynchronousChannelGroup(ExecutorService executor, int initialSize)
+        throws IOException
+    {
+        return new SolarisEventPort(this, ThreadPool.wrap(executor, initialSize)).start();
+    }
+
+    private SolarisEventPort toEventPort(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        if (group == null) {
+            return defaultEventPort();
+        } else {
+            if (!(group instanceof SolarisEventPort))
+                throw new IllegalChannelGroupException();
+            return (SolarisEventPort)group;
+        }
+    }
+
+    @Override
+    public AsynchronousServerSocketChannel openAsynchronousServerSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new UnixAsynchronousServerSocketChannelImpl(toEventPort(group));
+    }
+
+    @Override
+    public AsynchronousSocketChannel openAsynchronousSocketChannel(AsynchronousChannelGroup group)
+        throws IOException
+    {
+        return new UnixAsynchronousSocketChannelImpl(toEventPort(group));
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java	2024-08-17 18:29:44.556431676 +0200
@@ -0,0 +1,268 @@
+/*
+ * Copyright (c) 2008, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.ch;
+
+import java.nio.channels.spi.AsynchronousChannelProvider;
+import java.util.concurrent.RejectedExecutionException;
+import java.io.IOException;
+import jdk.internal.misc.Unsafe;
+
+/**
+ * Provides an AsynchronousChannelGroup implementation based on the Solaris 10
+ * event port framework and also provides direct access to that framework.
+ */
+
+class SolarisEventPort
+    extends Port
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static final int addressSize = unsafe.addressSize();
+
+    private static int dependsArch(int value32, int value64) {
+        return (addressSize == 4) ? value32 : value64;
+    }
+
+    /*
+     * typedef struct port_event {
+     *     int             portev_events;
+     *     ushort_t        portev_source;
+     *     ushort_t        portev_pad;
+     *     uintptr_t       portev_object;
+     *     void            *portev_user;
+     * } port_event_t;
+     */
+    static final int SIZEOF_PORT_EVENT  = dependsArch(16, 24);
+    static final int OFFSETOF_EVENTS    = 0;
+    static final int OFFSETOF_SOURCE    = 4;
+    static final int OFFSETOF_OBJECT    = 8;
+
+    // port sources
+    static final short PORT_SOURCE_USER     = 3;
+    static final short PORT_SOURCE_FD       = 4;
+
+    // file descriptor to event port.
+    private final int port;
+
+    // true when port is closed
+    private boolean closed;
+
+    SolarisEventPort(AsynchronousChannelProvider provider, ThreadPool pool)
+        throws IOException
+    {
+        super(provider, pool);
+
+        // create event port
+        this.port = port_create();
+    }
+
+    SolarisEventPort start() {
+        startThreads(new EventHandlerTask());
+        return this;
+    }
+
+    // releass resources
+    private void implClose() {
+        synchronized (this) {
+            if (closed)
+                return;
+            closed = true;
+        }
+        port_close(port);
+    }
+
+    private void wakeup() {
+        try {
+            port_send(port, 0);
+        } catch (IOException x) {
+            throw new AssertionError(x);
+        }
+    }
+
+    @Override
+    void executeOnHandlerTask(Runnable task) {
+        synchronized (this) {
+            if (closed)
+                throw new RejectedExecutionException();
+            offerTask(task);
+            wakeup();
+        }
+    }
+
+    @Override
+    void shutdownHandlerTasks() {
+        /*
+         * If no tasks are running then just release resources; otherwise
+         * write to the one end of the socketpair to wakeup any polling threads..
+         */
+        int nThreads = threadCount();
+        if (nThreads == 0) {
+            implClose();
+        } else {
+            // send user event to wakeup each thread
+            while (nThreads-- > 0) {
+                try {
+                    port_send(port, 0);
+                } catch (IOException x) {
+                    throw new AssertionError(x);
+                }
+            }
+        }
+    }
+
+    @Override
+    void startPoll(int fd, int events) {
+        // (re-)associate file descriptor
+        // no need to translate events
+        try {
+            port_associate(port, PORT_SOURCE_FD, fd, events);
+        } catch (IOException x) {
+            throw new AssertionError();     // should not happen
+        }
+    }
+
+    /*
+     * Task to read a single event from the port and dispatch it to the
+     * channel's onEvent handler.
+     */
+    private class EventHandlerTask implements Runnable {
+        public void run() {
+            Invoker.GroupAndInvokeCount myGroupAndInvokeCount =
+                Invoker.getGroupAndInvokeCount();
+            final boolean isPooledThread = (myGroupAndInvokeCount != null);
+            boolean replaceMe = false;
+            long address = unsafe.allocateMemory(SIZEOF_PORT_EVENT);
+            try {
+                for (;;) {
+                    // reset invoke count
+                    if (isPooledThread)
+                        myGroupAndInvokeCount.resetInvokeCount();
+
+                    // wait for I/O completion event
+                    // A error here is fatal (thread will not be replaced)
+                    replaceMe = false;
+                    try {
+                        int n;
+                        do {
+                            n = port_get(port, address);
+                        } while (n == IOStatus.INTERRUPTED);
+                    } catch (IOException x) {
+                        x.printStackTrace();
+                        return;
+                    }
+
+                    // event source
+                    short source = unsafe.getShort(address + OFFSETOF_SOURCE);
+                    if (source != PORT_SOURCE_FD) {
+                        // user event is trigger to invoke task or shutdown
+                        if (source == PORT_SOURCE_USER) {
+                            Runnable task = pollTask();
+                            if (task == null) {
+                                // shutdown request
+                                return;
+                            }
+                            // run task (may throw error/exception)
+                            replaceMe = true;
+                            task.run();
+                        }
+                        // ignore
+                        continue;
+                    }
+
+                    // pe->portev_object is file descriptor
+                    int fd = (int)unsafe.getAddress(address + OFFSETOF_OBJECT);
+                    // pe->portev_events
+                    int events = unsafe.getInt(address + OFFSETOF_EVENTS);
+
+                    // lookup channel
+                    PollableChannel ch;
+                    fdToChannelLock.readLock().lock();
+                    try {
+                        ch = fdToChannel.get(fd);
+                    } finally {
+                        fdToChannelLock.readLock().unlock();
+                    }
+
+                    // notify channel
+                    if (ch != null) {
+                        replaceMe = true;
+                        // no need to translate events
+                        ch.onEvent(events, isPooledThread);
+                    }
+                }
+            } finally {
+                // free per-thread resources
+                unsafe.freeMemory(address);
+                // last task to exit when shutdown release resources
+                int remaining = threadExit(this, replaceMe);
+                if (remaining == 0 && isShutdown())
+                    implClose();
+            }
+        }
+    }
+
+    /**
+     * Creates an event port
+     */
+    static native int port_create() throws IOException;
+
+    /**
+     * Associates specific events of a given object with a port
+     */
+    static native boolean port_associate(int port, int source, long object, int events)
+        throws IOException;
+
+    /**
+     * Removes the association of an object with a port.
+     */
+    static native boolean port_dissociate(int port, int source, long object)
+        throws IOException;
+
+    /**
+     * Retrieves a single event from a port
+     */
+    static native int port_get(int port, long address) throws IOException;
+
+    /**
+     * Retrieves at most {@code max} events from a port.
+     */
+    static native int port_getn(int port, long address, int max, long timeout)
+        throws IOException;
+
+    /**
+     * Sends a user-defined eventto a specified  port.
+     */
+    static native void port_send(int port, int events) throws IOException;
+
+    /**
+     * Closes a port.
+     */
+    static native void port_close(int port);
+
+
+    static {
+        IOUtil.load();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java	2024-08-17 18:29:44.556832840 +0200
@@ -0,0 +1,53 @@
+/*
+ * Copyright (c) 2017, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.FileSystem;
+
+/**
+ * Creates this platform's default FileSystemProvider.
+ */
+
+public class DefaultFileSystemProvider {
+    private static final SolarisFileSystemProvider INSTANCE
+        = new SolarisFileSystemProvider();
+
+    private DefaultFileSystemProvider() { }
+
+    /**
+     * Returns the platform's default file system provider.
+     */
+    public static SolarisFileSystemProvider instance() {
+        return INSTANCE;
+    }
+
+    /**
+     * Returns the platform's default file system.
+     */
+    public static FileSystem theFileSystem() {
+        return INSTANCE.theFileSystem();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	2024-08-17 18:29:44.557562340 +0200
@@ -0,0 +1,414 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.util.*;
+import java.io.IOException;
+import jdk.internal.misc.Unsafe;
+
+import static sun.nio.fs.UnixConstants.*;
+import static sun.nio.fs.SolarisConstants.*;
+import static sun.nio.fs.SolarisNativeDispatcher.*;
+
+
+/**
+ * Solaris implementation of AclFileAttributeView with native support for
+ * NFSv4 ACLs on ZFS.
+ */
+
+class SolarisAclFileAttributeView
+    extends AbstractAclFileAttributeView
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+
+    // Maximum number of entries allowed in an ACL
+    private static final int MAX_ACL_ENTRIES = 1024;
+
+    /**
+     * typedef struct ace {
+     *     uid_t        a_who;
+     *     uint32_t     a_access_mask;
+     *     uint16_t     a_flags;
+     *     uint16_t     a_type;
+     * } ace_t;
+     */
+    private static final short SIZEOF_ACE_T     = 12;
+    private static final short OFFSETOF_UID     = 0;
+    private static final short OFFSETOF_MASK    = 4;
+    private static final short OFFSETOF_FLAGS   = 8;
+    private static final short OFFSETOF_TYPE    = 10;
+
+    private final UnixPath file;
+    private final boolean followLinks;
+
+    SolarisAclFileAttributeView(UnixPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    /**
+     * Permission checks to access file
+     */
+    private void checkAccess(UnixPath file,
+                             boolean checkRead,
+                             boolean checkWrite)
+    {
+        @SuppressWarnings("removal")
+        SecurityManager sm = System.getSecurityManager();
+        if (sm != null) {
+            if (checkRead)
+                file.checkRead();
+            if (checkWrite)
+                file.checkWrite();
+            sm.checkPermission(new RuntimePermission("accessUserInformation"));
+        }
+    }
+
+    /**
+     * Encode the ACL to the given buffer
+     */
+    private static void encode(List<AclEntry> acl, long address) {
+        long offset = address;
+        for (AclEntry ace: acl) {
+            int flags = 0;
+
+            // map UserPrincipal to uid and flags
+            UserPrincipal who = ace.principal();
+            if (!(who instanceof UnixUserPrincipals.User))
+                throw new ProviderMismatchException();
+            UnixUserPrincipals.User user = (UnixUserPrincipals.User)who;
+            int uid;
+            if (user.isSpecial()) {
+                uid = -1;
+                if (who == UnixUserPrincipals.SPECIAL_OWNER)
+                    flags |= ACE_OWNER;
+                else if (who == UnixUserPrincipals.SPECIAL_GROUP)
+                    flags |= (ACE_GROUP | ACE_IDENTIFIER_GROUP);
+                else if (who == UnixUserPrincipals.SPECIAL_EVERYONE)
+                    flags |= ACE_EVERYONE;
+                else
+                    throw new AssertionError("Unable to map special identifier");
+            } else {
+                if (user instanceof UnixUserPrincipals.Group) {
+                    uid = user.gid();
+                    flags |= ACE_IDENTIFIER_GROUP;
+                } else {
+                    uid = user.uid();
+                }
+            }
+
+            // map ACE type
+            int type;
+            switch (ace.type()) {
+                case ALLOW:
+                    type = ACE_ACCESS_ALLOWED_ACE_TYPE;
+                    break;
+                case DENY:
+                    type = ACE_ACCESS_DENIED_ACE_TYPE;
+                    break;
+                case AUDIT:
+                    type = ACE_SYSTEM_AUDIT_ACE_TYPE;
+                    break;
+                case ALARM:
+                    type = ACE_SYSTEM_ALARM_ACE_TYPE;
+                    break;
+                default:
+                    throw new AssertionError("Unable to map ACE type");
+            }
+
+            // map permissions
+            Set<AclEntryPermission> aceMask = ace.permissions();
+            int mask = 0;
+            if (aceMask.contains(AclEntryPermission.READ_DATA))
+                mask |= ACE_READ_DATA;
+            if (aceMask.contains(AclEntryPermission.WRITE_DATA))
+                mask |= ACE_WRITE_DATA;
+            if (aceMask.contains(AclEntryPermission.APPEND_DATA))
+                mask |= ACE_APPEND_DATA;
+            if (aceMask.contains(AclEntryPermission.READ_NAMED_ATTRS))
+                mask |= ACE_READ_NAMED_ATTRS;
+            if (aceMask.contains(AclEntryPermission.WRITE_NAMED_ATTRS))
+                mask |= ACE_WRITE_NAMED_ATTRS;
+            if (aceMask.contains(AclEntryPermission.EXECUTE))
+                mask |= ACE_EXECUTE;
+            if (aceMask.contains(AclEntryPermission.DELETE_CHILD))
+                mask |= ACE_DELETE_CHILD;
+            if (aceMask.contains(AclEntryPermission.READ_ATTRIBUTES))
+                mask |= ACE_READ_ATTRIBUTES;
+            if (aceMask.contains(AclEntryPermission.WRITE_ATTRIBUTES))
+                mask |= ACE_WRITE_ATTRIBUTES;
+            if (aceMask.contains(AclEntryPermission.DELETE))
+                mask |= ACE_DELETE;
+            if (aceMask.contains(AclEntryPermission.READ_ACL))
+                mask |= ACE_READ_ACL;
+            if (aceMask.contains(AclEntryPermission.WRITE_ACL))
+                mask |= ACE_WRITE_ACL;
+            if (aceMask.contains(AclEntryPermission.WRITE_OWNER))
+                mask |= ACE_WRITE_OWNER;
+            if (aceMask.contains(AclEntryPermission.SYNCHRONIZE))
+                mask |= ACE_SYNCHRONIZE;
+
+            // FIXME - it would be desirable to know here if the file is a
+            // directory or not. Solaris returns EINVAL if an ACE has a directory
+            // -only flag and the file is not a directory.
+            Set<AclEntryFlag> aceFlags = ace.flags();
+            if (aceFlags.contains(AclEntryFlag.FILE_INHERIT))
+                flags |= ACE_FILE_INHERIT_ACE;
+            if (aceFlags.contains(AclEntryFlag.DIRECTORY_INHERIT))
+                flags |= ACE_DIRECTORY_INHERIT_ACE;
+            if (aceFlags.contains(AclEntryFlag.NO_PROPAGATE_INHERIT))
+                flags |= ACE_NO_PROPAGATE_INHERIT_ACE;
+            if (aceFlags.contains(AclEntryFlag.INHERIT_ONLY))
+                flags |= ACE_INHERIT_ONLY_ACE;
+
+            unsafe.putInt(offset + OFFSETOF_UID, uid);
+            unsafe.putInt(offset + OFFSETOF_MASK, mask);
+            unsafe.putShort(offset + OFFSETOF_FLAGS, (short)flags);
+            unsafe.putShort(offset + OFFSETOF_TYPE, (short)type);
+
+            offset += SIZEOF_ACE_T;
+        }
+    }
+
+    /**
+     * Decode the buffer, returning an ACL
+     */
+    private static List<AclEntry> decode(long address, int n) {
+        ArrayList<AclEntry> acl = new ArrayList<>(n);
+        for (int i=0; i<n; i++) {
+            long offset = address + i*SIZEOF_ACE_T;
+
+            int uid = unsafe.getInt(offset + OFFSETOF_UID);
+            int mask = unsafe.getInt(offset + OFFSETOF_MASK);
+            int flags = (int)unsafe.getShort(offset + OFFSETOF_FLAGS);
+            int type = (int)unsafe.getShort(offset + OFFSETOF_TYPE);
+
+            // map uid and flags to UserPrincipal
+            UnixUserPrincipals.User who = null;
+            if ((flags & ACE_OWNER) > 0) {
+                who = UnixUserPrincipals.SPECIAL_OWNER;
+            } else if ((flags & ACE_GROUP) > 0) {
+                who = UnixUserPrincipals.SPECIAL_GROUP;
+            } else if ((flags & ACE_EVERYONE) > 0) {
+                who = UnixUserPrincipals.SPECIAL_EVERYONE;
+            } else if ((flags & ACE_IDENTIFIER_GROUP) > 0) {
+                who = UnixUserPrincipals.fromGid(uid);
+            } else {
+                who = UnixUserPrincipals.fromUid(uid);
+            }
+
+            AclEntryType aceType = null;
+            switch (type) {
+                case ACE_ACCESS_ALLOWED_ACE_TYPE:
+                    aceType = AclEntryType.ALLOW;
+                    break;
+                case ACE_ACCESS_DENIED_ACE_TYPE:
+                    aceType = AclEntryType.DENY;
+                    break;
+                case ACE_SYSTEM_AUDIT_ACE_TYPE:
+                    aceType = AclEntryType.AUDIT;
+                    break;
+                case ACE_SYSTEM_ALARM_ACE_TYPE:
+                    aceType = AclEntryType.ALARM;
+                    break;
+                default:
+                    assert false;
+            }
+
+            Set<AclEntryPermission> aceMask = EnumSet.noneOf(AclEntryPermission.class);
+            if ((mask & ACE_READ_DATA) > 0)
+                aceMask.add(AclEntryPermission.READ_DATA);
+            if ((mask & ACE_WRITE_DATA) > 0)
+                aceMask.add(AclEntryPermission.WRITE_DATA);
+            if ((mask & ACE_APPEND_DATA ) > 0)
+                aceMask.add(AclEntryPermission.APPEND_DATA);
+            if ((mask & ACE_READ_NAMED_ATTRS) > 0)
+                aceMask.add(AclEntryPermission.READ_NAMED_ATTRS);
+            if ((mask & ACE_WRITE_NAMED_ATTRS) > 0)
+                aceMask.add(AclEntryPermission.WRITE_NAMED_ATTRS);
+            if ((mask & ACE_EXECUTE) > 0)
+                aceMask.add(AclEntryPermission.EXECUTE);
+            if ((mask & ACE_DELETE_CHILD ) > 0)
+                aceMask.add(AclEntryPermission.DELETE_CHILD);
+            if ((mask & ACE_READ_ATTRIBUTES) > 0)
+                aceMask.add(AclEntryPermission.READ_ATTRIBUTES);
+            if ((mask & ACE_WRITE_ATTRIBUTES) > 0)
+                aceMask.add(AclEntryPermission.WRITE_ATTRIBUTES);
+            if ((mask & ACE_DELETE) > 0)
+                aceMask.add(AclEntryPermission.DELETE);
+            if ((mask & ACE_READ_ACL) > 0)
+                aceMask.add(AclEntryPermission.READ_ACL);
+            if ((mask & ACE_WRITE_ACL) > 0)
+                aceMask.add(AclEntryPermission.WRITE_ACL);
+            if ((mask & ACE_WRITE_OWNER) > 0)
+                aceMask.add(AclEntryPermission.WRITE_OWNER);
+            if ((mask & ACE_SYNCHRONIZE) > 0)
+                aceMask.add(AclEntryPermission.SYNCHRONIZE);
+
+            Set<AclEntryFlag> aceFlags = EnumSet.noneOf(AclEntryFlag.class);
+            if ((flags & ACE_FILE_INHERIT_ACE) > 0)
+                aceFlags.add(AclEntryFlag.FILE_INHERIT);
+            if ((flags & ACE_DIRECTORY_INHERIT_ACE) > 0)
+                aceFlags.add(AclEntryFlag.DIRECTORY_INHERIT);
+            if ((flags & ACE_NO_PROPAGATE_INHERIT_ACE) > 0)
+                aceFlags.add(AclEntryFlag.NO_PROPAGATE_INHERIT);
+            if ((flags & ACE_INHERIT_ONLY_ACE) > 0)
+                aceFlags.add(AclEntryFlag.INHERIT_ONLY);
+
+            // build the ACL entry and add it to the list
+            AclEntry ace = AclEntry.newBuilder()
+                .setType(aceType)
+                .setPrincipal(who)
+                .setPermissions(aceMask).setFlags(aceFlags).build();
+            acl.add(ace);
+        }
+
+        return acl;
+    }
+
+    // Returns true if NFSv4 ACLs not enabled on file system
+    private static boolean isAclsEnabled(int fd) {
+        try {
+            long enabled = fpathconf(fd, _PC_ACL_ENABLED);
+            if (enabled == _ACL_ACE_ENABLED)
+                return true;
+        } catch (UnixException x) {
+        }
+        return false;
+    }
+
+    @Override
+    public List<AclEntry> getAcl()
+        throws IOException
+    {
+        // permission check
+        checkAccess(file, true, false);
+
+        // open file (will fail if file is a link and not following links)
+        int fd = -1;
+        try {
+            fd = file.openForAttributeAccess(followLinks);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+        }
+        try {
+            long address = unsafe.allocateMemory(SIZEOF_ACE_T * MAX_ACL_ENTRIES);
+            try {
+                // read ACL and decode it
+                int n = facl(fd, ACE_GETACL, MAX_ACL_ENTRIES, address);
+                assert n >= 0;
+                return decode(address, n);
+            } catch (UnixException x) {
+                if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
+                    throw new FileSystemException(file.getPathForExceptionMessage(),
+                        null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
+                }
+                x.rethrowAsIOException(file);
+                return null;    // keep compiler happy
+            } finally {
+                unsafe.freeMemory(address);
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public void setAcl(List<AclEntry> acl) throws IOException {
+        // permission check
+        checkAccess(file, false, true);
+
+        // open file (will fail if file is a link and not following links)
+        int fd = -1;
+        try {
+            fd = file.openForAttributeAccess(followLinks);
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+        }
+        try {
+            // SECURITY: need to copy list as can change during processing
+            acl = new ArrayList<AclEntry>(acl);
+            int n = acl.size();
+
+            long address = unsafe.allocateMemory(SIZEOF_ACE_T * n);
+            try {
+                encode(acl, address);
+                facl(fd, ACE_SETACL, n, address);
+            } catch (UnixException x) {
+                if ((x.errno() == ENOSYS) || !isAclsEnabled(fd)) {
+                    throw new FileSystemException(file.getPathForExceptionMessage(),
+                        null, x.getMessage() + " (file system does not support NFSv4 ACLs)");
+                }
+                if (x.errno() == EINVAL && (n < 3))
+                    throw new IOException("ACL must contain at least 3 entries");
+                x.rethrowAsIOException(file);
+            } finally {
+                unsafe.freeMemory(address);
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @Override
+    public UserPrincipal getOwner()
+        throws IOException
+    {
+        checkAccess(file, true, false);
+
+        try {
+            UnixFileAttributes attrs =
+                UnixFileAttributes.get(file, followLinks);
+            return UnixUserPrincipals.fromUid(attrs.uid());
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+            return null; // keep compile happy
+        }
+    }
+
+    @Override
+    public void setOwner(UserPrincipal owner) throws IOException {
+        checkAccess(file, true, false);
+
+        if (!(owner instanceof UnixUserPrincipals.User))
+            throw new ProviderMismatchException();
+        if (owner instanceof UnixUserPrincipals.Group)
+            throw new IOException("'owner' parameter is a group");
+        int uid = ((UnixUserPrincipals.User)owner).uid();
+
+        try {
+            if (followLinks) {
+                lchown(file, uid, -1);
+            } else {
+                chown(file, uid, -1);
+            }
+        } catch (UnixException x) {
+            x.rethrowAsIOException(file);
+        }
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template	2024-08-17 18:29:44.557920623 +0200
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2008, 2016, Oracle and/or its affiliates. All rights reserved.
+ *
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+@@END_COPYRIGHT@@
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/acl.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+/* On Solaris, "sun" is defined as a macro. Undefine to make package
+   declaration valid */
+#undef sun
+
+/* To be able to name the Java constants the same as the C constants without
+   having the preprocessor rewrite those identifiers, add PREFIX_ to all
+   identifiers matching a C constant. The PREFIX_ is filtered out in the
+   makefile. */
+
+@@START_HERE@@
+
+package sun.nio.fs;
+class SolarisConstants {
+
+    private SolarisConstants() { }
+
+    static final int PREFIX_O_XATTR = O_XATTR;
+    static final int PREFIX__PC_XATTR_ENABLED = _PC_XATTR_ENABLED;
+    static final int PREFIX__PC_ACL_ENABLED = _PC_ACL_ENABLED;
+    static final int PREFIX__ACL_ACE_ENABLED = _ACL_ACE_ENABLED;
+    static final int PREFIX_ACE_GETACL = ACE_GETACL;
+    static final int PREFIX_ACE_SETACL = ACE_SETACL;
+    static final int PREFIX_ACE_ACCESS_ALLOWED_ACE_TYPE = ACE_ACCESS_ALLOWED_ACE_TYPE;
+    static final int PREFIX_ACE_ACCESS_DENIED_ACE_TYPE = ACE_ACCESS_DENIED_ACE_TYPE;
+    static final int PREFIX_ACE_SYSTEM_AUDIT_ACE_TYPE = ACE_SYSTEM_AUDIT_ACE_TYPE;
+    static final int PREFIX_ACE_SYSTEM_ALARM_ACE_TYPE = ACE_SYSTEM_ALARM_ACE_TYPE;
+    static final int PREFIX_ACE_READ_DATA = ACE_READ_DATA;
+    static final int PREFIX_ACE_LIST_DIRECTORY = ACE_LIST_DIRECTORY;
+    static final int PREFIX_ACE_WRITE_DATA = ACE_WRITE_DATA;
+    static final int PREFIX_ACE_ADD_FILE = ACE_ADD_FILE;
+    static final int PREFIX_ACE_APPEND_DATA = ACE_APPEND_DATA;
+    static final int PREFIX_ACE_ADD_SUBDIRECTORY = ACE_ADD_SUBDIRECTORY;
+    static final int PREFIX_ACE_READ_NAMED_ATTRS = ACE_READ_NAMED_ATTRS;
+    static final int PREFIX_ACE_WRITE_NAMED_ATTRS = ACE_WRITE_NAMED_ATTRS;
+    static final int PREFIX_ACE_EXECUTE = ACE_EXECUTE;
+    static final int PREFIX_ACE_DELETE_CHILD = ACE_DELETE_CHILD;
+    static final int PREFIX_ACE_READ_ATTRIBUTES = ACE_READ_ATTRIBUTES;
+    static final int PREFIX_ACE_WRITE_ATTRIBUTES = ACE_WRITE_ATTRIBUTES;
+    static final int PREFIX_ACE_DELETE = ACE_DELETE;
+    static final int PREFIX_ACE_READ_ACL = ACE_READ_ACL;
+    static final int PREFIX_ACE_WRITE_ACL = ACE_WRITE_ACL;
+    static final int PREFIX_ACE_WRITE_OWNER = ACE_WRITE_OWNER;
+    static final int PREFIX_ACE_SYNCHRONIZE = ACE_SYNCHRONIZE;
+    static final int PREFIX_ACE_FILE_INHERIT_ACE = ACE_FILE_INHERIT_ACE;
+    static final int PREFIX_ACE_DIRECTORY_INHERIT_ACE = ACE_DIRECTORY_INHERIT_ACE;
+    static final int PREFIX_ACE_NO_PROPAGATE_INHERIT_ACE = ACE_NO_PROPAGATE_INHERIT_ACE;
+    static final int PREFIX_ACE_INHERIT_ONLY_ACE = ACE_INHERIT_ONLY_ACE;
+    static final int PREFIX_ACE_SUCCESSFUL_ACCESS_ACE_FLAG = ACE_SUCCESSFUL_ACCESS_ACE_FLAG;
+    static final int PREFIX_ACE_FAILED_ACCESS_ACE_FLAG = ACE_FAILED_ACCESS_ACE_FLAG;
+    static final int PREFIX_ACE_IDENTIFIER_GROUP = ACE_IDENTIFIER_GROUP;
+    static final int PREFIX_ACE_OWNER = ACE_OWNER;
+    static final int PREFIX_ACE_GROUP = ACE_GROUP;
+    static final int PREFIX_ACE_EVERYONE = ACE_EVERYONE;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java	2024-08-17 18:29:44.558283814 +0200
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2008, 2010, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.attribute.*;
+import java.io.IOException;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.SolarisConstants.*;
+
+/**
+ * Solaris implementation of FileStore
+ */
+
+class SolarisFileStore
+    extends UnixFileStore
+{
+    private final boolean xattrEnabled;
+
+    SolarisFileStore(UnixPath file) throws IOException {
+        super(file);
+        this.xattrEnabled = xattrEnabled();
+    }
+
+    SolarisFileStore(UnixFileSystem fs, UnixMountEntry entry) throws IOException {
+        super(fs, entry);
+        this.xattrEnabled = xattrEnabled();
+    }
+
+    // returns true if extended attributes enabled
+    private boolean xattrEnabled() {
+        long res = 0L;
+        try {
+            res = pathconf(file(), _PC_XATTR_ENABLED);
+        } catch (UnixException x) {
+            // ignore
+        }
+        return (res != 0L);
+    }
+
+    @Override
+    UnixMountEntry findMountEntry() throws IOException {
+        // On Solaris iterate over the entries in the mount table to find device
+        for (UnixMountEntry entry: file().getFileSystem().getMountEntries()) {
+            if (entry.dev() == dev()) {
+                return entry;
+            }
+        }
+        throw new IOException("Device not found in mnttab");
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(Class<? extends FileAttributeView> type) {
+        if (type == AclFileAttributeView.class) {
+            // lookup fstypes.properties
+            FeatureStatus status = checkIfFeaturePresent("nfsv4acl");
+            switch (status) {
+                case PRESENT     : return true;
+                case NOT_PRESENT : return false;
+                default :
+                    // AclFileAttributeView available on ZFS
+                    return (type().equals("zfs"));
+            }
+        }
+        if (type == UserDefinedFileAttributeView.class) {
+            // lookup fstypes.properties
+            FeatureStatus status = checkIfFeaturePresent("xattr");
+            switch (status) {
+                case PRESENT     : return true;
+                case NOT_PRESENT : return false;
+                default :
+                    // UserDefinedFileAttributeView available if extended
+                    // attributes supported
+                    return xattrEnabled;
+            }
+        }
+        return super.supportsFileAttributeView(type);
+    }
+
+    @Override
+    public boolean supportsFileAttributeView(String name) {
+        if (name.equals("acl"))
+            return supportsFileAttributeView(AclFileAttributeView.class);
+        if (name.equals("user"))
+            return supportsFileAttributeView(UserDefinedFileAttributeView.class);
+        return super.supportsFileAttributeView(name);
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java	2024-08-17 18:29:44.558639037 +0200
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.io.IOException;
+import java.util.*;
+import sun.security.action.GetPropertyAction;
+import static sun.nio.fs.SolarisNativeDispatcher.*;
+
+/**
+ * Solaris implementation of FileSystem
+ */
+
+class SolarisFileSystem extends UnixFileSystem {
+    private final boolean hasSolaris11Features;
+
+    SolarisFileSystem(UnixFileSystemProvider provider, String dir) {
+        super(provider, dir);
+
+        // check os.version
+        String osversion = GetPropertyAction.privilegedGetProperty("os.version");
+        String[] vers = Util.split(osversion, '.');
+        assert vers.length >= 2;
+        int majorVersion = Integer.parseInt(vers[0]);
+        int minorVersion = Integer.parseInt(vers[1]);
+        this.hasSolaris11Features =
+            (majorVersion > 5 || (majorVersion == 5 && minorVersion >= 11));
+    }
+
+    @Override
+    boolean isSolaris() {
+        return true;
+    }
+
+    @Override
+    public WatchService newWatchService()
+        throws IOException
+    {
+        // FEN available since Solaris 11
+        if (hasSolaris11Features) {
+            return new SolarisWatchService(this);
+        } else {
+            return new PollingWatchService();
+        }
+    }
+
+
+    // lazy initialization of the list of supported attribute views
+    private static class SupportedFileFileAttributeViewsHolder {
+        static final Set<String> supportedFileAttributeViews =
+            supportedFileAttributeViews();
+        private static Set<String> supportedFileAttributeViews() {
+            Set<String> result = new HashSet<>();
+            result.addAll(standardFileAttributeViews());
+            // additional Solaris-specific views
+            result.add("acl");
+            result.add("user");
+            return Collections.unmodifiableSet(result);
+        }
+    }
+
+    @Override
+    public Set<String> supportedFileAttributeViews() {
+        return SupportedFileFileAttributeViewsHolder.supportedFileAttributeViews;
+    }
+
+    @Override
+    void copyNonPosixAttributes(int ofd, int nfd) {
+        SolarisUserDefinedFileAttributeView.copyExtendedAttributes(ofd, nfd);
+        // TDB: copy ACL from source to target
+    }
+
+    /**
+     * Returns object to iterate over entries in /etc/mnttab
+     */
+    @Override
+    Iterable<UnixMountEntry> getMountEntries() {
+        ArrayList<UnixMountEntry> entries = new ArrayList<>();
+        try {
+            UnixPath mnttab = new UnixPath(this, "/etc/mnttab");
+            long fp = fopen(mnttab, "r");
+            try {
+                for (;;) {
+                    UnixMountEntry entry = new UnixMountEntry();
+                    int res = getextmntent(fp, entry);
+                    if (res < 0)
+                        break;
+                    entries.add(entry);
+                }
+            } finally {
+                fclose(fp);
+            }
+        } catch (UnixException x) {
+            // nothing we can do
+        }
+        return entries;
+    }
+
+    @Override
+    FileStore getFileStore(UnixMountEntry entry) throws IOException {
+        return new SolarisFileStore(this, entry);
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	2024-08-17 18:29:44.558982612 +0200
@@ -0,0 +1,94 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.file.attribute.*;
+import java.nio.file.spi.FileTypeDetector;
+import java.io.IOException;
+import jdk.internal.util.StaticProperty;
+import sun.security.action.GetPropertyAction;
+
+/**
+ * Solaris implementation of FileSystemProvider
+ */
+
+class SolarisFileSystemProvider extends UnixFileSystemProvider {
+    public SolarisFileSystemProvider() {
+        super();
+    }
+
+    @Override
+    SolarisFileSystem newFileSystem(String dir) {
+        return new SolarisFileSystem(this, dir);
+    }
+
+    @Override
+    SolarisFileStore getFileStore(UnixPath path) throws IOException {
+        return new SolarisFileStore(path);
+    }
+
+
+    @Override
+    @SuppressWarnings("unchecked")
+    public <V extends FileAttributeView> V getFileAttributeView(Path obj,
+                                                                Class<V> type,
+                                                                LinkOption... options)
+    {
+        if (type == AclFileAttributeView.class) {
+            return (V) new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj),
+                                                       Util.followLinks(options));
+        }
+        if (type == UserDefinedFileAttributeView.class) {
+            return(V) new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
+                                                              Util.followLinks(options));
+        }
+        return super.getFileAttributeView(obj, type, options);
+    }
+
+    @Override
+    public DynamicFileAttributeView getFileAttributeView(Path obj,
+                                                         String name,
+                                                         LinkOption... options)
+    {
+        if (name.equals("acl"))
+            return new SolarisAclFileAttributeView(UnixPath.toUnixPath(obj),
+                                                   Util.followLinks(options));
+        if (name.equals("user"))
+            return new SolarisUserDefinedFileAttributeView(UnixPath.toUnixPath(obj),
+                                                           Util.followLinks(options));
+        return super.getFileAttributeView(obj, name, options);
+    }
+
+    @Override
+    FileTypeDetector getFileTypeDetector() {
+        Path userMimeTypes = Path.of(StaticProperty.userHome(), ".mime.types");
+        Path etcMimeTypes = Path.of("/etc/mime.types");
+
+        return chain(new MimeTypesFileTypeDetector(userMimeTypes),
+                     new MimeTypesFileTypeDetector(etcMimeTypes));
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java	2024-08-17 18:29:44.559302356 +0200
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+/**
+ * Solaris specific system calls.
+ */
+
+class SolarisNativeDispatcher extends UnixNativeDispatcher {
+    private SolarisNativeDispatcher() { }
+
+    /**
+     * int getextmntent(FILE *fp, struct extmnttab *mp, int len);
+     */
+    static native int getextmntent(long fp, UnixMountEntry entry)
+        throws UnixException;
+
+    /**
+     * int facl(int filedes, int cmd, int nentries, void aclbufp)
+     */
+    static native int facl(int fd, int cmd, int nentries, long aclbufp)
+        throws UnixException;
+
+
+    // initialize
+    private static native void init();
+
+    static {
+        jdk.internal.loader.BootLoader.loadLibrary("nio");
+        init();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java	2024-08-17 18:29:44.559768564 +0200
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2008, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.nio.ByteBuffer;
+import java.nio.channels.FileChannel;
+import java.io.IOException;
+import java.util.*;
+
+import static sun.nio.fs.UnixNativeDispatcher.*;
+import static sun.nio.fs.UnixConstants.*;
+import static sun.nio.fs.SolarisConstants.*;
+
+/**
+ * Solaris emulation of NamedAttributeView using extended attributes.
+ */
+
+class SolarisUserDefinedFileAttributeView
+    extends AbstractUserDefinedFileAttributeView
+{
+    private static final byte[] HERE = { '.' };
+
+    private byte[] nameAsBytes(UnixPath file, String name) throws IOException {
+        byte[] bytes = Util.toBytes(name);
+        // "", "." and ".." not allowed
+        if (bytes.length == 0 || bytes[0] == '.') {
+            if (bytes.length <= 1 ||
+                (bytes.length == 2 && bytes[1] == '.'))
+            {
+                throw new FileSystemException(file.getPathForExceptionMessage(),
+                    null, "'" + name + "' is not a valid name");
+            }
+        }
+        return bytes;
+    }
+
+    private final UnixPath file;
+    private final boolean followLinks;
+
+    SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
+        this.file = file;
+        this.followLinks = followLinks;
+    }
+
+    @SuppressWarnings("removal")
+    @Override
+    public List<String> list() throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = -1;
+        try {
+            try {
+                fd = file.openForAttributeAccess(followLinks);
+
+                // open extended attribute directory
+                int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0);
+                long dp;
+                try {
+                    dp = fdopendir(dfd);
+                } catch (UnixException x) {
+                    close(dfd);
+                    throw x;
+                }
+
+                // read list of extended attributes
+                List<String> list = new ArrayList<>();
+                try {
+                    byte[] name;
+                    while ((name = readdir(dp)) != null) {
+                        String s = Util.toString(name);
+                        if (!s.equals(".") && !s.equals(".."))
+                            list.add(s);
+                    }
+                } finally {
+                    closedir(dp);
+                }
+                return Collections.unmodifiableList(list);
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExceptionMessage(),
+                    null, "Unable to get list of extended attributes: " +
+                    x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @SuppressWarnings("removal")
+    @Override
+    public int size(String name) throws IOException  {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = -1;
+        try {
+            try {
+                fd = file.openForAttributeAccess(followLinks);
+
+                // open attribute file
+                int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
+                try {
+                    // read attribute's attributes
+                    UnixFileAttributes attrs = UnixFileAttributes.get(afd);
+                    long size = attrs.size();
+                    if (size > Integer.MAX_VALUE)
+                        throw new ArithmeticException("Extended attribute value too large");
+                    return (int)size;
+                } finally {
+                    close(afd);
+                }
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExceptionMessage(),
+                    null, "Unable to get size of extended attribute '" + name +
+                    "': " + x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @SuppressWarnings("removal")
+    @Override
+    public int read(String name, ByteBuffer dst) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), true, false);
+
+        int fd = -1;
+        try {
+            try {
+                fd = file.openForAttributeAccess(followLinks);
+
+                // open attribute file
+                int afd = openat(fd, nameAsBytes(file,name), (O_RDONLY|O_XATTR), 0);
+
+                // wrap with channel
+                FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), true, false);
+
+                // read to EOF (nothing we can do if I/O error occurs)
+                try {
+                    if (fc.size() > dst.remaining())
+                        throw new IOException("Extended attribute file too large");
+                    int total = 0;
+                    while (dst.hasRemaining()) {
+                        int n = fc.read(dst);
+                        if (n < 0)
+                            break;
+                        total += n;
+                    }
+                    return total;
+                } finally {
+                    fc.close();
+                }
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExceptionMessage(),
+                    null, "Unable to read extended attribute '" + name +
+                    "': " + x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @SuppressWarnings("removal")
+    @Override
+    public int write(String name, ByteBuffer src) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        int fd = -1;
+        try {
+            try {
+                fd = file.openForAttributeAccess(followLinks);
+
+                // open/create attribute file
+                int afd = openat(fd, nameAsBytes(file,name),
+                                 (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
+                                 UnixFileModeAttribute.ALL_PERMISSIONS);
+
+                // wrap with channel
+                FileChannel fc = UnixChannelFactory.newFileChannel(afd, file.toString(), false, true);
+
+                // write value (nothing we can do if I/O error occurs)
+                try {
+                    int rem = src.remaining();
+                    while (src.hasRemaining()) {
+                        fc.write(src);
+                    }
+                    return rem;
+                } finally {
+                    fc.close();
+                }
+            } catch (UnixException x) {
+                throw new FileSystemException(file.getPathForExceptionMessage(),
+                    null, "Unable to write extended attribute '" + name +
+                    "': " + x.getMessage());
+            }
+        } finally {
+            close(fd);
+        }
+    }
+
+    @SuppressWarnings("removal")
+    @Override
+    public void delete(String name) throws IOException {
+        if (System.getSecurityManager() != null)
+            checkAccess(file.getPathForPermissionCheck(), false, true);
+
+        int fd = -1;
+        try {
+            fd = file.openForAttributeAccess(followLinks);
+
+            int dfd = openat(fd, HERE, (O_RDONLY|O_XATTR), 0);
+            try {
+                unlinkat(dfd, nameAsBytes(file,name), 0);
+            } finally {
+                close(dfd);
+            }
+        } catch (UnixException x) {
+            throw new FileSystemException(file.getPathForExceptionMessage(),
+                null, "Unable to delete extended attribute '" + name +
+                "': " + x.getMessage());
+        } finally {
+            close(fd);
+        }
+    }
+
+    /**
+     * Used by copyTo/moveTo to copy extended attributes from source to target.
+     *
+     * @param   ofd
+     *          file descriptor for source file
+     * @param   nfd
+     *          file descriptor for target file
+     */
+    static void copyExtendedAttributes(int ofd, int nfd) {
+        try {
+            // open extended attribute directory
+            int dfd = openat(ofd, HERE, (O_RDONLY|O_XATTR), 0);
+            long dp = 0L;
+            try {
+                dp = fdopendir(dfd);
+            } catch (UnixException x) {
+                close(dfd);
+                throw x;
+            }
+
+            // copy each extended attribute
+            try {
+                byte[] name;
+                while ((name = readdir(dp)) != null) {
+                    // ignore "." and ".."
+                    if (name[0] == '.') {
+                        if (name.length == 1)
+                            continue;
+                        if (name.length == 2 && name[1] == '.')
+                            continue;
+                    }
+                    copyExtendedAttribute(ofd, name, nfd);
+                }
+            } finally {
+                closedir(dp);
+            }
+        } catch (UnixException ignore) {
+        }
+    }
+
+    private static void copyExtendedAttribute(int ofd, byte[] name, int nfd)
+        throws UnixException
+    {
+        // open source attribute file
+        int src = openat(ofd, name, (O_RDONLY|O_XATTR), 0);
+        try {
+            // create target attribute file
+            int dst = openat(nfd, name, (O_CREAT|O_WRONLY|O_TRUNC|O_XATTR),
+                UnixFileModeAttribute.ALL_PERMISSIONS);
+            try {
+                UnixCopyFile.transfer(dst, src, 0L);
+            } finally {
+                close(dst);
+            }
+        } finally {
+            close(src);
+        }
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java	2024-08-17 18:29:44.560498798 +0200
@@ -0,0 +1,821 @@
+/*
+ * Copyright (c) 2008, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.nio.fs;
+
+import java.nio.file.*;
+import java.util.*;
+import java.io.IOException;
+import jdk.internal.misc.Unsafe;
+
+import static sun.nio.fs.UnixConstants.*;
+
+/**
+ * Solaris implementation of WatchService based on file events notification
+ * facility.
+ */
+
+class SolarisWatchService
+    extends AbstractWatchService
+{
+    private static final Unsafe unsafe = Unsafe.getUnsafe();
+    private static int addressSize = unsafe.addressSize();
+
+    private static int dependsArch(int value32, int value64) {
+        return (addressSize == 4) ? value32 : value64;
+    }
+
+    /*
+     * typedef struct port_event {
+     *     int             portev_events;
+     *     ushort_t        portev_source;
+     *     ushort_t        portev_pad;
+     *     uintptr_t       portev_object;
+     *     void            *portev_user;
+     * } port_event_t;
+     */
+    private static final int SIZEOF_PORT_EVENT  = dependsArch(16, 24);
+    private static final int OFFSETOF_EVENTS    = 0;
+    private static final int OFFSETOF_SOURCE    = 4;
+    private static final int OFFSETOF_OBJECT    = 8;
+
+    /*
+     * typedef struct file_obj {
+     *     timestruc_t     fo_atime;
+     *     timestruc_t     fo_mtime;
+     *     timestruc_t     fo_ctime;
+     *     uintptr_t       fo_pad[3];
+     *     char            *fo_name;
+     * } file_obj_t;
+     */
+    private static final int SIZEOF_FILEOBJ    = dependsArch(40, 80);
+    private static final int OFFSET_FO_NAME    = dependsArch(36, 72);
+
+    // port sources
+    private static final short PORT_SOURCE_USER     = 3;
+    private static final short PORT_SOURCE_FILE     = 7;
+
+    // user-watchable events
+    private static final int FILE_MODIFIED      = 0x00000002;
+    private static final int FILE_ATTRIB        = 0x00000004;
+    private static final int FILE_NOFOLLOW      = 0x10000000;
+
+    // exception events
+    private static final int FILE_DELETE        = 0x00000010;
+    private static final int FILE_RENAME_TO     = 0x00000020;
+    private static final int FILE_RENAME_FROM   = 0x00000040;
+    private static final int UNMOUNTED          = 0x20000000;
+    private static final int MOUNTEDOVER        = 0x40000000;
+
+    // background thread to read change events
+    private final Poller poller;
+
+    SolarisWatchService(UnixFileSystem fs) throws IOException {
+        int port = -1;
+        try {
+            port = portCreate();
+        } catch (UnixException x) {
+            throw new IOException(x.errorString());
+        }
+
+        this.poller = new Poller(fs, this, port);
+        this.poller.start();
+    }
+
+    @Override
+    WatchKey register(Path dir,
+                      WatchEvent.Kind<?>[] events,
+                      WatchEvent.Modifier... modifiers)
+         throws IOException
+    {
+        // delegate to poller
+        return poller.register(dir, events, modifiers);
+    }
+
+    @Override
+    void implClose() throws IOException {
+        // delegate to poller
+        poller.close();
+    }
+
+    /**
+     * WatchKey implementation
+     */
+    private class SolarisWatchKey extends AbstractWatchKey
+        implements DirectoryNode
+    {
+        private final UnixFileKey fileKey;
+
+        // pointer to native file_obj object
+        private final long object;
+
+        // events (may be changed). set to null when watch key is invalid
+        private volatile Set<? extends WatchEvent.Kind<?>> events;
+
+        // map of entries in directory; created lazily; accessed only by
+        // poller thread.
+        private Map<Path,EntryNode> children = new HashMap<>();
+
+        SolarisWatchKey(SolarisWatchService watcher,
+                        UnixPath dir,
+                        UnixFileKey fileKey,
+                        long object,
+                        Set<? extends WatchEvent.Kind<?>> events)
+        {
+            super(dir, watcher);
+            this.fileKey = fileKey;
+            this.object = object;
+            this.events = events;
+        }
+
+        UnixPath getDirectory() {
+            return (UnixPath)watchable();
+        }
+
+        UnixFileKey getFileKey() {
+            return fileKey;
+        }
+
+        @Override
+        public long object() {
+            return object;
+        }
+
+        void invalidate() {
+            events = null;
+        }
+
+        Set<? extends WatchEvent.Kind<?>> events() {
+            return events;
+        }
+
+        void setEvents(Set<? extends WatchEvent.Kind<?>> events) {
+            this.events = events;
+        }
+
+        Map<Path,EntryNode> children() {
+            return children;
+        }
+
+        @Override
+        public boolean isValid() {
+            return events != null;
+        }
+
+        @Override
+        public void cancel() {
+            if (isValid()) {
+                // delegate to poller
+                poller.cancel(this);
+            }
+        }
+
+        @Override
+        public void addChild(Path name, EntryNode node) {
+            children.put(name, node);
+        }
+
+        @Override
+        public void removeChild(Path name) {
+            children.remove(name);
+        }
+
+        @Override
+        public EntryNode getChild(Path name) {
+            return children.get(name);
+        }
+    }
+
+    /**
+     * Background thread to read from port
+     */
+    private class Poller extends AbstractPoller {
+
+        // maximum number of events to read per call to port_getn
+        private static final int MAX_EVENT_COUNT            = 128;
+
+        // events that map to ENTRY_DELETE
+        private static final int FILE_REMOVED =
+            (FILE_DELETE|FILE_RENAME_TO|FILE_RENAME_FROM);
+
+        // events that tell us not to re-associate the object
+        private static final int FILE_EXCEPTION =
+            (FILE_REMOVED|UNMOUNTED|MOUNTEDOVER);
+
+        // address of event buffers (used to receive events with port_getn)
+        private final long bufferAddress;
+
+        private final SolarisWatchService watcher;
+
+        // the I/O port
+        private final int port;
+
+        // maps file key (dev/inode) to WatchKey
+        private final Map<UnixFileKey,SolarisWatchKey> fileKey2WatchKey;
+
+        // maps file_obj object to Node
+        private final Map<Long,Node> object2Node;
+
+        /**
+         * Create a new instance
+         */
+        Poller(UnixFileSystem fs, SolarisWatchService watcher, int port) {
+            this.watcher = watcher;
+            this.port = port;
+            this.bufferAddress =
+                unsafe.allocateMemory(SIZEOF_PORT_EVENT * MAX_EVENT_COUNT);
+            this.fileKey2WatchKey = new HashMap<UnixFileKey,SolarisWatchKey>();
+            this.object2Node = new HashMap<Long,Node>();
+        }
+
+        @Override
+        void wakeup() throws IOException {
+            // write to port to wakeup polling thread
+            try {
+                portSend(port, 0);
+            } catch (UnixException x) {
+                throw new IOException(x.errorString());
+            }
+        }
+
+        @Override
+        Object implRegister(Path obj,
+                            Set<? extends WatchEvent.Kind<?>> events,
+                            WatchEvent.Modifier... modifiers)
+        {
+            // no modifiers supported at this time
+            if (modifiers.length > 0) {
+                for (WatchEvent.Modifier modifier: modifiers) {
+                    if (modifier == null)
+                        return new NullPointerException();
+                    if (!ExtendedOptions.SENSITIVITY_HIGH.matches(modifier) &&
+                            !ExtendedOptions.SENSITIVITY_MEDIUM.matches(modifier) &&
+                            !ExtendedOptions.SENSITIVITY_LOW.matches(modifier)) {
+                        return new UnsupportedOperationException("Modifier not supported");
+                    }
+                }
+            }
+
+            UnixPath dir = (UnixPath)obj;
+
+            // check file is directory
+            UnixFileAttributes attrs = null;
+            try {
+                attrs = UnixFileAttributes.get(dir, true);
+            } catch (UnixException x) {
+                return x.asIOException(dir);
+            }
+            if (!attrs.isDirectory()) {
+                return new NotDirectoryException(dir.getPathForExceptionMessage());
+            }
+
+            // if already registered then update the events and return existing key
+            UnixFileKey fileKey = attrs.fileKey();
+            SolarisWatchKey watchKey = fileKey2WatchKey.get(fileKey);
+            if (watchKey != null) {
+                try {
+                    updateEvents(watchKey, events);
+                } catch (UnixException x) {
+                    return x.asIOException(dir);
+                }
+                return watchKey;
+            }
+
+            // register directory
+            long object = 0L;
+            try {
+                object = registerImpl(dir, (FILE_MODIFIED | FILE_ATTRIB));
+            } catch (UnixException x) {
+                return x.asIOException(dir);
+            }
+
+            // create watch key and insert it into maps
+            watchKey = new SolarisWatchKey(watcher, dir, fileKey, object, events);
+            object2Node.put(object, watchKey);
+            fileKey2WatchKey.put(fileKey, watchKey);
+
+            // register all entries in directory
+            registerChildren(dir, watchKey, false, false);
+
+            return watchKey;
+        }
+
+        // release resources for single entry
+        void releaseChild(EntryNode node) {
+            long object = node.object();
+            if (object != 0L) {
+               object2Node.remove(object);
+               releaseObject(object, true);
+               node.setObject(0L);
+           }
+        }
+
+        // release resources for entries in directory
+        void releaseChildren(SolarisWatchKey key) {
+           for (EntryNode node: key.children().values()) {
+               releaseChild(node);
+           }
+        }
+
+        // cancel single key
+        @Override
+        void implCancelKey(WatchKey obj) {
+           SolarisWatchKey key = (SolarisWatchKey)obj;
+           if (key.isValid()) {
+               fileKey2WatchKey.remove(key.getFileKey());
+
+               // release resources for entries
+               releaseChildren(key);
+
+               // release resources for directory
+               long object = key.object();
+               object2Node.remove(object);
+               releaseObject(object, true);
+
+               // and finally invalidate the key
+               key.invalidate();
+           }
+        }
+
+        // close watch service
+        @Override
+        void implCloseAll() {
+            // release all native resources
+            for (Long object: object2Node.keySet()) {
+                releaseObject(object, true);
+            }
+
+            // invalidate all keys
+            for (Map.Entry<UnixFileKey,SolarisWatchKey> entry: fileKey2WatchKey.entrySet()) {
+                entry.getValue().invalidate();
+            }
+
+            // clean-up
+            object2Node.clear();
+            fileKey2WatchKey.clear();
+
+            // free global resources
+            unsafe.freeMemory(bufferAddress);
+            UnixNativeDispatcher.close(port);
+        }
+
+        /**
+         * Poller main loop. Blocks on port_getn waiting for events and then
+         * processes them.
+         */
+        @Override
+        public void run() {
+            try {
+                for (;;) {
+                    int n = portGetn(port, bufferAddress, MAX_EVENT_COUNT);
+                    assert n > 0;
+
+                    long address = bufferAddress;
+                    for (int i=0; i<n; i++) {
+                        boolean shutdown = processEvent(address);
+                        if (shutdown)
+                            return;
+                        address += SIZEOF_PORT_EVENT;
+                    }
+                }
+            } catch (UnixException x) {
+                x.printStackTrace();
+            }
+        }
+
+        /**
+         * Process a single port_event
+         *
+         * Returns true if poller thread is requested to shutdown.
+         */
+        boolean processEvent(long address) {
+            // pe->portev_source
+            short source = unsafe.getShort(address + OFFSETOF_SOURCE);
+            // pe->portev_object
+            long object = unsafe.getAddress(address + OFFSETOF_OBJECT);
+            // pe->portev_events
+            int events = unsafe.getInt(address + OFFSETOF_EVENTS);
+
+            // user event is trigger to process pending requests
+            if (source != PORT_SOURCE_FILE) {
+                if (source == PORT_SOURCE_USER) {
+                    // process any pending requests
+                    boolean shutdown = processRequests();
+                    if (shutdown)
+                        return true;
+                }
+                return false;
+            }
+
+            // lookup object to get Node
+            Node node = object2Node.get(object);
+            if (node == null) {
+                // should not happen
+                return false;
+            }
+
+            // As a workaround for 6642290 and 6636438/6636412 we don't use
+            // FILE_EXCEPTION events to tell use not to register the file.
+            // boolean reregister = (events & FILE_EXCEPTION) == 0;
+            boolean reregister = true;
+
+            // If node is EntryNode then event relates to entry in directory
+            // If node is a SolarisWatchKey (DirectoryNode) then event relates
+            // to a watched directory.
+            boolean isDirectory = (node instanceof SolarisWatchKey);
+            if (isDirectory) {
+                processDirectoryEvents((SolarisWatchKey)node, events);
+            } else {
+                boolean ignore = processEntryEvents((EntryNode)node, events);
+                if (ignore)
+                    reregister = false;
+            }
+
+            // need to re-associate to get further events
+            if (reregister) {
+                try {
+                    events = FILE_MODIFIED | FILE_ATTRIB;
+                    if (!isDirectory) events |= FILE_NOFOLLOW;
+                    portAssociate(port,
+                                  PORT_SOURCE_FILE,
+                                  object,
+                                  events);
+                } catch (UnixException x) {
+                    // unable to re-register
+                    reregister = false;
+                }
+            }
+
+            // object is not re-registered so release resources. If
+            // object is a watched directory then signal key
+            if (!reregister) {
+                // release resources
+                object2Node.remove(object);
+                releaseObject(object, false);
+
+                // if watch key then signal it
+                if (isDirectory) {
+                    SolarisWatchKey key = (SolarisWatchKey)node;
+                    fileKey2WatchKey.remove( key.getFileKey() );
+                    key.invalidate();
+                    key.signal();
+                } else {
+                    // if entry then remove it from parent
+                    EntryNode entry = (EntryNode)node;
+                    SolarisWatchKey key = (SolarisWatchKey)entry.parent();
+                    key.removeChild(entry.name());
+                }
+            }
+
+            return false;
+        }
+
+        /**
+         * Process directory events. If directory is modified then re-scan
+         * directory to register any new entries
+         */
+        void processDirectoryEvents(SolarisWatchKey key, int mask) {
+            if ((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) {
+                registerChildren(key.getDirectory(), key,
+                    key.events().contains(StandardWatchEventKinds.ENTRY_CREATE),
+                    key.events().contains(StandardWatchEventKinds.ENTRY_DELETE));
+            }
+        }
+
+        /**
+         * Process events for entries in registered directories. Returns {@code
+         * true} if events are ignored because the watch key has been cancelled.
+         */
+        boolean processEntryEvents(EntryNode node, int mask) {
+            SolarisWatchKey key = (SolarisWatchKey)node.parent();
+            Set<? extends WatchEvent.Kind<?>> events = key.events();
+            if (events == null) {
+                // key has been cancelled so ignore event
+                return true;
+            }
+
+            // entry modified
+            if (((mask & (FILE_MODIFIED | FILE_ATTRIB)) != 0) &&
+                events.contains(StandardWatchEventKinds.ENTRY_MODIFY))
+            {
+                key.signalEvent(StandardWatchEventKinds.ENTRY_MODIFY, node.name());
+            }
+
+
+            return false;
+        }
+
+        /**
+         * Registers all entries in the given directory
+         *
+         * The {@code sendCreateEvents} and {@code sendDeleteEvents} parameters
+         * indicates if ENTRY_CREATE and ENTRY_DELETE events should be queued
+         * when new entries are found. When initially registering a directory
+         * they will always be false. When re-scanning a directory then it
+         * depends on if the events are enabled or not.
+         */
+        void registerChildren(UnixPath dir,
+                              SolarisWatchKey parent,
+                              boolean sendCreateEvents,
+                              boolean sendDeleteEvents)
+        {
+            boolean isModifyEnabled =
+                parent.events().contains(StandardWatchEventKinds.ENTRY_MODIFY) ;
+
+            // reset visited flag on entries so that we can detect file deletes
+            for (EntryNode node: parent.children().values()) {
+                node.setVisited(false);
+            }
+
+            try (DirectoryStream<Path> stream = Files.newDirectoryStream(dir)) {
+                for (Path entry: stream) {
+                    Path name = entry.getFileName();
+
+                    // skip entry if already registered
+                    EntryNode node = parent.getChild(name);
+                    if (node != null) {
+                        node.setVisited(true);
+                        continue;
+                    }
+
+                    // new entry found
+
+                    long object = 0L;
+                    int errno = 0;
+                    boolean addNode = false;
+
+                    // if ENTRY_MODIFY enabled then we register the entry for events
+                    if (isModifyEnabled) {
+                        try {
+                            UnixPath path = (UnixPath)entry;
+                            int events = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
+                            object = registerImpl(path, events);
+                            addNode = true;
+                        } catch (UnixException x) {
+                            errno = x.errno();
+                        }
+                    } else {
+                        addNode = true;
+                    }
+
+                    if (addNode) {
+                        // create node
+                        node = new EntryNode(object, (UnixPath)entry.getFileName(), parent);
+                        node.setVisited(true);
+                        // tell the parent about it
+                        parent.addChild(entry.getFileName(), node);
+                        if (object != 0L)
+                            object2Node.put(object, node);
+                    }
+
+                    // send ENTRY_CREATE event for the new file
+                    // send ENTRY_DELETE event for files that were deleted immediately
+                    boolean deleted = (errno == ENOENT);
+                    if (sendCreateEvents && (addNode || deleted))
+                        parent.signalEvent(StandardWatchEventKinds.ENTRY_CREATE, name);
+                    if (sendDeleteEvents && deleted)
+                        parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, name);
+
+                }
+            } catch (DirectoryIteratorException | IOException x) {
+                // queue OVERFLOW event so that user knows to re-scan directory
+                parent.signalEvent(StandardWatchEventKinds.OVERFLOW, null);
+                return;
+            }
+
+            // clean-up and send ENTRY_DELETE events for any entries that were
+            // not found
+            Iterator<Map.Entry<Path,EntryNode>> iterator =
+                parent.children().entrySet().iterator();
+            while (iterator.hasNext()) {
+                Map.Entry<Path,EntryNode> entry = iterator.next();
+                EntryNode node = entry.getValue();
+                if (!node.isVisited()) {
+                    long object = node.object();
+                    if (object != 0L) {
+                        object2Node.remove(object);
+                        releaseObject(object, true);
+                    }
+                    if (sendDeleteEvents)
+                        parent.signalEvent(StandardWatchEventKinds.ENTRY_DELETE, node.name());
+                    iterator.remove();
+                }
+            }
+        }
+
+        /**
+         * Update watch key's events. If ENTRY_MODIFY changes to be enabled
+         * then register each file in the directory; If ENTRY_MODIFY changed to
+         * be disabled then unregister each file.
+         */
+        void updateEvents(SolarisWatchKey key, Set<? extends WatchEvent.Kind<?>> events)
+            throws UnixException
+        {
+
+            // update events, remembering if ENTRY_MODIFY was previously
+            // enabled or disabled.
+            boolean oldModifyEnabled = key.events()
+                .contains(StandardWatchEventKinds.ENTRY_MODIFY);
+            key.setEvents(events);
+
+            // check if ENTRY_MODIFY has changed
+            boolean newModifyEnabled = events
+                .contains(StandardWatchEventKinds.ENTRY_MODIFY);
+            if (newModifyEnabled != oldModifyEnabled) {
+                UnixException ex = null;
+                for (EntryNode node: key.children().values()) {
+                    if (newModifyEnabled) {
+                        // register
+                        UnixPath path = key.getDirectory().resolve(node.name());
+                        int ev = (FILE_NOFOLLOW | FILE_MODIFIED | FILE_ATTRIB);
+                        try {
+                            long object = registerImpl(path, ev);
+                            object2Node.put(object, node);
+                            node.setObject(object);
+                        } catch (UnixException x) {
+                            // if file has been deleted then it will be detected
+                            // as a FILE_MODIFIED event on the directory
+                            if (x.errno() != ENOENT) {
+                                ex = x;
+                                break;
+                            }
+                        }
+                    } else {
+                        // unregister
+                        releaseChild(node);
+                    }
+                }
+
+                // an error occurred
+                if (ex != null) {
+                    releaseChildren(key);
+                    throw ex;
+                }
+            }
+        }
+
+        /**
+         * Calls port_associate to register the given path.
+         * Returns pointer to fileobj structure that is allocated for
+         * the registration.
+         */
+        long registerImpl(UnixPath dir, int events)
+            throws UnixException
+        {
+            // allocate memory for the path (file_obj->fo_name field)
+            byte[] path = dir.getByteArrayForSysCalls();
+            int len = path.length;
+            long name = unsafe.allocateMemory(len+1);
+            unsafe.copyMemory(path, Unsafe.ARRAY_BYTE_BASE_OFFSET, null,
+                name, (long)len);
+            unsafe.putByte(name + len, (byte)0);
+
+            // allocate memory for filedatanode structure - this is the object
+            // to port_associate
+            long object = unsafe.allocateMemory(SIZEOF_FILEOBJ);
+            unsafe.setMemory(null, object, SIZEOF_FILEOBJ, (byte)0);
+            unsafe.putAddress(object + OFFSET_FO_NAME, name);
+
+            // associate the object with the port
+            try {
+                portAssociate(port,
+                              PORT_SOURCE_FILE,
+                              object,
+                              events);
+            } catch (UnixException x) {
+                // debugging
+                if (x.errno() == EAGAIN) {
+                    System.err.println("The maximum number of objects associated "+
+                        "with the port has been reached");
+                }
+
+                unsafe.freeMemory(name);
+                unsafe.freeMemory(object);
+                throw x;
+            }
+            return object;
+        }
+
+        /**
+         * Frees all resources for an file_obj object; optionally remove
+         * association from port
+         */
+        void releaseObject(long object, boolean dissociate) {
+            // remove association
+            if (dissociate) {
+                try {
+                    portDissociate(port, PORT_SOURCE_FILE, object);
+                } catch (UnixException x) {
+                    // ignore
+                }
+            }
+
+            // free native memory
+            long name = unsafe.getAddress(object + OFFSET_FO_NAME);
+            unsafe.freeMemory(name);
+            unsafe.freeMemory(object);
+        }
+    }
+
+    /**
+     * A node with native (file_obj) resources
+     */
+    private static interface Node {
+        long object();
+    }
+
+    /**
+     * A directory node with a map of the entries in the directory
+     */
+    private static interface DirectoryNode extends Node {
+        void addChild(Path name, EntryNode node);
+        void removeChild(Path name);
+        EntryNode getChild(Path name);
+    }
+
+    /**
+     * An implementation of a node that is an entry in a directory.
+     */
+    private static class EntryNode implements Node {
+        private long object;
+        private final UnixPath name;
+        private final DirectoryNode parent;
+        private boolean visited;
+
+        EntryNode(long object, UnixPath name, DirectoryNode parent) {
+            this.object = object;
+            this.name = name;
+            this.parent = parent;
+        }
+
+        @Override
+        public long object() {
+            return object;
+        }
+
+        void setObject(long ptr) {
+            this.object = ptr;
+        }
+
+        UnixPath name() {
+            return name;
+        }
+
+        DirectoryNode parent() {
+            return parent;
+        }
+
+        boolean isVisited() {
+            return visited;
+        }
+
+        void setVisited(boolean v) {
+            this.visited = v;
+        }
+    }
+
+    // -- native methods --
+
+    private static native void init();
+
+    private static native int portCreate() throws UnixException;
+
+    private static native void portAssociate(int port, int source, long object, int events)
+        throws UnixException;
+
+    private static native void portDissociate(int port, int source, long object)
+        throws UnixException;
+
+    private static native void portSend(int port, int events)
+        throws UnixException;
+
+    private static native int portGetn(int port, long address, int max)
+        throws UnixException;
+
+    static {
+        jdk.internal.loader.BootLoader.loadLibrary("nio");
+        init();
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	2024-08-17 18:29:44.560943061 +0200
@@ -0,0 +1,51 @@
+/*
+ * Copyright (c) 2014, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+
+#include "ProcessHandleImpl_unix.h"
+
+#include <procfs.h>
+
+/*
+ * Implementation of native ProcessHandleImpl functions for Solaris.
+ * See ProcessHandleImpl_unix.c for more details.
+ */
+
+void os_initNative(JNIEnv *env, jclass clazz) {}
+
+jint os_getChildren(JNIEnv *env, jlong jpid, jlongArray jarray,
+                    jlongArray jparentArray, jlongArray jstimesArray) {
+    return unix_getChildren(env, jpid, jarray, jparentArray, jstimesArray);
+}
+
+pid_t os_getParentPidAndTimings(JNIEnv *env, pid_t pid, jlong *total, jlong *start) {
+    return unix_getParentPidAndTimings(env, pid, total, start);
+}
+
+void os_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
+    unix_getCmdlineAndUserInfo(env, jinfo, pid);
+}
+
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.c	2024-08-17 18:29:44.562047547 +0200
@@ -0,0 +1,1552 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <gelf.h>
+
+#include "libjvm_db.h"
+#include "JvmOffsets.h"
+
+#define LIBJVM_SO "libjvm.so"
+
+#if defined(i386) || defined(__i386) || defined(__amd64)
+#ifdef COMPILER2
+#define X86_COMPILER2
+#endif /* COMPILER2 */
+#endif /* i386 */
+
+typedef struct {
+    short     vf_cnt; /* number of recognized java vframes */
+    short     bci;    /* current frame method byte code index */
+    int       line;   /* current frame method source line */
+    uint64_t new_fp; /* fp for the next frame */
+    uint64_t new_pc; /* pc for the next frame */
+    uint64_t new_sp; /* "raw" sp for the next frame (includes extension by interpreter/adapter */
+    char      locinf; /* indicates there is valid location info */
+} Jframe_t;
+
+int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,
+                    size_t size, Jframe_t *jframe);
+
+int main(int arg) { return arg; }
+
+static int debug = 0;
+
+static void failed(int err, const char * file, int line) {
+  if (debug) {
+    fprintf(stderr, "failed %d at %s:%d\n", err, file, line);
+  }
+}
+
+static void warn(const char * file, int line, const char * msg) {
+  if (debug) {
+    fprintf(stderr, "warning: %s at %s:%d\n", msg, file, line);
+  }
+}
+
+static void warn1(const char * file, int line, const char * msg, intptr_t arg1) {
+  if (debug) {
+    fprintf(stderr, "warning: ");
+    fprintf(stderr, msg, arg1);
+    fprintf(stderr, " at %s:%d\n", file, line);
+  }
+}
+
+#define CHECK_FAIL(err) \
+        if (err != PS_OK) { failed(err, __FILE__, __LINE__); goto fail; }
+#define WARN(msg)  warn(__FILE__, __LINE__, msg)
+#define WARN1(msg, arg1)  warn1(__FILE__, __LINE__, msg, arg1)
+
+typedef struct VMStructEntry {
+  const char * typeName;           /* The type name containing the given field (example: "Klass") */
+  const char * fieldName;          /* The field name within the type           (example: "_name") */
+  uint64_t address;                /* Address of field; only used for static fields */
+                                   /* ("offset" can not be reused because of apparent solstudio compiler bug */
+                                   /* in generation of initializer data) */
+} VMStructEntry;
+
+/* Prototyping inlined methods */
+
+int sprintf(char *s, const char *format, ...);
+
+#define SZ16  sizeof(int16_t)
+#define SZ32  sizeof(int32_t)
+
+#define COMP_METHOD_SIGN '*'
+
+#define MAX_VFRAMES_CNT 256
+
+typedef struct vframe {
+  uint64_t method;
+  int32_t  sender_decode_offset;
+  int32_t  methodIdx;
+  int32_t  bci;
+  int32_t  line;
+} Vframe_t;
+
+typedef struct frame {
+  uintptr_t fp;
+  uintptr_t pc;
+  uintptr_t sp;
+  uintptr_t sender_sp; // The unextended sp of the caller
+} Frame_t;
+
+typedef struct Nmethod_t {
+  struct jvm_agent* J;
+  Jframe_t *jframe;
+
+  uint64_t nm;                  /* _nmethod */
+  uint64_t pc;
+  uint64_t pc_desc;
+
+  int32_t  orig_pc_offset;      /* _orig_pc_offset */
+  uint64_t  instrs_beg;          /* _code_offset */
+  uint64_t  instrs_end;
+  uint64_t  deopt_beg;           /* _deoptimize_offset */
+  uint64_t  scopes_data_beg;     /* _scopes_data_begin */
+  int32_t  scopes_data_end;
+  int32_t  metadata_beg;        /* _metadata_offset */
+  int32_t  metadata_end;
+  int32_t  scopes_pcs_beg;      /* _scopes_pcs_offset */
+  int32_t  scopes_pcs_end;
+
+  int      vf_cnt;
+  Vframe_t vframes[MAX_VFRAMES_CNT];
+} Nmethod_t;
+
+struct jvm_agent {
+  struct ps_prochandle* P;
+
+  uint64_t nmethod_vtbl;
+  uint64_t CodeBlob_vtbl;
+  uint64_t BufferBlob_vtbl;
+  uint64_t RuntimeStub_vtbl;
+  uint64_t Method_vtbl;
+
+  uint64_t Use_Compressed_Oops_address;
+  uint64_t Universe_narrow_oop_base_address;
+  uint64_t Universe_narrow_oop_shift_address;
+  uint64_t CodeCache_heaps_address;
+
+  /* Volatiles */
+  uint8_t  Use_Compressed_Oops;
+  uint64_t Universe_narrow_oop_base;
+  uint32_t Universe_narrow_oop_shift;
+  // Code cache heaps
+  int32_t  Number_of_heaps;
+  uint64_t* Heap_low;
+  uint64_t* Heap_high;
+  uint64_t* Heap_segmap_low;
+  uint64_t* Heap_segmap_high;
+
+  int32_t  SIZE_CodeCache_log2_segment;
+
+  uint64_t methodPtr;
+  uint64_t bcp;
+
+  Nmethod_t *N;                 /*Inlined methods support */
+  Frame_t   prev_fr;
+  Frame_t   curr_fr;
+};
+
+static int
+read_string(struct ps_prochandle *P,
+        char *buf,              /* caller's buffer */
+        size_t size,            /* upper limit on bytes to read */
+        uintptr_t addr)         /* address in process */
+{
+  int err = PS_OK;
+  while (size-- > 1 && err == PS_OK) {
+    err = ps_pread(P, addr, buf, 1);
+    if (*buf == '\0') {
+      return PS_OK;
+    }
+    addr += 1;
+    buf += 1;
+  }
+  return -1;
+}
+
+static int read_compressed_pointer(jvm_agent_t* J, uint64_t base, uint32_t *ptr) {
+  int err = -1;
+  uint32_t ptr32;
+  err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));
+  *ptr = ptr32;
+  return err;
+}
+
+static int read_pointer(jvm_agent_t* J, uint64_t base, uint64_t* ptr) {
+  int err = -1;
+  uint32_t ptr32;
+
+  switch (DATA_MODEL) {
+  case PR_MODEL_LP64:
+    err = ps_pread(J->P, base, ptr, sizeof(uint64_t));
+    break;
+  case PR_MODEL_ILP32:
+    err = ps_pread(J->P, base, &ptr32, sizeof(uint32_t));
+    *ptr = ptr32;
+    break;
+  }
+
+  return err;
+}
+
+static int read_string_pointer(jvm_agent_t* J, uint64_t base, const char ** stringp) {
+  uint64_t ptr;
+  int err;
+  char buffer[1024];
+
+  *stringp = NULL;
+  err = read_pointer(J, base, &ptr);
+  CHECK_FAIL(err);
+  if (ptr != 0) {
+    err = read_string(J->P, buffer, sizeof(buffer), ptr);
+    CHECK_FAIL(err);
+    *stringp = strdup(buffer);
+  }
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int parse_vmstruct_entry(jvm_agent_t* J, uint64_t base, VMStructEntry* vmp) {
+  uint64_t ptr;
+  int err;
+
+  err = read_string_pointer(J, base + OFFSET_VMStructEntrytypeName, &vmp->typeName);
+  CHECK_FAIL(err);
+  err = read_string_pointer(J, base + OFFSET_VMStructEntryfieldName, &vmp->fieldName);
+  CHECK_FAIL(err);
+  err = read_pointer(J, base + OFFSET_VMStructEntryaddress, &vmp->address);
+  CHECK_FAIL(err);
+
+  return PS_OK;
+
+ fail:
+  if (vmp->typeName != NULL) free((void*)vmp->typeName);
+  if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
+  return err;
+}
+
+static int parse_vmstructs(jvm_agent_t* J) {
+  VMStructEntry  vmVar;
+  VMStructEntry* vmp = &vmVar;
+  uint64_t gHotSpotVMStructs;
+  psaddr_t sym_addr;
+  uint64_t base;
+  int err;
+
+  /* Clear *vmp now in case we jump to fail: */
+  memset(vmp, 0, sizeof(VMStructEntry));
+
+  err = ps_pglobal_lookup(J->P, LIBJVM_SO, "gHotSpotVMStructs", &sym_addr);
+  CHECK_FAIL(err);
+  err = read_pointer(J, sym_addr, &gHotSpotVMStructs);
+  CHECK_FAIL(err);
+  base = gHotSpotVMStructs;
+
+  err = PS_OK;
+  while (err == PS_OK) {
+    memset(vmp, 0, sizeof(VMStructEntry));
+    err = parse_vmstruct_entry(J, base, vmp);
+    if (err != PS_OK || vmp->typeName == NULL) {
+      break;
+    }
+
+    if (vmp->typeName[0] == 'C' && strcmp("CodeCache", vmp->typeName) == 0) {
+      /* Read _heaps field of type GrowableArray<CodeHeaps*>*      */
+      if (strcmp("_heaps", vmp->fieldName) == 0) {
+        err = read_pointer(J, vmp->address, &J->CodeCache_heaps_address);
+      }
+    } else if (vmp->typeName[0] == 'U' && strcmp("Universe", vmp->typeName) == 0) {
+      if (strcmp("_narrow_oop._base", vmp->fieldName) == 0) {
+        J->Universe_narrow_oop_base_address = vmp->address;
+      }
+      if (strcmp("_narrow_oop._shift", vmp->fieldName) == 0) {
+        J->Universe_narrow_oop_shift_address = vmp->address;
+      }
+    }
+    CHECK_FAIL(err);
+
+    base += SIZE_VMStructEntry;
+    if (vmp->typeName != NULL) free((void*)vmp->typeName);
+    if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
+  }
+
+  return PS_OK;
+
+ fail:
+  if (vmp->typeName != NULL) free((void*)vmp->typeName);
+  if (vmp->fieldName != NULL) free((void*)vmp->fieldName);
+  return -1;
+}
+
+static int find_symbol(jvm_agent_t* J, const char *name, uint64_t* valuep) {
+  psaddr_t sym_addr;
+  int err;
+
+  err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);
+  if (err != PS_OK) goto fail;
+  *valuep = sym_addr;
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int read_volatiles(jvm_agent_t* J) {
+  int i;
+  uint64_t array_data;
+  uint64_t code_heap_address;
+  int err;
+
+  err = find_symbol(J, "UseCompressedOops", &J->Use_Compressed_Oops_address);
+  if (err == PS_OK) {
+    err = ps_pread(J->P,  J->Use_Compressed_Oops_address, &J->Use_Compressed_Oops, sizeof(uint8_t));
+    CHECK_FAIL(err);
+  } else {
+    J->Use_Compressed_Oops = 0;
+  }
+
+  err = read_pointer(J, J->Universe_narrow_oop_base_address, &J->Universe_narrow_oop_base);
+  CHECK_FAIL(err);
+  err = ps_pread(J->P,  J->Universe_narrow_oop_shift_address, &J->Universe_narrow_oop_shift, sizeof(uint32_t));
+  CHECK_FAIL(err);
+
+  /* CodeCache_heaps_address points to GrowableArray<CodeHeaps*>, read _data field
+     pointing to the first entry of type CodeCache* in the array */
+  err = read_pointer(J, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_data, &array_data);
+  /* Read _len field containing the number of code heaps */
+  err = ps_pread(J->P, J->CodeCache_heaps_address + OFFSET_GrowableArray_CodeHeap_len,
+                 &J->Number_of_heaps, sizeof(J->Number_of_heaps));
+
+  /* Allocate memory for heap configurations */
+  J->Heap_low         = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
+  J->Heap_high        = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
+  J->Heap_segmap_low  = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
+  J->Heap_segmap_high = (uint64_t*)calloc(J->Number_of_heaps, sizeof(uint64_t));
+
+  /* Read code heap configurations */
+  for (i = 0; i < J->Number_of_heaps; ++i) {
+    /* Read address of heap */
+    err = read_pointer(J, array_data, &code_heap_address);
+    CHECK_FAIL(err);
+
+    err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory +
+                       OFFSET_VirtualSpace_low, &J->Heap_low[i]);
+    CHECK_FAIL(err);
+    err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_memory +
+                       OFFSET_VirtualSpace_high, &J->Heap_high[i]);
+    CHECK_FAIL(err);
+    err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap +
+                       OFFSET_VirtualSpace_low, &J->Heap_segmap_low[i]);
+    CHECK_FAIL(err);
+    err = read_pointer(J, code_heap_address + OFFSET_CodeHeap_segmap +
+                       OFFSET_VirtualSpace_high, &J->Heap_segmap_high[i]);
+    CHECK_FAIL(err);
+
+    /* Increment pointer to next entry */
+    array_data = array_data + POINTER_SIZE;
+  }
+
+  err = ps_pread(J->P, code_heap_address + OFFSET_CodeHeap_log2_segment_size,
+                 &J->SIZE_CodeCache_log2_segment, sizeof(J->SIZE_CodeCache_log2_segment));
+  CHECK_FAIL(err);
+
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int codeheap_contains(int heap_num, jvm_agent_t* J, uint64_t ptr) {
+  return (J->Heap_low[heap_num] <= ptr && ptr < J->Heap_high[heap_num]);
+}
+
+static int codecache_contains(jvm_agent_t* J, uint64_t ptr) {
+  int i;
+  for (i = 0; i < J->Number_of_heaps; ++i) {
+    if (codeheap_contains(i, J, ptr)) {
+      return 1;
+    }
+  }
+  return 0;
+}
+
+static uint64_t segment_for(int heap_num, jvm_agent_t* J, uint64_t p) {
+  return (p - J->Heap_low[heap_num]) >> J->SIZE_CodeCache_log2_segment;
+}
+
+static uint64_t block_at(int heap_num, jvm_agent_t* J, int i) {
+  return J->Heap_low[heap_num] + (i << J->SIZE_CodeCache_log2_segment);
+}
+
+static int find_start(jvm_agent_t* J, uint64_t ptr, uint64_t *startp) {
+  int err;
+  int i;
+
+  for (i = 0; i < J->Number_of_heaps; ++i) {
+    *startp = 0;
+    if (codeheap_contains(i, J, ptr)) {
+      int32_t used;
+      uint64_t segment = segment_for(i, J, ptr);
+      uint64_t block = J->Heap_segmap_low[i];
+      uint8_t tag;
+      err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
+      CHECK_FAIL(err);
+      if (tag == 0xff)
+        return PS_OK;
+      while (tag > 0) {
+        err = ps_pread(J->P, block + segment, &tag, sizeof(tag));
+        CHECK_FAIL(err);
+        segment -= tag;
+      }
+      block = block_at(i, J, segment);
+      err = ps_pread(J->P, block + OFFSET_HeapBlockHeader_used, &used, sizeof(used));
+      CHECK_FAIL(err);
+      if (used) {
+        *startp = block + SIZE_HeapBlockHeader;
+      }
+    }
+    return PS_OK;
+  }
+
+ fail:
+  return -1;
+}
+
+static int find_jlong_constant(jvm_agent_t* J, const char *name, uint64_t* valuep) {
+  psaddr_t sym_addr;
+  int err = ps_pglobal_lookup(J->P, LIBJVM_SO, name, &sym_addr);
+  if (err == PS_OK) {
+    err = ps_pread(J->P, sym_addr, valuep, sizeof(uint64_t));
+    return err;
+  }
+  *valuep = -1;
+  return -1;
+}
+
+jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers) {
+  jvm_agent_t* J;
+  int err;
+
+  if (vers != JVM_DB_VERSION) {
+    errno = ENOTSUP;
+    return NULL;
+  }
+
+  J = (jvm_agent_t*)calloc(sizeof(struct jvm_agent), 1);
+
+  debug = getenv("LIBJVMDB_DEBUG") != NULL;
+  if (debug) debug = 3;
+
+  if (debug) {
+      fprintf(stderr, "Jagent_create: debug=%d\n", debug);
+#ifdef X86_COMPILER2
+      fprintf(stderr, "Jagent_create: R_SP=%d, R_FP=%d, POINTER_SIZE=%d\n", R_SP, R_FP, POINTER_SIZE);
+#endif  /* X86_COMPILER2 */
+  }
+
+  J->P = P;
+
+  // Initialize the initial previous frame
+
+  J->prev_fr.fp = 0;
+  J->prev_fr.pc = 0;
+  J->prev_fr.sp = 0;
+  J->prev_fr.sender_sp = 0;
+
+  err = find_symbol(J, "__1cHnmethodG__vtbl_", &J->nmethod_vtbl);
+  CHECK_FAIL(err);
+  err = find_symbol(J, "__1cKBufferBlobG__vtbl_", &J->BufferBlob_vtbl);
+  if (err != PS_OK) J->BufferBlob_vtbl = 0;
+  err = find_symbol(J, "__1cICodeBlobG__vtbl_", &J->CodeBlob_vtbl);
+  CHECK_FAIL(err);
+  err = find_symbol(J, "__1cLRuntimeStubG__vtbl_", &J->RuntimeStub_vtbl);
+  CHECK_FAIL(err);
+  err = find_symbol(J, "__1cGMethodG__vtbl_", &J->Method_vtbl);
+  CHECK_FAIL(err);
+
+  err = parse_vmstructs(J);
+  CHECK_FAIL(err);
+  err = read_volatiles(J);
+  CHECK_FAIL(err);
+
+  return J;
+
+ fail:
+  Jagent_destroy(J);
+  return NULL;
+}
+
+void Jagent_destroy(jvm_agent_t *J) {
+  if (J != NULL) {
+    free(J);
+  }
+}
+
+static int is_method(jvm_agent_t* J, uint64_t methodPtr) {
+  uint64_t klass;
+  int err = read_pointer(J, methodPtr, &klass);
+  if (err != PS_OK) goto fail;
+  return klass == J->Method_vtbl;
+
+ fail:
+  return 0;
+}
+
+static int
+name_for_methodPtr(jvm_agent_t* J, uint64_t methodPtr, char * result, size_t size)
+{
+  short nameIndex;
+  short signatureIndex;
+  uint64_t constantPool;
+  uint64_t constMethod;
+  uint64_t nameSymbol;
+  uint64_t signatureSymbol;
+  uint64_t klassPtr;
+  uint64_t klassSymbol;
+  short klassSymbolLength;
+  short nameSymbolLength;
+  short signatureSymbolLength;
+  char * nameString = NULL;
+  char * klassString = NULL;
+  char * signatureString = NULL;
+  int err;
+
+  err = read_pointer(J, methodPtr + OFFSET_Method_constMethod, &constMethod);
+  CHECK_FAIL(err);
+  err = read_pointer(J, constMethod + OFFSET_ConstMethod_constants, &constantPool);
+  CHECK_FAIL(err);
+
+  /* To get name string */
+  err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_name_index, &nameIndex, 2);
+  CHECK_FAIL(err);
+  err = read_pointer(J, constantPool + nameIndex * POINTER_SIZE + SIZE_ConstantPool, &nameSymbol);
+  CHECK_FAIL(err);
+  // The symbol is a CPSlot and has lower bit set to indicate metadata
+  nameSymbol &= (~1); // remove metadata lsb
+  err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_length, &nameSymbolLength, 2);
+  CHECK_FAIL(err);
+  nameString = (char*)calloc(nameSymbolLength + 1, 1);
+  err = ps_pread(J->P, nameSymbol + OFFSET_Symbol_body, nameString, nameSymbolLength);
+  CHECK_FAIL(err);
+
+  /* To get signature string */
+  err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_signature_index, &signatureIndex, 2);
+  CHECK_FAIL(err);
+  err = read_pointer(J, constantPool + signatureIndex * POINTER_SIZE + SIZE_ConstantPool, &signatureSymbol);
+  CHECK_FAIL(err);
+  signatureSymbol &= (~1);  // remove metadata lsb
+  err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_length, &signatureSymbolLength, 2);
+  CHECK_FAIL(err);
+  signatureString = (char*)calloc(signatureSymbolLength + 1, 1);
+  err = ps_pread(J->P, signatureSymbol + OFFSET_Symbol_body, signatureString, signatureSymbolLength);
+  CHECK_FAIL(err);
+
+  /* To get klass string */
+  err = read_pointer(J, constantPool + OFFSET_ConstantPool_pool_holder, &klassPtr);
+  CHECK_FAIL(err);
+  err = read_pointer(J, klassPtr + OFFSET_Klass_name, &klassSymbol);
+  CHECK_FAIL(err);
+  err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_length, &klassSymbolLength, 2);
+  CHECK_FAIL(err);
+  klassString = (char*)calloc(klassSymbolLength + 1, 1);
+  err = ps_pread(J->P, klassSymbol + OFFSET_Symbol_body, klassString, klassSymbolLength);
+  CHECK_FAIL(err);
+
+  result[0] = '\0';
+  if (snprintf(result, size,
+    "%s.%s%s",
+    klassString,
+    nameString,
+    signatureString) >= size) {
+    // truncation
+    goto fail;
+  }
+
+  if (nameString != NULL) free(nameString);
+  if (klassString != NULL) free(klassString);
+  if (signatureString != NULL) free(signatureString);
+
+  return PS_OK;
+
+ fail:
+  if (debug) {
+      fprintf(stderr, "name_for_methodPtr: FAIL \n\n");
+  }
+  if (nameString != NULL) free(nameString);
+  if (klassString != NULL) free(klassString);
+  if (signatureString != NULL) free(signatureString);
+  return -1;
+}
+
+static int nmethod_info(Nmethod_t *N)
+{
+  jvm_agent_t *J = N->J;
+  uint64_t    nm = N->nm;
+  int32_t err;
+
+  if (debug > 2 )
+      fprintf(stderr, "\t nmethod_info: BEGIN \n");
+
+  /* Instructions */
+  err = read_pointer(J, nm + OFFSET_CodeBlob_code_begin, &N->instrs_beg);
+  CHECK_FAIL(err);
+  err = read_pointer(J, nm + OFFSET_CodeBlob_code_end, &N->instrs_end);
+  CHECK_FAIL(err);
+  err = read_pointer(J, nm + OFFSET_nmethod_deopt_handler_begin, &N->deopt_beg);
+  CHECK_FAIL(err);
+  err = ps_pread(J->P, nm + OFFSET_nmethod_orig_pc_offset, &N->orig_pc_offset, SZ32);
+  CHECK_FAIL(err);
+
+  /* Metadata */
+  err = ps_pread(J->P, nm + OFFSET_nmethod_metadata_offset, &N->metadata_beg, SZ32);
+  CHECK_FAIL(err);
+  err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->metadata_end, SZ32);
+  CHECK_FAIL(err);
+
+  /* scopes_pcs */
+  err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_pcs_offset, &N->scopes_pcs_beg, SZ32);
+  CHECK_FAIL(err);
+  err = ps_pread(J->P, nm + OFFSET_nmethod_dependencies_offset, &N->scopes_pcs_end, SZ32);
+  CHECK_FAIL(err);
+
+  /* scopes_data */
+  err = ps_pread(J->P, nm + OFFSET_nmethod_scopes_data_begin, &N->scopes_data_beg, POINTER_SIZE);
+  CHECK_FAIL(err);
+
+  if (debug > 2 ) {
+      N->scopes_data_end = N->scopes_pcs_beg;
+
+      fprintf(stderr, "\t nmethod_info: instrs_beg: %#x, instrs_end: %#x\n",
+                       N->instrs_beg, N->instrs_end);
+
+      fprintf(stderr, "\t nmethod_info: deopt_beg: %#x \n",
+                       N->deopt_beg);
+
+      fprintf(stderr, "\t nmethod_info: orig_pc_offset: %#x \n",
+                       N->orig_pc_offset);
+
+      fprintf(stderr, "\t nmethod_info: metadata_beg: %#x, metadata_end: %#x\n",
+                       N->metadata_beg, N->metadata_end);
+
+      fprintf(stderr, "\t nmethod_info: scopes_data_beg: %#x, scopes_data_end: %#x\n",
+                       N->scopes_data_beg, N->scopes_data_end);
+
+      fprintf(stderr, "\t nmethod_info: scopes_pcs_beg: %#x, scopes_pcs_end: %#x\n",
+                       N->scopes_pcs_beg, N->scopes_pcs_end);
+
+      fprintf(stderr, "\t nmethod_info: END \n\n");
+  }
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int
+raw_read_int(jvm_agent_t* J, uint64_t *buffer, int32_t *val)
+{
+  int shift = 0;
+  int value = 0;
+  uint8_t ch = 0;
+  int32_t  err;
+  int32_t sum;
+  // Constants for UNSIGNED5 coding of Pack200
+  // see compressedStream.hpp
+  enum {
+    lg_H = 6,
+    H = 1<<lg_H,
+    BitsPerByte = 8,
+    L = (1<<BitsPerByte)-H,
+  };
+  int i;
+
+  err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t));
+  CHECK_FAIL(err);
+  if (debug > 2)
+      fprintf(stderr, "\t\t\t raw_read_int: *buffer: %#llx, ch: %#x\n", *buffer, ch);
+
+  sum = ch;
+  if ( sum >= L ) {
+    int32_t lg_H_i = lg_H;
+    // Read maximum of 5 total bytes (we've already read 1).
+    // See CompressedReadStream::read_int_mb
+    for ( i = 0;  i < 4; i++) {
+      err = ps_pread(J->P, (*buffer)++, &ch, sizeof(uint8_t));
+      CHECK_FAIL(err);
+      sum += ch << lg_H_i;
+      if (ch < L ) {
+        *val = sum;
+        return PS_OK;
+      }
+      lg_H_i += lg_H;
+    }
+  }
+  *val = sum;
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int
+read_pair(jvm_agent_t* J, uint64_t *buffer, int32_t *bci, int32_t *line)
+{
+  uint8_t next = 0;
+  int32_t bci_delta;
+  int32_t line_delta;
+  int32_t err;
+
+  if (debug > 2)
+      fprintf(stderr, "\t\t read_pair: BEGIN\n");
+
+  err = ps_pread(J->P, (*buffer)++, &next, sizeof(uint8_t));
+  CHECK_FAIL(err);
+
+  if (next == 0) {
+      if (debug > 2)
+          fprintf(stderr, "\t\t read_pair: END: next == 0\n");
+      return 1; /* stream terminated */
+  }
+  if (next == 0xFF) {
+      if (debug > 2)
+          fprintf(stderr, "\t\t read_pair: END: next == 0xFF\n");
+
+      /* Escape character, regular compression used */
+
+      err = raw_read_int(J, buffer, &bci_delta);
+      CHECK_FAIL(err);
+
+      err = raw_read_int(J, buffer, &line_delta);
+      CHECK_FAIL(err);
+
+      *bci  += bci_delta;
+      *line += line_delta;
+
+      if (debug > 2) {
+          fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n",
+                          line_delta, bci_delta);
+          fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n",
+                          *line, *bci);
+      }
+  } else {
+      /* Single byte compression used */
+      *bci  += next >> 3;
+      *line += next & 0x7;
+      if (debug > 2) {
+          fprintf(stderr, "\t\t read_pair: delta = (line %d: %d)\n",
+                          next & 0x7, next >> 3);
+          fprintf(stderr, "\t\t read_pair: unpack= (line %d: %d)\n",
+                          *line, *bci);
+      }
+  }
+  if (debug > 2)
+      fprintf(stderr, "\t\t read_pair: END\n");
+  return PS_OK;
+
+ fail:
+  if (debug)
+      fprintf(stderr, "\t\t read_pair: FAIL\n");
+  return err;
+}
+
+static int
+line_number_from_bci(jvm_agent_t* J, Vframe_t *vf)
+{
+  uint64_t buffer;
+  uint16_t code_size;
+  uint64_t code_end_delta;
+  uint64_t constMethod;
+  int8_t   access_flags;
+  int32_t  best_bci    = 0;
+  int32_t  stream_bci  = 0;
+  int32_t  stream_line = 0;
+  int32_t  err;
+
+  if (debug > 2) {
+      char name[256];
+      err = name_for_methodPtr(J, vf->method, name, 256);
+      CHECK_FAIL(err);
+      fprintf(stderr, "\t line_number_from_bci: BEGIN, method name: %s, targ bci: %d\n",
+                       name, vf->bci);
+  }
+
+  err = read_pointer(J, vf->method + OFFSET_Method_constMethod, &constMethod);
+  CHECK_FAIL(err);
+
+  vf->line = 0;
+  err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_flags, &access_flags, sizeof(int8_t));
+  CHECK_FAIL(err);
+
+  if (!(access_flags & ConstMethod_has_linenumber_table)) {
+      if (debug > 2)
+          fprintf(stderr, "\t line_number_from_bci: END: !HAS_LINE_NUMBER_TABLE \n\n");
+      return PS_OK;
+  }
+
+  /*  The line numbers are a short array of 2-tuples [start_pc, line_number].
+   *  Not necessarily sorted and not necessarily one-to-one.
+   */
+
+  err = ps_pread(J->P, constMethod + OFFSET_ConstMethod_code_size, &code_size, SZ16);
+  CHECK_FAIL(err);
+
+  /* inlined_table_start() */
+  code_end_delta = (uint64_t) (access_flags & AccessFlags_NATIVE) ? 2*POINTER_SIZE : 0;
+  buffer = constMethod + (uint64_t) SIZE_ConstMethod + (uint64_t) code_size + code_end_delta;
+
+  if (debug > 2) {
+      fprintf(stderr, "\t\t line_number_from_bci: method: %#llx, native: %d\n",
+                      vf->method, (access_flags & AccessFlags_NATIVE));
+      fprintf(stderr, "\t\t line_number_from_bci: buffer: %#llx, code_size: %d\n",
+                      buffer, (int) code_size);
+  }
+
+  while (read_pair(J, &buffer, &stream_bci, &stream_line) == 0) {
+      if (stream_bci == vf->bci) {
+          /* perfect match */
+          if (debug > 2)
+              fprintf(stderr, "\t line_number_from_bci: END: exact line: %d \n\n", vf->line);
+          vf->line = stream_line;
+          return PS_OK;
+      } else {
+          /* update best_bci/line */
+          if (stream_bci < vf->bci && stream_bci >= best_bci) {
+              best_bci = stream_bci;
+              vf->line = stream_line;
+              if (debug > 2) {
+                  fprintf(stderr, "\t line_number_from_bci: best_bci: %d, best_line: %d\n",
+                                   best_bci, vf->line);
+              }
+          }
+      }
+  }
+  if (debug > 2)
+      fprintf(stderr, "\t line_number_from_bci: END: line: %d \n\n", vf->line);
+  return PS_OK;
+
+ fail:
+  if (debug)
+      fprintf(stderr, "\t line_number_from_bci: FAIL\n");
+  return err;
+}
+
+static int
+get_real_pc(Nmethod_t *N, uint64_t pc_desc, uint64_t *real_pc)
+{
+  int32_t pc_offset;
+  int32_t err;
+
+  err = ps_pread(N->J->P, pc_desc + OFFSET_PcDesc_pc_offset, &pc_offset, SZ32);
+  CHECK_FAIL(err);
+
+  *real_pc = N->instrs_beg + pc_offset;
+  if (debug > 2) {
+      fprintf(stderr, "\t\t get_real_pc: pc_offset: %lx, real_pc: %llx\n",
+                       pc_offset, *real_pc);
+  }
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+/* Finds a PcDesc with real-pc equal to N->pc */
+static int pc_desc_at(Nmethod_t *N)
+{
+  uint64_t pc_diff = 999;
+  int32_t offs;
+  int32_t err;
+
+  if (debug > 2)
+      fprintf(stderr, "\t pc_desc_at: BEGIN\n");
+
+  N->vf_cnt  = 0;
+  N->pc_desc = 0;
+
+  for (offs = N->scopes_pcs_beg; offs < N->scopes_pcs_end; offs += SIZE_PcDesc) {
+      uint64_t pd;
+      uint64_t best_pc_diff = 16;       /* some approximation */
+      uint64_t real_pc = 0;
+
+      pd = N->nm + offs;
+      err = get_real_pc(N, pd, &real_pc);
+      CHECK_FAIL(err);
+
+      pc_diff = real_pc - N->pc;
+
+      /* In general, this fragment should work */
+      if (pc_diff == 0) {
+          N->pc_desc = pd;
+          if (debug) {
+            fprintf(stderr, "\t pc_desc_at: END: pc_desc: FOUND: %#lx \n\n", pd);
+          }
+          return PS_OK;
+      }
+      /* This fragment is to be able to find out an appropriate
+       * pc_desc entry even if pc_desc info is inaccurate.
+       */
+      if (best_pc_diff > pc_diff && pc_diff > 0) {
+          best_pc_diff = pc_diff;
+          N->pc_desc = pd;
+      }
+  }
+  if (debug) {
+      fprintf(stderr, "\t pc_desc_at: END: pc_desc NOT FOUND");
+      if (pc_diff < 20)
+          fprintf(stderr, ", best pc_diff: %d\n\n", pc_diff);
+      else
+          fprintf(stderr, "\n\n");
+  }
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int
+scope_desc_at(Nmethod_t *N, int32_t decode_offset, Vframe_t *vf)
+{
+  uint64_t buffer;
+  int32_t  err;
+
+  if (debug > 2) {
+      fprintf(stderr, "\t\t scope_desc_at: BEGIN \n");
+  }
+
+  buffer = N->scopes_data_beg + decode_offset;
+
+  err = raw_read_int(N->J, &buffer, &vf->sender_decode_offset);
+  CHECK_FAIL(err);
+
+  err = raw_read_int(N->J, &buffer, &vf->methodIdx);
+  CHECK_FAIL(err);
+
+  err = raw_read_int(N->J, &buffer, &vf->bci);
+  CHECK_FAIL(err);
+
+  if (debug > 2) {
+      fprintf(stderr, "\t\t scope_desc_at: sender_decode_offset: %#x\n",
+                      vf->sender_decode_offset);
+      fprintf(stderr, "\t\t scope_desc_at: methodIdx: %d\n", vf->methodIdx);
+      fprintf(stderr, "\t\t scope_desc_at: bci: %d\n", vf->bci);
+
+      fprintf(stderr, "\t\t scope_desc_at: END \n\n");
+  }
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+static int scopeDesc_chain(Nmethod_t *N) {
+  int32_t decode_offset = 0;
+  int32_t err;
+
+  if (debug > 2) {
+    fprintf(stderr, "\t scopeDesc_chain: BEGIN\n");
+  }
+
+  err = ps_pread(N->J->P, N->pc_desc + OFFSET_PcDesc_scope_decode_offset,
+                 &decode_offset, SZ32);
+  CHECK_FAIL(err);
+
+  while (decode_offset > 0) {
+    Vframe_t *vf = &N->vframes[N->vf_cnt];
+
+    if (debug > 2) {
+      fprintf(stderr, "\t scopeDesc_chain: decode_offset: %#x\n", decode_offset);
+    }
+
+    err = scope_desc_at(N, decode_offset, vf);
+    CHECK_FAIL(err);
+
+    if (vf->methodIdx > ((N->metadata_end - N->metadata_beg) / POINTER_SIZE)) {
+      fprintf(stderr, "\t scopeDesc_chain: (methodIdx > metadata length) !\n");
+      return -1;
+    }
+    err = read_pointer(N->J, N->nm + N->metadata_beg + (vf->methodIdx-1)*POINTER_SIZE,
+                       &vf->method);
+    CHECK_FAIL(err);
+
+    if (vf->method) {
+      N->vf_cnt++;
+      err = line_number_from_bci(N->J, vf);
+      CHECK_FAIL(err);
+      if (debug > 2) {
+        fprintf(stderr, "\t scopeDesc_chain: method: %#8llx, line: %d\n",
+                vf->method, vf->line);
+      }
+    }
+    decode_offset = vf->sender_decode_offset;
+  }
+  if (debug > 2) {
+    fprintf(stderr, "\t scopeDesc_chain: END \n\n");
+  }
+  return PS_OK;
+
+ fail:
+  if (debug) {
+    fprintf(stderr, "\t scopeDesc_chain: FAIL \n\n");
+  }
+  return err;
+}
+
+
+static int
+name_for_nmethod(jvm_agent_t* J,
+                 uint64_t nm,
+                 uint64_t pc,
+                 uint64_t method,
+                 char *result,
+                 size_t size,
+                 Jframe_t *jframe
+) {
+  Nmethod_t *N;
+  Vframe_t *vf;
+  int32_t err;
+  int deoptimized = 0;
+
+  if (debug) {
+      fprintf(stderr, "name_for_nmethod: BEGIN: nmethod: %#llx, pc: %#llx\n", nm, pc);
+  }
+  if (J->N == NULL) {
+    J->N = (Nmethod_t *) malloc(sizeof(Nmethod_t));
+  }
+  memset(J->N, 0, sizeof(Nmethod_t));   /* Initial stat: all values are zeros */
+  N     = J->N;
+  N->J  = J;
+  N->nm = nm;
+  N->pc = pc;
+  N->jframe = jframe;
+
+  err = nmethod_info(N);
+  CHECK_FAIL(err);
+  if (debug) {
+      fprintf(stderr, "name_for_nmethod: pc: %#llx, deopt_pc:  %#llx\n",
+              pc, N->deopt_beg);
+  }
+
+  /* check for a deoptimized frame */
+  if ( pc == N->deopt_beg) {
+    uint64_t base;
+    if (debug) {
+        fprintf(stderr, "name_for_nmethod: found deoptimized frame\n");
+    }
+    if (J->prev_fr.sender_sp != 0) {
+      base = J->prev_fr.sender_sp + N->orig_pc_offset;
+    } else {
+      base = J->curr_fr.sp + N->orig_pc_offset;
+    }
+    err = read_pointer(J, base, &N->pc);
+    CHECK_FAIL(err);
+    if (debug) {
+        fprintf(stderr, "name_for_nmethod: found deoptimized frame converting pc from %#8llx to %#8llx\n",
+        pc,  N->pc);
+    }
+    deoptimized = 1;
+  }
+
+  err = pc_desc_at(N);
+  CHECK_FAIL(err);
+
+  if (N->pc_desc > 0) {
+      jframe->locinf = 1;
+      err = scopeDesc_chain(N);
+      CHECK_FAIL(err);
+  }
+  result[0] = COMP_METHOD_SIGN;
+  vf = &N->vframes[0];
+  if (N->vf_cnt > 0) {
+      jframe->vf_cnt = N->vf_cnt;
+      jframe->bci  = vf->bci;
+      jframe->line = vf->line;
+      err = name_for_methodPtr(J, N->vframes[0].method, result+1, size-1);
+      CHECK_FAIL(err);
+  } else {
+      err = name_for_methodPtr(J, method, result+1, size-1);
+      CHECK_FAIL(err);
+  }
+  if (deoptimized) {
+    strncat(result, " [deoptimized frame]; ", size - strlen(result) - 1);
+  } else {
+    strncat(result, " [compiled] ", size - strlen(result) - 1);
+  }
+  if (debug)
+      fprintf(stderr, "name_for_nmethod: END: method name: %s, vf_cnt: %d\n\n",
+                      result, N->vf_cnt);
+  return PS_OK;
+
+ fail:
+  if (debug)
+      fprintf(stderr, "name_for_nmethod: FAIL \n\n");
+  return err;
+}
+
+static int
+name_for_imethod(jvm_agent_t* J,
+                 uint64_t bcp,
+                 uint64_t method,
+                 char *result,
+                 size_t size,
+                 Jframe_t *jframe
+) {
+  uint64_t bci;
+  uint64_t constMethod;
+  Vframe_t vframe = {0};
+  Vframe_t *vf = &vframe;
+  int32_t   err;
+
+  err = read_pointer(J, method + OFFSET_Method_constMethod, &constMethod);
+  CHECK_FAIL(err);
+
+  bci = bcp - (constMethod + (uint64_t) SIZE_ConstMethod);
+
+  if (debug)
+      fprintf(stderr, "\t name_for_imethod: BEGIN: method: %#llx\n", method);
+
+  err = name_for_methodPtr(J, method, result, size);
+  CHECK_FAIL(err);
+  if (debug)
+      fprintf(stderr, "\t name_for_imethod: method name: %s\n", result);
+
+  if (bci > 0) {
+      vf->method = method;
+      vf->bci       = bci;
+      err = line_number_from_bci(J, vf);
+      CHECK_FAIL(err);
+  }
+  jframe->bci  = vf->bci;
+  jframe->line = vf->line;
+  jframe->locinf = 1;
+
+  if (debug) {
+      fprintf(stderr, "\t name_for_imethod: END: bci: %d, line: %d\n\n",
+                      vf->bci, vf->line);
+  }
+  return PS_OK;
+
+ fail:
+  if (debug)
+      fprintf(stderr, "\t name_for_imethod: FAIL\n");
+  return err;
+}
+
+static int
+name_for_codecache(jvm_agent_t* J, uint64_t fp, uint64_t pc, char * result,
+                   size_t size, Jframe_t *jframe, int* is_interpreted)
+{
+  uint64_t start;
+  uint64_t vtbl;
+  int32_t err;
+  *is_interpreted = 0;
+
+  result[0] = '\0';
+
+  err = find_start(J, pc, &start);
+  CHECK_FAIL(err);
+
+  err = read_pointer(J, start, &vtbl);
+  CHECK_FAIL(err);
+
+  if (vtbl == J->nmethod_vtbl) {
+    uint64_t method;
+
+    err = read_pointer(J, start + OFFSET_nmethod_method, &method);
+    CHECK_FAIL(err);
+
+    if (debug) {
+        fprintf(stderr, "name_for_codecache: start: %#8llx, pc: %#8llx, method: %#8llx \n",
+                        start, pc, method);
+    }
+    err = name_for_nmethod(J, start, pc, method, result, size, jframe);
+    CHECK_FAIL(err);
+  } else if (vtbl == J->BufferBlob_vtbl) {
+    const char * name;
+
+    err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name);
+
+    /*
+     * Temporary usage of string "Interpreter".
+     * We need some other way to distinguish "StubRoutines"
+     * and regular interpreted frames.
+     */
+    if (err == PS_OK && strncmp(name, "Interpreter", 11) == 0) {
+      *is_interpreted = 1;
+      if (is_method(J, J->methodPtr)) {
+        return name_for_imethod(J, J->bcp, J->methodPtr, result, size, jframe);
+      }
+    }
+
+    if (err == PS_OK) {
+      strncpy(result, name, size);
+      free((void*)name);
+    } else {
+      strncpy(result, "<unknown BufferBlob>", size);
+    }
+    /* return PS_OK; */
+  } else {
+    const char * name;
+
+    err = read_string_pointer(J, start + OFFSET_CodeBlob_name, &name);
+    if (err == PS_OK) {
+      strncpy(result, name, size);
+      free((void*)name);
+    } else {
+      strncpy(result, "<unknown CodeBlob>", size);
+      WARN1("unknown CodeBlob: vtbl = 0x%x", vtbl);
+    }
+  }
+  result[size-1] = '\0';
+
+#ifdef X86_COMPILER2
+  if (vtbl != J->RuntimeStub_vtbl) {
+    uint64_t trial_pc;
+    int frame_size;
+    err = ps_pread(J->P, start + OFFSET_CodeBlob_frame_size,
+                         &frame_size, SZ32);
+    CHECK_FAIL(err);
+
+    // frame_size is in words, we want bytes.
+    frame_size *= POINTER_SIZE; /* word => byte conversion */
+
+    /*
+      Because c2 doesn't use FP as a framepointer the value of sp/fp we receive
+      in the initial entry to a set of stack frames containing server frames
+      will pretty much be nonsense. We can detect that nonsense by looking to
+      see if the PC we received is correct if we look at the expected storage
+      location in relation to the FP (ie. POINTER_SIZE(FP) )
+    */
+
+    err = read_pointer(J, fp + POINTER_SIZE , &trial_pc);
+    if ( (err != PS_OK || trial_pc != pc) && frame_size > 0 ) {
+      // Either we couldn't even read at the "fp" or the pc didn't match
+      // both are sure clues that the fp is bogus. We no search the stack
+      // for a reasonable number of words trying to find the bogus fp
+      // and the current pc in adjacent words. The we will be able to
+      // deduce an approximation of the frame pointer and actually get
+      // the correct stack pointer. Which we can then unwind for the
+      // next frame.
+      int i;
+      uint64_t check;
+      uint64_t base = J->curr_fr.sp;
+      uint64_t prev_fp = 0;
+      for ( i = 0; i < frame_size * 5 ; i++, base += POINTER_SIZE ) {
+        err = read_pointer(J, base , &check);
+        CHECK_FAIL(err);
+        if (check == fp) {
+          base += POINTER_SIZE;
+          err = read_pointer(J, base , &check);
+          CHECK_FAIL(err);
+          if (check == pc) {
+            if (debug) {
+              fprintf(stderr, "name_for_codecache: found matching fp/pc combo at 0x%llx\n", base - POINTER_SIZE);
+            }
+            prev_fp = base - 2 * POINTER_SIZE;
+            break;
+          }
+        }
+      }
+      if ( prev_fp != 0 ) {
+        // real_sp is the sp we should have received for this frame
+        uint64_t real_sp = prev_fp + 2 * POINTER_SIZE;
+        // +POINTER_SIZE because callee owns the return address so caller's sp is +1 word
+        jframe->new_sp = real_sp + frame_size + POINTER_SIZE;
+        err = read_pointer(J, jframe->new_sp - POINTER_SIZE , &jframe->new_pc);
+        CHECK_FAIL(err);
+        err = read_pointer(J, jframe->new_sp - 2*POINTER_SIZE, &jframe->new_fp);
+        CHECK_FAIL(err);
+        return PS_OK;
+      }
+    }
+
+    /* A prototype to workaround FP absence */
+    /*
+     * frame_size can be 0 for StubRoutines (1) frame.
+     * In this case it should work with fp as usual.
+     */
+    if (frame_size > 0) {
+      jframe->new_fp = J->prev_fr.fp + frame_size;
+      jframe->new_sp = jframe->new_fp + 2 * POINTER_SIZE;
+    } else {
+      memset(&J->curr_fr, 0, sizeof(Frame_t));
+      err = read_pointer(J,  fp, &jframe->new_fp);
+      CHECK_FAIL(err);
+
+      err = read_pointer(J,  jframe->new_fp + POINTER_SIZE,  &jframe->new_pc);
+      CHECK_FAIL(err);
+    }
+    if (debug) {
+      fprintf(stderr, "name_for_codecache: %s, frame_size=%#lx\n",
+                       result, frame_size);
+      fprintf(stderr, "name_for_codecache: prev_fr.fp=%#lx, fp=%#lx\n",
+                       J->prev_fr.fp, jframe->new_fp);
+    }
+  }
+#endif /* X86_COMPILER2 */
+
+  return PS_OK;
+
+ fail:
+  return err;
+}
+
+int Jget_vframe(jvm_agent_t* J, int vframe_no,
+                char *name, size_t size, Jframe_t *jframe)
+{
+  Nmethod_t *N = J->N;
+  Vframe_t  *vf;
+  int32_t   err;
+
+  if (vframe_no >= N->vf_cnt) {
+     (void) sprintf(name, "Wrong inlinedMethod%1d()", vframe_no);
+     return -1;
+  }
+  vf = N->vframes + vframe_no;
+  name[0] = COMP_METHOD_SIGN;
+  err = name_for_methodPtr(J, vf->method, name + 1, size);
+  CHECK_FAIL(err);
+
+  jframe->bci = vf->bci;
+  jframe->line = vf->line;
+  if (debug) {
+      fprintf(stderr, "\t Jget_vframe: method name: %s, line: %d\n",
+                       name, vf->line);
+  }
+  return PS_OK;
+
+ fail:
+  if (debug) {
+      fprintf(stderr, "\t Jget_vframe: FAIL\n");
+  }
+  return err;
+}
+
+#define MAX_SYM_SIZE 256
+
+int Jlookup_by_regs(jvm_agent_t* J, const prgregset_t regs, char *name,
+                    size_t size, Jframe_t *jframe) {
+  uintptr_t fp;
+  uintptr_t pc;
+  /* arguments given to read_pointer need to be worst case sized */
+  uint64_t methodPtr = 0;
+  uint64_t sender_sp;
+  uint64_t bcp = 0;
+  int is_interpreted = 0;
+  int result = PS_OK;
+  int err = PS_OK;
+
+  if (J == NULL) {
+    return -1;
+  }
+
+  jframe->vf_cnt = 1;
+  jframe->new_fp = 0;
+  jframe->new_pc = 0;
+  jframe->line   = 0;
+  jframe->bci    = 0;
+  jframe->locinf = 0;
+
+  read_volatiles(J);
+  pc = (uintptr_t) regs[R_PC];
+  J->curr_fr.pc = pc;
+  J->curr_fr.fp = regs[R_FP];
+  J->curr_fr.sp = regs[R_SP];
+
+  if (debug)
+      fprintf(stderr, "Jlookup_by_regs: BEGINs: fp=%#lx, pc=%#lx\n", regs[R_FP], pc);
+
+#if defined(i386) || defined(__i386) || defined(__amd64)
+
+    fp = (uintptr_t) regs[R_FP];
+    if (J->prev_fr.fp == 0) {
+#ifdef X86_COMPILER2
+        /* A workaround for top java frames */
+        J->prev_fr.fp = (uintptr_t)(regs[R_SP] - 2 * POINTER_SIZE);
+#else
+        J->prev_fr.fp = (uintptr_t)(regs[R_SP] - POINTER_SIZE);
+#endif /* COMPILER2 */
+    }
+    if (debug > 2) {
+        printf("Jlookup_by_regs: J->prev_fr.fp = %#lx\n", J->prev_fr.fp);
+    }
+
+    if (read_pointer(J,  fp + OFFSET_interpreter_frame_method, &methodPtr) != PS_OK) {
+      methodPtr = 0;
+    }
+    if (read_pointer(J,  fp + OFFSET_interpreter_frame_sender_sp, &sender_sp) != PS_OK) {
+      sender_sp = 0;
+    }
+    if (read_pointer(J,  fp + OFFSET_interpreter_frame_bcp_offset, &bcp) != PS_OK) {
+      bcp = 0;
+    }
+#endif /* i386 */
+
+  J->methodPtr = methodPtr;
+  J->bcp = bcp;
+
+  /* On x86 with C2 JVM: native frame may have wrong regs[R_FP]
+   * For example: JVM_SuspendThread frame poins to the top interpreted frame.
+   * If we call is_method(J, methodPtr) before codecache_contains(J, pc)
+   * then we go over and omit both: nmethod and I2CAdapter frames.
+   * Note, that regs[R_PC] is always correct if frame defined correctly.
+   * So it is better to call codecache_contains(J, pc) from the beginning.
+   */
+#ifndef X86_COMPILER2
+  if (is_method(J, J->methodPtr)) {
+    result = name_for_imethod(J, bcp, J->methodPtr, name, size, jframe);
+    /* If the methodPtr is a method then this is highly likely to be
+       an interpreter frame */
+    if (result >= 0) {
+      is_interpreted = 1;
+    }
+  } else
+#endif /* ! X86_COMPILER2 */
+
+  if (codecache_contains(J, pc)) {
+    result = name_for_codecache(J, fp, pc, name, size, jframe, &is_interpreted);
+  }
+#ifdef X86_COMPILER2
+  else if (is_method(J, J->methodPtr)) {
+    result = name_for_imethod(J, bcp, J->methodPtr, name, size, jframe);
+    /* If the methodPtr is a method then this is highly likely to be
+       an interpreter frame */
+    if (result >= 0) {
+      is_interpreted = 1;
+    }
+  }
+#endif /* X86_COMPILER2 */
+  else {
+    if (debug) {
+        fprintf(stderr, "Jlookup_by_regs: END with -1\n\n");
+    }
+    result = -1;
+  }
+  if (!is_interpreted) {
+    sender_sp = 0;
+  }
+  J->curr_fr.sender_sp = sender_sp;
+
+#ifdef X86_COMPILER2
+  if (!J->curr_fr.fp) {
+    J->curr_fr.fp = (jframe->new_fp) ? jframe->new_fp : (uintptr_t)regs[R_FP];
+  }
+  if (!jframe->new_pc && jframe->new_fp) {
+    // This seems dubious
+    read_pointer(J,  jframe->new_fp + POINTER_SIZE,  &jframe->new_pc);
+    CHECK_FAIL(err);
+    if (debug > 2) {
+        printf("Jlookup_by_regs: (update pc) jframe->new_fp: %#llx, jframe->new_pc: %#llx\n",
+               jframe->new_fp, jframe->new_pc);
+    }
+  }
+
+#endif /* X86_COMPILER2 */
+  J->prev_fr = J->curr_fr;
+
+  if (debug)
+      fprintf(stderr, "Jlookup_by_regs: END\n\n");
+
+  return result;
+
+ fail:
+  return err;
+}
+
+void update_gregs(prgregset_t gregs, Jframe_t jframe) {
+#ifdef X86_COMPILER2
+    if (debug > 0) {
+      fprintf(stderr, "update_gregs: before update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);
+    }
+    /*
+     * A workaround for java C2 frames with unconventional FP.
+     * may have to modify regset with new values for FP/PC/SP when needed.
+     */
+     if (jframe.new_sp) {
+         *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) jframe.new_sp;
+     } else {
+         // *((uintptr_t *) &gregs[R_SP]) = (uintptr_t) gregs[R_FP] + 2 * POINTER_SIZE;
+     }
+
+     if (jframe.new_fp) {
+         *((uintptr_t *) &gregs[R_FP]) = (uintptr_t) jframe.new_fp;
+     }
+     if (jframe.new_pc) {
+         *((uintptr_t *) &gregs[R_PC]) = (uintptr_t) jframe.new_pc;
+     }
+    if (debug > 0) {
+      fprintf(stderr, "update_gregs: after update sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);
+    }
+#endif  /* X86_COMPILER2 */
+}
+
+/*
+ * Iterates over java frames at current location given by 'gregs'.
+ *
+ *  Returns -1 if no java frames are present or if an error is encountered.
+ *  Returns the result of calling 'func' if the return value is non-zero.
+ *  Returns 0 otherwise.
+ */
+int Jframe_iter(jvm_agent_t *J, prgregset_t gregs, java_stack_f *func, void* cld) {
+    char buf[MAX_SYM_SIZE + 1];
+    Jframe_t jframe;
+    int i = 0, res;
+#ifdef X86_COMPILER2
+    if (debug > 0) {
+      fprintf(stderr, "Jframe_iter: Entry sp = 0x%llx, fp = 0x%llx, pc = 0x%llx\n", gregs[R_SP], gregs[R_FP], gregs[R_PC]);
+    }
+#endif  /* X86_COMPILER2 */
+
+    memset(&jframe, 0, sizeof(Jframe_t));
+    memset(buf, 0, sizeof(buf));
+    res =  Jlookup_by_regs(J, gregs, buf, sizeof(buf), &jframe);
+    if (res != PS_OK)
+        return (-1);
+
+
+    res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1,
+               jframe.line, NULL);
+    if (res != 0) {
+        update_gregs(gregs, jframe);
+        return (res);
+    }
+    for (i = 1; i < jframe.vf_cnt; i++) {
+        Jget_vframe(J, i, buf, sizeof(buf), &jframe);
+        res = func(cld, gregs, buf, (jframe.locinf)? jframe.bci : -1,
+                   jframe.line, NULL);
+        if (res != 0) {
+            update_gregs(gregs, jframe);
+            return (res);
+        }
+    }
+    update_gregs(gregs, jframe);
+    return (0);
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.h jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_db/libjvm_db.h	2024-08-17 18:29:44.562365407 +0200
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2003, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef OS_SOLARIS_DTRACE_LIBJVM_DB_H
+#define OS_SOLARIS_DTRACE_LIBJVM_DB_H
+
+#include <proc_service.h>
+#include "jni.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+typedef struct jvm_agent jvm_agent_t;
+
+#define JVM_DB_VERSION  1
+
+JNIEXPORT jvm_agent_t *Jagent_create(struct ps_prochandle *P, int vers);
+
+/*
+ * Called from Jframe_iter() for each java frame.  If it returns 0, then
+ * Jframe_iter() proceeds to the next frame.  Otherwise, the return value is
+ * immediately returned to the caller of Jframe_iter().
+ *
+ * Parameters:
+ *    'cld' is client supplied data (to maintain iterator state, if any).
+ *    'name' is java method name.
+ *    'bci' is byte code index. it will be -1 if not available.
+ *    'line' is java source line number. it will be 0 if not available.
+ *    'handle' is an abstract client handle, reserved for future expansions
+ */
+
+typedef int java_stack_f(void *cld, const prgregset_t regs, const char* name, int bci, int line, void *handle);
+
+/*
+ * Iterates over the java frames at the current location.  Returns -1 if no java
+ * frames were found, or if there was some unrecoverable error.  Otherwise,
+ * returns the last value returned from 'func'.
+ */
+JNIEXPORT int Jframe_iter(jvm_agent_t *agent, prgregset_t gregs, java_stack_f *func, void* cld);
+
+JNIEXPORT void Jagent_destroy(jvm_agent_t *J);
+
+#ifdef __cplusplus
+} /* extern "C" */
+#endif /* __cplusplus */
+
+#endif // OS_SOLARIS_DTRACE_LIBJVM_DB_H
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c	2024-08-17 18:29:44.563158133 +0200
@@ -0,0 +1,562 @@
+/*
+ * Copyright (c) 2006, 2015, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <poll.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <thread.h>
+#include <unistd.h>
+#include "jvm_dtrace.h"
+
+// NOTE: These constants are used in JVM code as well.
+// KEEP JVM CODE IN SYNC if you are going to change these...
+
+#define DTRACE_ALLOC_PROBES   0x1
+#define DTRACE_METHOD_PROBES  0x2
+#define DTRACE_MONITOR_PROBES 0x4
+#define DTRACE_ALL_PROBES     -1
+
+// generic error messages
+#define JVM_ERR_OUT_OF_MEMORY            "out of memory (native heap)"
+#define JVM_ERR_INVALID_PARAM            "invalid input parameter(s)"
+#define JVM_ERR_NULL_PARAM               "input paramater is NULL"
+
+// error messages for attach
+#define JVM_ERR_CANT_OPEN_DOOR           "cannot open door file"
+#define JVM_ERR_CANT_CREATE_ATTACH_FILE  "cannot create attach file"
+#define JVM_ERR_DOOR_FILE_PERMISSION     "door file is not secure"
+#define JVM_ERR_CANT_SIGNAL              "cannot send SIGQUIT to target"
+
+// error messages for enable probe
+#define JVM_ERR_DOOR_CMD_SEND            "door command send failed"
+#define JVM_ERR_DOOR_CANT_READ_STATUS    "cannot read door command status"
+#define JVM_ERR_DOOR_CMD_STATUS          "door command error status"
+
+// error message for detach
+#define JVM_ERR_CANT_CLOSE_DOOR          "cannot close door file"
+
+#define RESTARTABLE(_cmd, _result) do { \
+    do { \
+        _result = _cmd; \
+    } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+struct _jvm_t {
+    pid_t pid;
+    int door_fd;
+};
+
+static int libjvm_dtrace_debug;
+static void print_debug(const char* fmt,...) {
+    if (libjvm_dtrace_debug) {
+        va_list alist;
+        va_start(alist, fmt);
+        fputs("libjvm_dtrace DEBUG: ", stderr);
+        vfprintf(stderr, fmt, alist);
+        va_end(alist);
+    }
+}
+
+/* Key for thread local error message */
+static thread_key_t jvm_error_key;
+
+/* init function for this library */
+static void init_jvm_dtrace() {
+    /* check for env. var for debug mode */
+    libjvm_dtrace_debug = getenv("LIBJVM_DTRACE_DEBUG") != NULL;
+    /* create key for thread local error message */
+    if (thr_keycreate(&jvm_error_key, NULL) != 0) {
+        print_debug("can't create thread_key_t for jvm error key\n");
+        // exit(1); ?
+    }
+}
+
+#pragma init(init_jvm_dtrace)
+
+/* set thread local error message */
+static void set_jvm_error(const char* msg) {
+    thr_setspecific(jvm_error_key, (void*)msg);
+}
+
+/* clear thread local error message */
+static void clear_jvm_error() {
+    thr_setspecific(jvm_error_key, NULL);
+}
+
+/* file handling functions that can handle interrupt */
+
+static int file_open(const char* path, int flag) {
+    int ret;
+    RESTARTABLE(open(path, flag), ret);
+    return ret;
+}
+
+static int file_close(int fd) {
+    return close(fd);
+}
+
+static int file_read(int fd, char* buf, int len) {
+    int ret;
+    RESTARTABLE(read(fd, buf, len), ret);
+    return ret;
+}
+
+/* send SIGQUIT signal to given process */
+static int send_sigquit(pid_t pid) {
+    int ret;
+    RESTARTABLE(kill(pid, SIGQUIT), ret);
+    return ret;
+}
+
+/* called to check permissions on attach file */
+static int check_permission(const char* path) {
+    struct stat64 sb;
+    uid_t uid, gid;
+    int res;
+
+    /*
+     * Check that the path is owned by the effective uid/gid of this
+     * process. Also check that group/other access is not allowed.
+     */
+    uid = geteuid();
+    gid = getegid();
+
+    res = stat64(path, &sb);
+    if (res != 0) {
+        print_debug("stat failed for %s\n", path);
+        return -1;
+    }
+
+    if ((sb.st_uid != uid) || (sb.st_gid != gid) ||
+        ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0)) {
+        print_debug("well-known file %s is not secure\n", path);
+        return -1;
+    }
+    return 0;
+}
+
+#define ATTACH_FILE_PATTERN "/tmp/.attach_pid%d"
+
+/* fill-in the name of attach file name in given buffer */
+static void fill_attach_file_name(char* path, int len, pid_t pid) {
+    memset(path, 0, len);
+    sprintf(path, ATTACH_FILE_PATTERN, pid);
+}
+
+#define DOOR_FILE_PATTERN "/tmp/.java_pid%d"
+
+/* open door file for the given JVM */
+static int open_door(pid_t pid) {
+    char path[PATH_MAX + 1];
+    int fd;
+
+    sprintf(path, DOOR_FILE_PATTERN, pid);
+    fd = file_open(path, O_RDONLY);
+    if (fd < 0) {
+        set_jvm_error(JVM_ERR_CANT_OPEN_DOOR);
+        print_debug("cannot open door file %s\n", path);
+        return -1;
+    }
+    print_debug("opened door file %s\n", path);
+    if (check_permission(path) != 0) {
+        set_jvm_error(JVM_ERR_DOOR_FILE_PERMISSION);
+        print_debug("check permission failed for %s\n", path);
+        file_close(fd);
+        fd = -1;
+    }
+    return fd;
+}
+
+/* create attach file for given process */
+static int create_attach_file(pid_t pid) {
+    char path[PATH_MAX + 1];
+    int fd;
+    fill_attach_file_name(path, sizeof(path), pid);
+    fd = file_open(path, O_CREAT | O_RDWR);
+    if (fd < 0) {
+        set_jvm_error(JVM_ERR_CANT_CREATE_ATTACH_FILE);
+        print_debug("cannot create file %s\n", path);
+    } else {
+        print_debug("created attach file %s\n", path);
+    }
+    return fd;
+}
+
+/* delete attach file for given process */
+static void delete_attach_file(pid_t pid) {
+    char path[PATH_MAX + 1];
+    fill_attach_file_name(path, sizeof(path), pid);
+    int res = unlink(path);
+    if (res) {
+        print_debug("cannot delete attach file %s\n", path);
+    } else {
+        print_debug("deleted attach file %s\n", path);
+    }
+}
+
+/* attach to given JVM */
+jvm_t* jvm_attach(pid_t pid) {
+    jvm_t* jvm;
+    int door_fd, attach_fd, i = 0;
+
+    jvm = (jvm_t*) calloc(1, sizeof(jvm_t));
+    if (jvm == NULL) {
+        set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
+        print_debug("calloc failed in %s at %d\n", __FILE__, __LINE__);
+        return NULL;
+    }
+    jvm->pid = pid;
+    attach_fd = -1;
+
+    door_fd = open_door(pid);
+    if (door_fd < 0) {
+        print_debug("trying to create attach file\n");
+        if ((attach_fd = create_attach_file(pid)) < 0) {
+            goto quit;
+        }
+
+        /* send QUIT signal to the target so that it will
+         * check for the attach file.
+         */
+        if (send_sigquit(pid) != 0) {
+            set_jvm_error(JVM_ERR_CANT_SIGNAL);
+            print_debug("sending SIGQUIT failed\n");
+            goto quit;
+        }
+
+        /* give the target VM time to start the attach mechanism */
+        do {
+            int res;
+            RESTARTABLE(poll(0, 0, 200), res);
+            door_fd = open_door(pid);
+            i++;
+        } while (i <= 50 && door_fd == -1);
+        if (door_fd < 0) {
+            print_debug("Unable to open door to process %d\n", pid);
+            goto quit;
+        }
+    }
+
+quit:
+    if (attach_fd >= 0) {
+        file_close(attach_fd);
+        delete_attach_file(jvm->pid);
+    }
+    if (door_fd >= 0) {
+        jvm->door_fd = door_fd;
+        clear_jvm_error();
+    } else {
+        free(jvm);
+        jvm = NULL;
+    }
+    return jvm;
+}
+
+/* return the last thread local error message */
+const char* jvm_get_last_error() {
+    const char* res = NULL;
+    thr_getspecific(jvm_error_key, (void**)&res);
+    return res;
+}
+
+/* detach the givenb JVM */
+int jvm_detach(jvm_t* jvm) {
+    if (jvm) {
+        int res = 0;
+        if (jvm->door_fd != -1) {
+            if (file_close(jvm->door_fd) != 0) {
+                set_jvm_error(JVM_ERR_CANT_CLOSE_DOOR);
+                res = -1;
+            } else {
+                clear_jvm_error();
+            }
+        }
+        free(jvm);
+        return res;
+    } else {
+        set_jvm_error(JVM_ERR_NULL_PARAM);
+        print_debug("jvm_t* is NULL\n");
+        return -1;
+    }
+}
+
+/*
+ * A simple table to translate some known errors into reasonable
+ * error messages
+ */
+static struct {
+    int err;
+    const char* msg;
+} const error_messages[] = {
+    { 100,      "Bad request" },
+    { 101,      "Protocol mismatch" },
+    { 102,      "Resource failure" },
+    { 103,      "Internal error" },
+    { 104,      "Permission denied" },
+};
+
+/*
+ * Lookup the given error code and return the appropriate
+ * message. If not found return NULL.
+ */
+static const char* translate_error(int err) {
+    int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
+    int i;
+
+    for (i=0; i<table_size; i++) {
+        if (err == error_messages[i].err) {
+            return error_messages[i].msg;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Current protocol version
+ */
+static const char* PROTOCOL_VERSION = "1";
+
+#define RES_BUF_SIZE 128
+
+/*
+ * Enqueue attach-on-demand command to the given JVM
+ */
+static
+int enqueue_command(jvm_t* jvm, const char* cstr, int arg_count, const char** args) {
+    size_t size;
+    door_arg_t door_args;
+    char res_buffer[RES_BUF_SIZE];
+    int rc, i;
+    char* buf = NULL;
+    int result = -1;
+
+    /*
+     * First we get the command string and create the start of the
+     * argument string to send to the target VM:
+     * <ver>\0<cmd>\0
+     */
+    if (cstr == NULL) {
+        print_debug("command name is NULL\n");
+        goto quit;
+    }
+    size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
+    buf = (char*)malloc(size);
+    if (buf != NULL) {
+        char* pos = buf;
+        strcpy(buf, PROTOCOL_VERSION);
+        pos += strlen(PROTOCOL_VERSION)+1;
+        strcpy(pos, cstr);
+    } else {
+        set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
+        print_debug("malloc failed at %d in %s\n", __LINE__, __FILE__);
+        goto quit;
+    }
+
+    /*
+     * Next we iterate over the arguments and extend the buffer
+     * to include them.
+     */
+    for (i=0; i<arg_count; i++) {
+        cstr = args[i];
+        if (cstr != NULL) {
+            size_t len = strlen(cstr);
+            char* newbuf = (char*)realloc(buf, size+len+1);
+            if (newbuf == NULL) {
+                set_jvm_error(JVM_ERR_OUT_OF_MEMORY);
+                print_debug("realloc failed in %s at %d\n", __FILE__, __LINE__);
+                goto quit;
+            }
+            buf = newbuf;
+            strcpy(buf+size, cstr);
+            size += len+1;
+        }
+    }
+
+    /*
+     * The arguments to the door function are in 'buf' so we now
+     * do the door call
+     */
+    door_args.data_ptr = buf;
+    door_args.data_size = size;
+    door_args.desc_ptr = NULL;
+    door_args.desc_num = 0;
+    door_args.rbuf = (char*)&res_buffer;
+    door_args.rsize = sizeof(res_buffer);
+
+    RESTARTABLE(door_call(jvm->door_fd, &door_args), rc);
+
+    /*
+     * door_call failed
+     */
+    if (rc == -1) {
+        print_debug("door_call failed\n");
+    } else {
+        /*
+         * door_call succeeded but the call didn't return the expected jint.
+         */
+        if (door_args.data_size < sizeof(int)) {
+            print_debug("Enqueue error - reason unknown as result is truncated!");
+        } else {
+            int* res = (int*)(door_args.data_ptr);
+            if (*res != 0) {
+                const char* msg = translate_error(*res);
+                if (msg == NULL) {
+                    print_debug("Unable to enqueue command to target VM: %d\n", *res);
+                } else {
+                    print_debug("Unable to enqueue command to target VM: %s\n", msg);
+                }
+            } else {
+                /*
+                 * The door call should return a file descriptor to one end of
+                 * a socket pair
+                 */
+                if ((door_args.desc_ptr != NULL) &&
+                    (door_args.desc_num == 1) &&
+                    (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
+                    result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
+                } else {
+                    print_debug("Reply from enqueue missing descriptor!\n");
+                }
+            }
+        }
+    }
+
+quit:
+    if (buf) free(buf);
+    return result;
+}
+
+/* read status code for a door command */
+static int read_status(int fd) {
+    char ch, buf[16];
+    int index = 0;
+
+    while (1) {
+        if (file_read(fd, &ch, sizeof(ch)) != sizeof(ch)) {
+            set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
+            print_debug("door cmd status: read status failed\n");
+            return -1;
+        }
+        buf[index++] = ch;
+        if (ch == '\n') {
+            buf[index - 1] = '\0';
+            return atoi(buf);
+        }
+        if (index == sizeof(buf)) {
+            set_jvm_error(JVM_ERR_DOOR_CANT_READ_STATUS);
+            print_debug("door cmd status: read status overflow\n");
+            return -1;
+        }
+    }
+}
+
+static const char* ENABLE_DPROBES_CMD = "enabledprobes";
+
+/* enable one or more DTrace probes for a given JVM */
+int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types) {
+    int fd, status = 0;
+    char ch;
+    const char* args[1];
+    char buf[16];
+    int probe_type = 0, index;
+    int count = 0;
+
+    if (jvm == NULL) {
+        set_jvm_error(JVM_ERR_NULL_PARAM);
+        print_debug("jvm_t* is NULL\n");
+        return -1;
+    }
+
+    if (num_probe_types == 0 || probe_types == NULL ||
+        probe_types[0] == NULL) {
+        set_jvm_error(JVM_ERR_INVALID_PARAM);
+        print_debug("invalid probe type argument(s)\n");
+        return -1;
+    }
+
+    for (index = 0; index < num_probe_types; index++) {
+        const char* p = probe_types[index];
+        if (strcmp(p, JVM_DTPROBE_OBJECT_ALLOC) == 0) {
+            probe_type |= DTRACE_ALLOC_PROBES;
+            count++;
+        } else if (strcmp(p, JVM_DTPROBE_METHOD_ENTRY) == 0 ||
+                   strcmp(p, JVM_DTPROBE_METHOD_RETURN) == 0) {
+            probe_type |= DTRACE_METHOD_PROBES;
+            count++;
+        } else if (strcmp(p, JVM_DTPROBE_MONITOR_ENTER) == 0   ||
+                   strcmp(p, JVM_DTPROBE_MONITOR_ENTERED) == 0 ||
+                   strcmp(p, JVM_DTPROBE_MONITOR_EXIT) == 0    ||
+                   strcmp(p, JVM_DTPROBE_MONITOR_WAIT) == 0    ||
+                   strcmp(p, JVM_DTPROBE_MONITOR_WAITED) == 0  ||
+                   strcmp(p, JVM_DTPROBE_MONITOR_NOTIFY) == 0  ||
+                   strcmp(p, JVM_DTPROBE_MONITOR_NOTIFYALL) == 0) {
+            probe_type |= DTRACE_MONITOR_PROBES;
+            count++;
+        } else if (strcmp(p, JVM_DTPROBE_ALL) == 0) {
+            probe_type |= DTRACE_ALL_PROBES;
+            count++;
+        }
+    }
+
+    if (count == 0) {
+        return count;
+    }
+    sprintf(buf, "%d", probe_type);
+    args[0] = buf;
+
+    fd = enqueue_command(jvm, ENABLE_DPROBES_CMD, 1, args);
+    if (fd < 0) {
+        set_jvm_error(JVM_ERR_DOOR_CMD_SEND);
+        return -1;
+    }
+
+    status = read_status(fd);
+    // non-zero status is error
+    if (status) {
+        set_jvm_error(JVM_ERR_DOOR_CMD_STATUS);
+        print_debug("%s command failed (status: %d) in target JVM\n",
+                    ENABLE_DPROBES_CMD, status);
+        file_close(fd);
+        return -1;
+    }
+    // read from stream until EOF
+    while (file_read(fd, &ch, sizeof(ch)) == sizeof(ch)) {
+        if (libjvm_dtrace_debug) {
+            printf("%c", ch);
+        }
+    }
+
+    file_close(fd);
+    clear_jvm_error();
+    return count;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h	2024-08-17 18:29:44.563492357 +0200
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2006, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#ifndef _JVM_DTRACE_H_
+#define _JVM_DTRACE_H_
+
+/*
+ * Interface to dynamically turn on probes in Hotspot JVM. Currently,
+ * this interface can be used to dynamically enable certain DTrace
+ * probe points that are costly to have "always on".
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <sys/types.h>
+#include "jni.h"
+
+struct _jvm_t;
+typedef struct _jvm_t jvm_t;
+
+
+/* Attach to the given JVM process. Returns NULL on failure.
+   jvm_get_last_error() returns last error message. */
+JNIEXPORT jvm_t* jvm_attach(pid_t pid);
+
+/* Returns the last error message from this library or NULL if none. */
+JNIEXPORT const char* jvm_get_last_error();
+
+/* few well-known probe type constants for 'probe_types' param below */
+
+#define JVM_DTPROBE_METHOD_ENTRY         "method-entry"
+#define JVM_DTPROBE_METHOD_RETURN        "method-return"
+#define JVM_DTPROBE_MONITOR_ENTER        "monitor-contended-enter"
+#define JVM_DTPROBE_MONITOR_ENTERED      "monitor-contended-entered"
+#define JVM_DTPROBE_MONITOR_EXIT         "monitor-contended-exit"
+#define JVM_DTPROBE_MONITOR_WAIT         "monitor-wait"
+#define JVM_DTPROBE_MONITOR_WAITED       "monitor-waited"
+#define JVM_DTPROBE_MONITOR_NOTIFY       "monitor-notify"
+#define JVM_DTPROBE_MONITOR_NOTIFYALL    "monitor-notifyall"
+#define JVM_DTPROBE_OBJECT_ALLOC         "object-alloc"
+#define JVM_DTPROBE_ALL                  "*"
+
+/* Enable the specified DTrace probes of given probe types on
+ * the specified JVM. Returns >= 0 on success, -1 on failure.
+ * On success, this returns number of probe_types enabled.
+ * On failure, jvm_get_last_error() returns the last error message.
+ */
+JNIEXPORT int jvm_enable_dtprobes(jvm_t* jvm, int num_probe_types, const char** probe_types);
+
+/* Note: There is no jvm_disable_dtprobes function. Probes are automatically
+ * disabled when there are no more clients requiring those probes.
+ */
+
+/* Detach the given JVM. Returns 0 on success, -1 on failure.
+ * jvm_get_last_error() returns the last error message.
+ */
+JNIEXPORT int jvm_detach(jvm_t* jvm);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _JVM_DTRACE_H_ */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnet/solaris_close.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnet/solaris_close.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnet/solaris_close.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnet/solaris_close.c	2024-08-17 18:29:44.563899880 +0200
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2014, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <errno.h>
+#include <sys/socket.h>
+#include <stropts.h>
+#include <unistd.h>
+#include "jvm.h"
+#include "net_util.h"
+
+/* Support for restartable system calls on Solaris. */
+
+#define RESTARTABLE_RETURN_INT(_cmd) do {             \
+    int _result;                                      \
+    if (1) {                                          \
+        do {                                          \
+            _result = _cmd;                           \
+        } while((_result == -1) && (errno == EINTR));      \
+        return _result;                               \
+    }                                                 \
+} while(0)
+
+int NET_Read(int s, void* buf, size_t len) {
+    RESTARTABLE_RETURN_INT(recv(s, buf, len, 0));
+}
+
+int NET_NonBlockingRead(int s, void* buf, size_t len) {
+    RESTARTABLE_RETURN_INT(recv(s, buf, len, MSG_DONTWAIT));
+}
+
+int NET_RecvFrom(int s, void *buf, int len, unsigned int flags,
+                 struct sockaddr *from, socklen_t *fromlen) {
+    RESTARTABLE_RETURN_INT(recvfrom(s, buf, len, flags, from, fromlen));
+}
+
+int NET_Send(int s, void *msg, int len, unsigned int flags) {
+    RESTARTABLE_RETURN_INT(send(s, msg, len, flags));
+}
+
+int NET_SendTo(int s, const void *msg, int len,  unsigned  int flags,
+               const struct sockaddr *to, int tolen) {
+    RESTARTABLE_RETURN_INT(sendto(s, msg, len, flags, to, tolen));
+}
+
+int NET_Connect(int s, struct sockaddr *addr, int addrlen) {
+    RESTARTABLE_RETURN_INT(connect(s, addr, addrlen));
+}
+
+int NET_Accept(int s, struct sockaddr *addr, socklen_t *addrlen) {
+    RESTARTABLE_RETURN_INT(accept(s, addr, addrlen));
+}
+
+int NET_SocketClose(int fd) {
+    return close(fd);
+}
+
+int NET_Dup2(int fd, int fd2) {
+    return dup2(fd, fd2);
+}
+
+int NET_Poll(struct pollfd *ufds, unsigned int nfds, int timeout) {
+    RESTARTABLE_RETURN_INT(poll(ufds, nfds, timeout));
+}
+
+int NET_Timeout(JNIEnv *env, int s, long timeout, jlong nanoTimeStamp) {
+    int result;
+    jlong prevNanoTime = nanoTimeStamp;
+    jlong nanoTimeout = (jlong) timeout * NET_NSEC_PER_MSEC;
+    struct pollfd pfd;
+    pfd.fd = s;
+    pfd.events = POLLIN;
+
+    for(;;) {
+        result = poll(&pfd, 1, nanoTimeout / NET_NSEC_PER_MSEC);
+        if (result < 0 && errno == EINTR) {
+            jlong newNanoTime = JVM_NanoTime(env, 0);
+            nanoTimeout -= newNanoTime - prevNanoTime;
+            if (nanoTimeout < NET_NSEC_PER_MSEC)
+                return 0;
+            prevNanoTime = newNanoTime;
+        } else {
+            return result;
+        }
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	2024-08-17 18:29:44.564359591 +0200
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2001, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <devpoll.h>
+#include <fcntl.h>
+#include <poll.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_DevPollArrayWrapper.h"
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_DevPollArrayWrapper_init(JNIEnv *env, jobject this)
+{
+    int wfd = open("/dev/poll", O_RDWR);
+    if (wfd < 0) {
+       JNU_ThrowIOExceptionWithLastError(env, "Error opening driver");
+       return -1;
+    }
+    return wfd;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_DevPollArrayWrapper_register(JNIEnv *env, jobject this,
+                                             jint wfd, jint fd, jint mask)
+{
+    struct pollfd a[1];
+    int n;
+
+    a[0].fd = fd;
+    a[0].events = mask;
+    a[0].revents = 0;
+
+    n = write(wfd, &a[0], sizeof(a));
+    if (n != sizeof(a)) {
+        if (n < 0) {
+            JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
+        } else {
+            JNU_ThrowIOException(env, "Unexpected number of bytes written");
+        }
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_DevPollArrayWrapper_registerMultiple(JNIEnv *env, jobject this,
+                                                     jint wfd, jlong address,
+                                                     jint len)
+{
+    unsigned char *pollBytes = (unsigned char *)jlong_to_ptr(address);
+    unsigned char *pollEnd = pollBytes + sizeof(struct pollfd) * len;
+    while (pollBytes < pollEnd) {
+        int bytesWritten = write(wfd, pollBytes, (int)(pollEnd - pollBytes));
+        if (bytesWritten < 0) {
+            JNU_ThrowIOExceptionWithLastError(env, "Error writing pollfds");
+            return;
+        }
+        pollBytes += bytesWritten;
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_DevPollArrayWrapper_poll0(JNIEnv *env, jobject this,
+                                          jlong address, jint numfds,
+                                          jlong timeout, jint wfd)
+{
+    struct dvpoll a;
+    void *pfd = (void *) jlong_to_ptr(address);
+    int result;
+
+    a.dp_fds = pfd;
+    a.dp_nfds = numfds;
+    a.dp_timeout = (int)timeout;
+    result = ioctl(wfd, DP_POLL, &a);
+    if (result < 0) {
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "Error reading driver");
+            return IOS_THROWN;
+        }
+    }
+    return result;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c	2024-08-17 18:29:44.564719786 +0200
@@ -0,0 +1,147 @@
+/*
+ * Copyright (c) 2008, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <port.h>
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+#include "nio.h"
+#include "nio_util.h"
+
+#include "sun_nio_ch_SolarisEventPort.h"
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1create
+    (JNIEnv* env, jclass clazz)
+{
+    int port = port_create();
+    if (port == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_create");
+    }
+    return (jint)port;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1close
+    (JNIEnv* env, jclass clazz, jint port)
+{
+    int res = close(port);
+    if (res < 0 && res != EINTR) {
+        JNU_ThrowIOExceptionWithLastError(env, "close failed");
+    }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1associate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+    if (port_associate((int)port, (int)source, object, (int)events, NULL) == 0) {
+        return JNI_TRUE;
+    } else {
+        if (errno != EBADFD)
+            JNU_ThrowIOExceptionWithLastError(env, "port_associate");
+        return JNI_FALSE;
+    }
+}
+
+JNIEXPORT jboolean JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1dissociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_dissociate((int)port, (int)source, object) == 0) {
+        return JNI_TRUE;
+    } else {
+        if (errno != ENOENT)
+            JNU_ThrowIOExceptionWithLastError(env, "port_dissociate");
+        return JNI_FALSE;
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1send(JNIEnv* env, jclass clazz,
+    jint port, jint events)
+{
+    if (port_send((int)port, (int)events, NULL) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "port_send");
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1get(JNIEnv* env, jclass clazz,
+    jint port, jlong eventAddress)
+{
+    int res;
+    port_event_t* ev = (port_event_t*)jlong_to_ptr(eventAddress);
+
+    res = port_get((int)port, ev, NULL);
+    if (res == -1) {
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "port_get failed");
+            return IOS_THROWN;
+        }
+    }
+    return res;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_ch_SolarisEventPort_port_1getn(JNIEnv* env, jclass clazz,
+    jint port, jlong arrayAddress, jint max, jlong timeout)
+{
+    int res;
+    uint_t n = 1;
+    port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
+    timespec_t ts;
+    timespec_t* tsp;
+
+    if (timeout >= 0L) {
+        ts.tv_sec = timeout / 1000;
+        ts.tv_nsec = 1000000 * (timeout % 1000);
+        tsp = &ts;
+    } else {
+        tsp = NULL;
+    }
+
+    res = port_getn((int)port, list, (uint_t)max, &n, tsp);
+    if (res == -1 && errno != ETIME) {
+        if (errno == EINTR) {
+            return IOS_INTERRUPTED;
+        } else {
+            JNU_ThrowIOExceptionWithLastError(env, "port_getn failed");
+            return IOS_THROWN;
+        }
+    }
+
+    return (jint)n;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c	2024-08-17 18:29:44.565148373 +0200
@@ -0,0 +1,143 @@
+/*
+ * Copyright (c) 2008, 2012, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <strings.h>
+#include <errno.h>
+#include <sys/acl.h>
+#include <sys/mnttab.h>
+#include <sys/mkdev.h>
+
+#include "jni.h"
+
+#include "sun_nio_fs_SolarisNativeDispatcher.h"
+
+static jfieldID entry_name;
+static jfieldID entry_dir;
+static jfieldID entry_fstype;
+static jfieldID entry_options;
+static jfieldID entry_dev;
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisNativeDispatcher_init(JNIEnv *env, jclass clazz) {
+    clazz = (*env)->FindClass(env, "sun/nio/fs/UnixMountEntry");
+    CHECK_NULL(clazz);
+    entry_name = (*env)->GetFieldID(env, clazz, "name", "[B");
+    CHECK_NULL(entry_name);
+    entry_dir = (*env)->GetFieldID(env, clazz, "dir", "[B");
+    CHECK_NULL(entry_dir);
+    entry_fstype = (*env)->GetFieldID(env, clazz, "fstype", "[B");
+    CHECK_NULL(entry_fstype);
+    entry_options = (*env)->GetFieldID(env, clazz, "opts", "[B");
+    CHECK_NULL(entry_options);
+    entry_dev = (*env)->GetFieldID(env, clazz, "dev", "J");
+    CHECK_NULL(entry_dev);
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisNativeDispatcher_facl(JNIEnv* env, jclass this, jint fd,
+    jint cmd, jint nentries, jlong address)
+{
+    void* aclbufp = jlong_to_ptr(address);
+    int n = -1;
+
+    n = facl((int)fd, (int)cmd, (int)nentries, aclbufp);
+    if (n == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)n;
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisNativeDispatcher_getextmntent(JNIEnv* env, jclass this,
+    jlong value, jobject entry)
+{
+    struct extmnttab ent;
+    FILE* fp = jlong_to_ptr(value);
+    jsize len;
+    jbyteArray bytes;
+    char* name;
+    char* dir;
+    char* fstype;
+    char* options;
+    dev_t dev;
+
+    if (getextmntent(fp, &ent, 0))
+        return -1;
+    name = ent.mnt_special;
+    dir = ent.mnt_mountp;
+    fstype = ent.mnt_fstype;
+    options = ent.mnt_mntopts;
+    dev = makedev(ent.mnt_major, ent.mnt_minor);
+    if (dev == NODEV) {
+        throwUnixException(env, errno);
+        return -1;
+    }
+
+    len = strlen(name);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)name);
+    (*env)->SetObjectField(env, entry, entry_name, bytes);
+
+    len = strlen(dir);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)dir);
+    (*env)->SetObjectField(env, entry, entry_dir, bytes);
+
+    len = strlen(fstype);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)fstype);
+    (*env)->SetObjectField(env, entry, entry_fstype, bytes);
+
+    len = strlen(options);
+    bytes = (*env)->NewByteArray(env, len);
+    if (bytes == NULL)
+        return -1;
+    (*env)->SetByteArrayRegion(env, bytes, 0, len, (jbyte*)options);
+    (*env)->SetObjectField(env, entry, entry_options, bytes);
+
+    if (dev != 0)
+        (*env)->SetLongField(env, entry, entry_dev, (jlong)dev);
+
+    return 0;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c	2024-08-17 18:29:44.565489116 +0200
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2008, 2009, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni.h"
+#include "jni_util.h"
+#include "jvm.h"
+#include "jlong.h"
+
+#include <stdlib.h>
+#include <dlfcn.h>
+#include <sys/types.h>
+#include <port.h>       // Solaris 10
+
+#include "sun_nio_fs_SolarisWatchService.h"
+
+static void throwUnixException(JNIEnv* env, int errnum) {
+    jobject x = JNU_NewObjectByName(env, "sun/nio/fs/UnixException",
+        "(I)V", errnum);
+    if (x != NULL) {
+        (*env)->Throw(env, x);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_init(JNIEnv *env, jclass clazz)
+{
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisWatchService_portCreate
+    (JNIEnv* env, jclass clazz)
+{
+    int port = port_create();
+    if (port == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)port;
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_portAssociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress, jint events)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_associate((int)port, (int)source, object, (int)events, NULL) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_portDissociate
+    (JNIEnv* env, jclass clazz, jint port, jint source, jlong objectAddress)
+{
+    uintptr_t object = (uintptr_t)jlong_to_ptr(objectAddress);
+
+    if (port_dissociate((int)port, (int)source, object) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT void JNICALL
+Java_sun_nio_fs_SolarisWatchService_portSend(JNIEnv* env, jclass clazz,
+    jint port, jint events)
+{
+    if (port_send((int)port, (int)events, NULL) == -1) {
+        throwUnixException(env, errno);
+    }
+}
+
+JNIEXPORT jint JNICALL
+Java_sun_nio_fs_SolarisWatchService_portGetn(JNIEnv* env, jclass clazz,
+    jint port, jlong arrayAddress, jint max)
+{
+    uint_t n = 1;
+    port_event_t* list = (port_event_t*)jlong_to_ptr(arrayAddress);
+
+    if (port_getn((int)port, list, (uint_t)max, &n, NULL) == -1) {
+        throwUnixException(env, errno);
+    }
+    return (jint)n;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/java/lang/ProcessImpl.java jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/java/lang/ProcessImpl.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/java/lang/ProcessImpl.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/java/lang/ProcessImpl.java	2024-08-17 18:29:44.486646507 +0200
@@ -77,6 +77,9 @@
     private /* final */ InputStream  stdout;
     private /* final */ InputStream  stderr;
 
+    // only used on Solaris
+    private /* final */ DeferredCloseInputStream stdout_inner_stream;
+
     private static enum LaunchMechanism {
         // order IS important!
         FORK,
@@ -90,6 +93,8 @@
 
         BSD(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
 
+        SOLARIS(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK),
+
         AIX(LaunchMechanism.POSIX_SPAWN, LaunchMechanism.FORK);
 
         final LaunchMechanism defaultLaunchMechanism;
@@ -135,6 +140,7 @@
 
             if (osName.equals("Linux")) { return LINUX; }
             if (osName.contains("OS X")) { return BSD; }
+            if (osName.equals("SunOS")) { return SOLARIS; }
             if (osName.equals("AIX")) { return AIX; }
 
             throw new Error(osName + " is not a supported OS platform.");
@@ -381,6 +387,41 @@
                 });
                 break;
 
+            case SOLARIS:
+                stdin = (fds[0] == -1) ?
+                        ProcessBuilder.NullOutputStream.INSTANCE :
+                        new BufferedOutputStream(
+                            new FileOutputStream(newFileDescriptor(fds[0])));
+
+                stdout = (fds[1] == -1 || forceNullOutputStream) ?
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new BufferedInputStream(
+                             stdout_inner_stream =
+                                 new DeferredCloseInputStream(
+                                     newFileDescriptor(fds[1])));
+
+                stderr = (fds[2] == -1) ?
+                         ProcessBuilder.NullInputStream.INSTANCE :
+                         new DeferredCloseInputStream(newFileDescriptor(fds[2]));
+
+                /*
+                 * For each subprocess forked a corresponding reaper task
+                 * is submitted.  That task is the only thread which waits
+                 * for the subprocess to terminate and it doesn't hold any
+                 * locks while doing so.  This design allows waitFor() and
+                 * exitStatus() to be safely executed in parallel (and they
+                 * need no native code).
+                 */
+                ProcessHandleImpl.completion(pid, true).handle((exitcode, throwable) -> {
+                    synchronized (this) {
+                        this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
+                        this.hasExited = true;
+                        this.notifyAll();
+                    }
+                    return null;
+                });
+                break;
+
             case AIX:
                 stdin = (fds[0] == -1) ?
                         ProcessBuilder.NullOutputStream.INSTANCE :
@@ -483,6 +524,29 @@
                 try { stderr.close(); } catch (IOException ignored) {}
                 break;
 
+            case SOLARIS:
+                // There is a risk that pid will be recycled, causing us to
+                // kill the wrong process!  So we only terminate processes
+                // that appear to still be running.  Even with this check,
+                // there is an unavoidable race condition here, but the window
+                // is very small, and OSes try hard to not recycle pids too
+                // soon, so this is quite safe.
+                synchronized (this) {
+                    if (!hasExited)
+                        processHandle.destroyProcess(force);
+                    try {
+                        stdin.close();
+                        if (stdout_inner_stream != null)
+                            stdout_inner_stream.closeDeferred(stdout);
+                        if (stderr instanceof DeferredCloseInputStream)
+                            ((DeferredCloseInputStream) stderr)
+                                .closeDeferred(stderr);
+                    } catch (IOException e) {
+                        // ignore
+                    }
+                }
+                break;
+
             default: throw new AssertionError("Unsupported platform: " + platform);
         }
     }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/net/dns/ResolverConfigurationImpl.java	2024-08-17 18:29:44.487679811 +0200
@@ -179,6 +179,16 @@
 
         // No search keyword so use local domain
 
+
+        // LOCALDOMAIN has absolute priority on Solaris
+
+        String localDomain = localDomain0();
+        if (localDomain != null && !localDomain.isEmpty()) {
+            sl = new ArrayList<>();
+            sl.add(localDomain);
+            return sl;
+        }
+
         // try domain keyword in /etc/resolv.conf
 
         sl = java.security.AccessController.doPrivileged(
@@ -246,6 +256,8 @@
 
     // --- Native methods --
 
+    static native String localDomain0();
+
     static native String fallbackDomain0();
 
     static {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/net/PortConfig.java jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/net/PortConfig.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/net/PortConfig.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/net/PortConfig.java	2024-08-17 18:29:44.487143722 +0200
@@ -46,6 +46,9 @@
         if (os.startsWith("Linux")) {
             defaultLower = 32768;
             defaultUpper = 61000;
+        } else if (os.startsWith("SunOS")) {
+            defaultLower = 32768;
+            defaultUpper = 65535;
         } else if (os.contains("OS X")) {
             defaultLower = 49152;
             defaultUpper = 65535;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template	2024-08-17 18:29:44.488177162 +0200
@@ -31,6 +31,10 @@
 #include <fcntl.h>
 #include <sys/stat.h>
 
+/* On Solaris, "sun" is defined as a macro. Undefine to make package
+   declaration valid */
+#undef sun
+
 /* To be able to name the Java constants the same as the C constants without
    having the preprocessor rewrite those identifiers, add PREFIX_ to all
    identifiers matching a C constant. The PREFIX_ is filtered out in the
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/nio/fs/UnixFileSystem.java	2024-08-17 18:29:44.488626557 +0200
@@ -92,6 +92,10 @@
         return rootDirectory;
     }
 
+    boolean isSolaris() {
+        return false;
+    }
+
     static List<String> standardFileAttributeViews() {
         return Arrays.asList("basic", "posix", "unix", "owner");
     }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixPath.java jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/nio/fs/UnixPath.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/nio/fs/UnixPath.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/nio/fs/UnixPath.java	2024-08-17 18:29:44.489166005 +0200
@@ -770,7 +770,15 @@
                     ("NOFOLLOW_LINKS is not supported on this platform");
             flags |= O_NOFOLLOW;
         }
-        return open(this, flags, 0);
+        try {
+            return open(this, flags, 0);
+        } catch (UnixException x) {
+            // HACK: EINVAL instead of ELOOP on Solaris 10 prior to u4 (see 6460380)
+            if (getFileSystem().isSolaris() && x.errno() == EINVAL)
+                x.setError(ELOOP);
+
+            throw x;
+        }
     }
 
     void checkRead() {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/security/provider/NativePRNG.java jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/security/provider/NativePRNG.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/classes/sun/security/provider/NativePRNG.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/classes/sun/security/provider/NativePRNG.java	2024-08-17 18:29:44.489767230 +0200
@@ -33,7 +33,7 @@
 import sun.security.util.Debug;
 
 /**
- * Native PRNG implementation for Linux/MacOS.
+ * Native PRNG implementation for Solaris/Linux/MacOS.
  * <p>
  * It obtains seed and random numbers by reading system files such as
  * the special device files /dev/random and /dev/urandom.  This
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/io_util_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/io_util_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/io_util_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/io_util_md.c	2024-08-17 18:29:44.493618799 +0200
@@ -30,6 +30,10 @@
 #include <string.h>
 #include <unistd.h>
 
+#ifdef __solaris__
+#include <sys/filio.h>
+#endif
+
 #if defined(__linux__) || defined(_ALLBSD_SOURCE) || defined(_AIX)
 #include <sys/ioctl.h>
 #endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/java_props_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/java_props_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/java_props_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/java_props_md.c	2024-08-17 18:29:44.494088357 +0200
@@ -313,6 +313,27 @@
         }
 #endif
 
+#ifdef __solaris__
+        if (strcmp(p,"eucJP") == 0) {
+            /* For Solaris use customized vendor defined character
+             * customized EUC-JP converter
+             */
+            *std_encoding = "eucJP-open";
+        } else if (strcmp(p, "Big5") == 0 || strcmp(p, "BIG5") == 0) {
+            /*
+             * Remap the encoding string to Big5_Solaris which augments
+             * the default converter for Solaris Big5 locales to include
+             * seven additional ideographic characters beyond those included
+             * in the Java "Big5" converter.
+             */
+            *std_encoding = "Big5_Solaris";
+        } else if (strcmp(p, "Big5-HKSCS") == 0) {
+            /*
+             * Solaris uses HKSCS2001
+             */
+            *std_encoding = "Big5-HKSCS-2001";
+        }
+#endif
 #ifdef MACOSX
         /*
          * For the case on MacOS X where encoding is set to US-ASCII, but we
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/jlong_md.h jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/jlong_md.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/jlong_md.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/jlong_md.h	2024-08-17 18:29:44.494532190 +0200
@@ -23,8 +23,8 @@
  * questions.
  */
 
-#ifndef _UNIX_JLONG_MD_H_
-#define _UNIX_JLONG_MD_H_
+#ifndef _SOLARIS_JLONG_MD_H_
+#define _SOLARIS_JLONG_MD_H_
 
 /* Make sure ptrdiff_t is defined */
 #include <stddef.h>
@@ -97,4 +97,4 @@
 #define size_to_jlong(a)    ((jlong)(a))
 #define long_to_jlong(a)    ((jlong)(a))
 
-#endif /* !_UNIX_JLONG_MD_H_ */
+#endif /* !_SOLARIS_JLONG_MD_H_ */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	2024-08-17 18:29:44.490665232 +0200
@@ -45,10 +45,20 @@
 #include <sys/stat.h>
 #include <sys/wait.h>
 
+/* For POSIX-compliant getpwuid_r on Solaris */
+#if defined(__solaris__)
+#define _POSIX_PTHREAD_SEMANTICS
+#endif
 #include <pwd.h>
 
+#ifdef _AIX
+#include <sys/procfs.h>
+#endif
+#ifdef __solaris__
+#include <procfs.h>
+#endif
+
 #if defined(_AIX)
-  #include <sys/procfs.h>
   #define DIR DIR64
   #define dirent dirent64
   #define opendir opendir64
@@ -128,13 +138,18 @@
 #define WTERMSIG(status) ((status)&0x7F)
 #endif
 
+#ifdef __solaris__
 /* The child exited because of a signal.
  * The best value to return is 0x80 + signal number,
  * because that is what all Unix shells do, and because
  * it allows callers to distinguish between process exit and
  * process death by signal.
- */
+ * Unfortunately, the historical behavior on Solaris is to return
+ * the signal number, and we preserve this for compatibility. */
+#define WTERMSIG_RETURN(status) WTERMSIG(status)
+#else
 #define WTERMSIG_RETURN(status) (WTERMSIG(status) + 0x80)
+#endif
 
 #define RESTARTABLE(_cmd, _result) do { \
   do { \
@@ -488,7 +503,7 @@
  * The following functions are common on Solaris, Linux and AIX.
  */
 
-#if defined (__linux__) || defined(_AIX)
+#if defined(__solaris__) || defined (__linux__) || defined(_AIX)
 
 /*
  * Returns the children of the requested pid and optionally each parent and
@@ -607,13 +622,13 @@
     return count;
 }
 
-#endif // defined (__linux__) || defined(_AIX)
+#endif // defined(__solaris__) || defined (__linux__) || defined(_AIX)
 
 /*
- * The following functions are for AIX.
+ * The following functions are common on Solaris and AIX.
  */
 
-#if defined(_AIX)
+#if defined(__solaris__) || defined(_AIX)
 
 /**
  * Helper function to get the 'psinfo_t' data from "/proc/%d/psinfo".
@@ -677,6 +692,19 @@
     int ret;
 
     /*
+     * On Solaris, the full path to the executable command is the link in
+     * /proc/<pid>/paths/a.out. But it is only readable for processes we own.
+     */
+#if defined(__solaris__)
+    snprintf(fn, sizeof fn, "/proc/%d/path/a.out", pid);
+    if ((ret = readlink(fn, exePath, PATH_MAX - 1)) > 0) {
+        // null terminate and create String to store for command
+        exePath[ret] = '\0';
+        CHECK_NULL(cmdexe = JNU_NewStringPlatform(env, exePath));
+    }
+#endif
+
+    /*
      * Now try to open /proc/%d/psinfo
      */
     if (getPsinfo(pid, &psinfo) < 0) {
@@ -705,4 +733,4 @@
                       prargs[0] == '\0' ? NULL : prargs);
 }
 
-#endif // defined(_AIX)
+#endif // defined(__solaris__) || defined(_AIX)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h	2024-08-17 18:29:44.491100959 +0200
@@ -29,7 +29,7 @@
  * Declaration of ProcessHandleImpl functions common on all Unix platforms.
  * 'unix_' functions have a single implementation in ProcessHandleImpl_unix.c
  * 'os_' prefixed functions have different, os-specific implementations in the
- * various ProcessHandleImpl_{linux,macosx,aix}.c files.
+ * various ProcessHandleImpl_{linux,macosx,solaris,aix}.c files.
  * See ProcessHandleImpl_unix.c for more details.
  */
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/ProcessImpl_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/ProcessImpl_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/ProcessImpl_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/ProcessImpl_md.c	2024-08-17 18:29:44.491735345 +0200
@@ -230,7 +230,14 @@
 static const char*
 defaultPath(void)
 {
-    return ":/bin:/usr/bin";
+#ifdef __solaris__
+    /* These really are the Solaris defaults! */
+    return (geteuid() == 0 || getuid() == 0) ?
+        "/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:/usr/sbin" :
+        "/usr/xpg4/bin:/usr/bin:/opt/SUNWspro/bin:";
+#else
+    return ":/bin:/usr/bin";    /* glibc */
+#endif
 }
 
 static const char*
@@ -445,7 +452,7 @@
 #endif
 
 /* vfork(2) is deprecated on Darwin */
-#ifndef __APPLE__
+#ifndef __solaris__
 static pid_t
 vforkChild(ChildStuff *c) {
     volatile pid_t resultPid;
@@ -576,7 +583,7 @@
 startChild(JNIEnv *env, jobject process, ChildStuff *c, const char *helperpath) {
     switch (c->mode) {
 /* vfork(2) is deprecated on Darwin*/
-      #ifndef __APPLE__
+      #ifndef __solaris__
       case MODE_VFORK:
         return vforkChild(c);
       #endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/TimeZone_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/TimeZone_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/TimeZone_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/TimeZone_md.c	2024-08-17 18:29:44.492735255 +0200
@@ -35,6 +35,9 @@
 #include <string.h>
 #include <dirent.h>
 #include <unistd.h>
+#if defined(__solaris__)
+#include <libscf.h>
+#endif
 
 #include "jvm.h"
 #include "TimeZone_md.h"
@@ -50,9 +53,11 @@
   } while((_result == -1) && (errno == EINTR)); \
 } while(0)
 
+#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64)
 #define fileopen        fopen
 #define filegets        fgets
 #define fileclose       fclose
+#endif
 
 #if defined(_ALLBSD_SOURCE)
 #define stat64 stat
@@ -76,7 +81,7 @@
 static const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
 #endif
 
-#if defined(__linux__) || defined(MACOSX)
+#if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
 
 /*
  * remove repeated path separators ('/') in the given 'path'.
@@ -187,6 +192,13 @@
          */
         if ((strcmp(dp->d_name, "ROC") == 0)
             || (strcmp(dp->d_name, "posixrules") == 0)
+#if defined(__solaris__)
+            /*
+             * Skip the "src" and "tab" directories on Solaris.
+             */
+            || (strcmp(dp->d_name, "src") == 0)
+            || (strcmp(dp->d_name, "tab") == 0)
+#endif
             || (strcmp(dp->d_name, "localtime") == 0)) {
             continue;
         }
@@ -258,6 +270,8 @@
     return possibleMatch;
 }
 
+#if defined(__linux__) || defined(MACOSX)
+
 /*
  * Performs Linux specific mapping and returns a zone ID
  * if found. Otherwise, NULL is returned.
@@ -369,6 +383,311 @@
     return tz;
 }
 
+#elif defined(__solaris__)
+
+#if !defined(__sparcv9) && !defined(amd64)
+
+/*
+ * Those file* functions mimic the UNIX stream io functions. This is
+ * because of the limitation of the number of open files on Solaris
+ * (32-bit mode only) due to the System V ABI.
+ */
+
+#define BUFFER_SIZE     4096
+
+static struct iobuffer {
+    int     magic;      /* -1 to distinguish from the real FILE */
+    int     fd;         /* file descriptor */
+    char    *buffer;    /* pointer to buffer */
+    char    *ptr;       /* current read pointer */
+    char    *endptr;    /* end pointer */
+};
+
+static int
+fileclose(FILE *stream)
+{
+    struct iobuffer *iop = (struct iobuffer *) stream;
+
+    if (iop->magic != -1) {
+        return fclose(stream);
+    }
+
+    if (iop == NULL) {
+        return 0;
+    }
+    close(iop->fd);
+    free((void *)iop->buffer);
+    free((void *)iop);
+    return 0;
+}
+
+static FILE *
+fileopen(const char *fname, const char *fmode)
+{
+    FILE *fp;
+    int fd;
+    struct iobuffer *iop;
+
+    if ((fp = fopen(fname, fmode)) != NULL) {
+        return fp;
+    }
+
+    /*
+     * It assumes read open.
+     */
+    RESTARTABLE(open(fname, O_RDONLY), fd);
+    if (fd == -1) {
+        return NULL;
+    }
+
+    /*
+     * Allocate struct iobuffer and its buffer
+     */
+    iop = malloc(sizeof(struct iobuffer));
+    if (iop == NULL) {
+        (void) close(fd);
+        errno = ENOMEM;
+        return NULL;
+    }
+    iop->magic = -1;
+    iop->fd = fd;
+    iop->buffer = malloc(BUFFER_SIZE);
+    if (iop->buffer == NULL) {
+        (void) close(fd);
+        free((void *) iop);
+        errno = ENOMEM;
+        return NULL;
+    }
+    iop->ptr = iop->buffer;
+    iop->endptr = iop->buffer;
+    return (FILE *)iop;
+}
+
+/*
+ * This implementation assumes that n is large enough and the line
+ * separator is '\n'.
+ */
+static char *
+filegets(char *s, int n, FILE *stream)
+{
+    struct iobuffer *iop = (struct iobuffer *) stream;
+    char *p;
+
+    if (iop->magic != -1) {
+        return fgets(s, n, stream);
+    }
+
+    p = s;
+    for (;;) {
+        char c;
+
+        if (iop->ptr == iop->endptr) {
+            ssize_t len;
+
+            RESTARTABLE(read(iop->fd, (void *)iop->buffer, BUFFER_SIZE), len);
+            if (len == -1) {
+                return NULL;
+            }
+            if (len == 0) {
+                *p = 0;
+                if (s == p) {
+                    return NULL;
+                }
+                return s;
+            }
+            iop->ptr = iop->buffer;
+            iop->endptr = iop->buffer + len;
+        }
+        c = *iop->ptr++;
+        *p++ = c;
+        if ((p - s) == (n - 1)) {
+            *p = 0;
+            return s;
+        }
+        if (c == '\n') {
+            *p = 0;
+            return s;
+        }
+    }
+    /*NOTREACHED*/
+}
+#endif /* !defined(__sparcv9) && !defined(amd64) */
+
+/*
+ * Performs Solaris dependent mapping. Returns a zone ID if
+ * found. Otherwise, NULL is returned.  Solaris libc looks up
+ * "/etc/default/init" to get the default TZ value if TZ is not defined
+ * as an environment variable.
+ */
+static char *
+getPlatformTimeZoneID()
+{
+    char *tz = NULL;
+    FILE *fp;
+
+    /*
+     * Try the TZ entry in /etc/default/init.
+     */
+    if ((fp = fileopen(SYS_INIT_FILE, "r")) != NULL) {
+        char line[256];
+        char quote = '\0';
+
+        while (filegets(line, sizeof(line), fp) != NULL) {
+            char *p = line;
+            char *s;
+            char c;
+
+            /* quick check for comment lines */
+            if (*p == '#') {
+                continue;
+            }
+            if (strncmp(p, "TZ=", 3) == 0) {
+                p += 3;
+                SKIP_SPACE(p);
+                c = *p;
+                if (c == '"' || c == '\'') {
+                    quote = c;
+                    p++;
+                }
+
+                /*
+                 * PSARC/2001/383: quoted string support
+                 */
+                for (s = p; (c = *s) != '\0' && c != '\n'; s++) {
+                    /* No '\\' is supported here. */
+                    if (c == quote) {
+                        quote = '\0';
+                        break;
+                    }
+                    if (c == ' ' && quote == '\0') {
+                        break;
+                    }
+                }
+                if (quote != '\0') {
+                    jio_fprintf(stderr, "ZoneInfo: unterminated time zone name in /etc/TIMEZONE\n");
+                }
+                *s = '\0';
+                tz = strdup(p);
+                break;
+            }
+        }
+        (void) fileclose(fp);
+    }
+    return tz;
+}
+
+#define TIMEZONE_FMRI   "svc:/system/timezone:default"
+#define TIMEZONE_PG     "timezone"
+#define LOCALTIME_PROP  "localtime"
+
+static void
+cleanupScf(scf_handle_t *h,
+           scf_snapshot_t *snap,
+           scf_instance_t *inst,
+           scf_propertygroup_t *pg,
+           scf_property_t *prop,
+           scf_value_t *val,
+           char *buf) {
+    if (buf != NULL) {
+        free(buf);
+    }
+    if (snap != NULL) {
+        scf_snapshot_destroy(snap);
+    }
+    if (val != NULL) {
+        scf_value_destroy(val);
+    }
+    if (prop != NULL) {
+        scf_property_destroy(prop);
+    }
+    if (pg != NULL) {
+        scf_pg_destroy(pg);
+    }
+    if (inst != NULL) {
+        scf_instance_destroy(inst);
+    }
+    if (h != NULL) {
+        scf_handle_destroy(h);
+    }
+}
+
+/*
+ * Returns a zone ID of Solaris when the TZ value is "localtime".
+ * First, it tries scf. If scf fails, it looks for the same file as
+ * /usr/share/lib/zoneinfo/localtime under /usr/share/lib/zoneinfo/.
+ */
+static char *
+getSolarisDefaultZoneID() {
+    char *tz = NULL;
+    struct stat64 statbuf;
+    size_t size;
+    char *buf;
+    int fd;
+    int res;
+    /* scf specific variables */
+    scf_handle_t *h = NULL;
+    scf_snapshot_t *snap = NULL;
+    scf_instance_t *inst = NULL;
+    scf_propertygroup_t *pg = NULL;
+    scf_property_t *prop = NULL;
+    scf_value_t *val = NULL;
+
+    if ((h = scf_handle_create(SCF_VERSION)) != NULL
+        && scf_handle_bind(h) == 0
+        && (inst = scf_instance_create(h)) != NULL
+        && (snap = scf_snapshot_create(h)) != NULL
+        && (pg = scf_pg_create(h)) != NULL
+        && (prop = scf_property_create(h)) != NULL
+        && (val = scf_value_create(h)) != NULL
+        && scf_handle_decode_fmri(h, TIMEZONE_FMRI, NULL, NULL, inst,
+                                  NULL, NULL, SCF_DECODE_FMRI_REQUIRE_INSTANCE) == 0
+        && scf_instance_get_snapshot(inst, "running", snap) == 0
+        && scf_instance_get_pg_composed(inst, snap, TIMEZONE_PG, pg) == 0
+        && scf_pg_get_property(pg, LOCALTIME_PROP, prop) == 0
+        && scf_property_get_value(prop, val) == 0) {
+        ssize_t len;
+
+        /* Gets the length of the zone ID string */
+        len = scf_value_get_astring(val, NULL, 0);
+        if (len != -1) {
+            tz = malloc(++len); /* +1 for a null byte */
+            if (tz != NULL && scf_value_get_astring(val, tz, len) != -1) {
+                cleanupScf(h, snap, inst, pg, prop, val, NULL);
+                return tz;
+            }
+        }
+    }
+    cleanupScf(h, snap, inst, pg, prop, val, tz);
+
+    RESTARTABLE(stat64(DEFAULT_ZONEINFO_FILE, &statbuf), res);
+    if (res == -1) {
+        return NULL;
+    }
+    size = (size_t) statbuf.st_size;
+    buf = malloc(size);
+    if (buf == NULL) {
+        return NULL;
+    }
+    RESTARTABLE(open(DEFAULT_ZONEINFO_FILE, O_RDONLY), fd);
+    if (fd == -1) {
+        free((void *) buf);
+        return NULL;
+    }
+
+    RESTARTABLE(read(fd, buf, size), res);
+    if (res != (ssize_t) size) {
+        (void) close(fd);
+        free((void *) buf);
+        return NULL;
+    }
+    (void) close(fd);
+    tz = findZoneinfoFile(buf, size, ZONEINFO_DIR);
+    free((void *) buf);
+    return tz;
+}
+
+#endif /* defined(__solaris__) */
+
 #elif defined(_AIX)
 
 static char *
@@ -535,6 +854,15 @@
             free((void *) freetz);
         }
 #else
+#if defined(__solaris__)
+        /* Solaris might use localtime, so handle it here. */
+        if (strcmp(tz, "localtime") == 0) {
+            javatz = getSolarisDefaultZoneID();
+            if (freetz != NULL) {
+                free((void *) freetz);
+            }
+        } else
+#endif
         if (freetz == NULL) {
             /* strdup if we are still working on getenv result. */
             javatz = strdup(tz);
@@ -592,7 +920,19 @@
 {
     time_t offset;
     char sign, buf[32];
+#if defined(__solaris__)
+    struct tm localtm;
+    time_t currenttime;
+
+    currenttime = time(NULL);
+    if (localtime_r(&currenttime, &localtm) == NULL) {
+        return strdup("GMT");
+    }
+
+    offset = localtm.tm_isdst ? altzone : timezone;
+#else
     offset = timezone;
+#endif
 
     if (offset == 0) {
         return strdup("GMT");
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/UnixFileSystem_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/UnixFileSystem_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjava/UnixFileSystem_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjava/UnixFileSystem_md.c	2024-08-17 18:29:44.493197160 +0200
@@ -63,6 +63,10 @@
   #define stat stat64
 #endif
 
+#if defined(__solaris__) && !defined(NAME_MAX)
+  #define NAME_MAX MAXNAMLEN
+#endif
+
 #if defined(_ALLBSD_SOURCE)
   #ifndef MACOSX
     #define statvfs64 statvfs
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjsig/jsig.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjsig/jsig.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libjsig/jsig.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libjsig/jsig.c	2024-08-17 18:29:44.495410814 +0200
@@ -35,6 +35,16 @@
 
 #include "jni.h"
 
+#ifdef SOLARIS
+/* Our redeclarations of the system functions must not have a less
+ * restrictive linker scoping, so we have to declare them as JNIEXPORT
+ * before including signal.h */
+#include "sys/signal.h"
+JNIEXPORT void (*signal(int sig, void (*disp)(int)))(int);
+JNIEXPORT void (*sigset(int sig, void (*disp)(int)))(int);
+JNIEXPORT int sigaction(int sig, const struct sigaction *act, struct sigaction *oact);
+#endif
+
 #include <dlfcn.h>
 #include <errno.h>
 #include <pthread.h>
@@ -51,9 +61,16 @@
   #define false 0
 #endif
 
+#ifdef SOLARIS
+#define MAX_SIGNALS (SIGRTMAX+1)
+
+/* On solaris, MAX_SIGNALS is a macro, not a constant, so we must allocate sact dynamically. */
+static struct sigaction *sact = (struct sigaction *)NULL; /* saved signal handlers */
+#else
 #define MAX_SIGNALS NSIG
 
 static struct sigaction sact[MAX_SIGNALS]; /* saved signal handlers */
+#endif
 
 static sigset_t jvmsigs; /* Signals used by jvm. */
 
@@ -78,6 +95,20 @@
 static bool jvm_signal_installed = false;
 
 
+/* assume called within signal_lock */
+static void allocate_sact() {
+#ifdef SOLARIS
+  if (sact == NULL) {
+    sact = (struct sigaction *)malloc((MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
+    if (sact == NULL) {
+      printf("%s\n", "libjsig.so unable to allocate memory");
+      exit(0);
+    }
+    memset(sact, 0, (MAX_SIGNALS) * (size_t)sizeof(struct sigaction));
+  }
+#endif
+}
+
 static void signal_lock() {
   pthread_mutex_lock(&mutex);
   /* When the jvm is installing its set of signal handlers, threads
@@ -137,7 +168,18 @@
   sact[sig].sa_handler = disp;
   sigemptyset(&set);
   sact[sig].sa_mask = set;
-  sact[sig].sa_flags = 0;
+  if (!is_sigset) {
+#ifdef SOLARIS
+    sact[sig].sa_flags = SA_NODEFER;
+    if (sig != SIGILL && sig != SIGTRAP && sig != SIGPWR) {
+      sact[sig].sa_flags |= SA_RESETHAND;
+    }
+#else
+    sact[sig].sa_flags = 0;
+#endif
+  } else {
+    sact[sig].sa_flags = 0;
+  }
 }
 
 static sa_handler_t set_signal(int sig, sa_handler_t disp, bool is_sigset) {
@@ -146,6 +188,7 @@
   bool sigblocked;
 
   signal_lock();
+  allocate_sact();
 
   sigused = sigismember(&jvmsigs, sig);
   if (jvm_signal_installed && sigused) {
@@ -157,6 +200,13 @@
     oldhandler = sact[sig].sa_handler;
     save_signal_handler(sig, disp, is_sigset);
 
+#ifdef SOLARIS
+    if (is_sigset && sigblocked) {
+      /* We won't honor the SIG_HOLD request to change the signal mask */
+      oldhandler = SIG_HOLD;
+    }
+#endif
+
     signal_unlock();
     return oldhandler;
   } else if (jvm_signal_installing) {
@@ -234,6 +284,7 @@
 
   signal_lock();
 
+  allocate_sact();
   sigused = sigismember(&jvmsigs, sig);
   if (jvm_signal_installed && sigused) {
     /* jvm has installed its signal handler for this signal. */
@@ -289,6 +340,7 @@
 }
 
 JNIEXPORT struct sigaction *JVM_get_signal_action(int sig) {
+  allocate_sact();
   /* Does race condition make sense here? */
   if (sigismember(&jvmsigs, sig)) {
     return &sact[sig];
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/Inet4AddressImpl.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/Inet4AddressImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/Inet4AddressImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/Inet4AddressImpl.c	2024-08-17 18:29:44.495932255 +0200
@@ -66,8 +66,27 @@
     if (gethostname(hostname, sizeof(hostname)) != 0) {
         strcpy(hostname, "localhost");
     } else {
+#if defined(__solaris__)
+        // try to resolve hostname via nameservice
+        // if it is known but getnameinfo fails, hostname will still be the
+        // value from gethostname
+        struct addrinfo hints, *res;
+
         // make sure string is null-terminated
         hostname[NI_MAXHOST] = '\0';
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = AI_CANONNAME;
+        hints.ai_family = AF_INET;
+
+        if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
+            getnameinfo(res->ai_addr, res->ai_addrlen, hostname, sizeof(hostname),
+                        NULL, 0, NI_NAMEREQD);
+            freeaddrinfo(res);
+        }
+#else
+        // make sure string is null-terminated
+        hostname[NI_MAXHOST] = '\0';
+#endif
     }
     return (*env)->NewStringUTF(env, hostname);
 }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/Inet6AddressImpl.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/Inet6AddressImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/Inet6AddressImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/Inet6AddressImpl.c	2024-08-17 18:29:44.496458082 +0200
@@ -67,8 +67,27 @@
     if (gethostname(hostname, sizeof(hostname)) != 0) {
         strcpy(hostname, "localhost");
     } else {
+#if defined(__solaris__)
+        // try to resolve hostname via nameservice
+        // if it is known but getnameinfo fails, hostname will still be the
+        // value from gethostname
+        struct addrinfo hints, *res;
+
         // make sure string is null-terminated
         hostname[NI_MAXHOST] = '\0';
+        memset(&hints, 0, sizeof(hints));
+        hints.ai_flags = AI_CANONNAME;
+        hints.ai_family = AF_UNSPEC;
+
+        if (getaddrinfo(hostname, NULL, &hints, &res) == 0) {
+            getnameinfo(res->ai_addr, res->ai_addrlen, hostname, sizeof(hostname),
+                        NULL, 0, NI_NAMEREQD);
+            freeaddrinfo(res);
+        }
+#else
+        // make sure string is null-terminated
+        hostname[NI_MAXHOST] = '\0';
+#endif
     }
     return (*env)->NewStringUTF(env, hostname);
 }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/net_util_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/net_util_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/net_util_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/net_util_md.c	2024-08-17 18:29:44.500121772 +0200
@@ -37,6 +37,14 @@
 #include <sys/utsname.h>
 #endif
 
+#if defined(__solaris__)
+#include <inet/nd.h>
+#include <limits.h>
+#include <stropts.h>
+#include <sys/filio.h>
+#include <sys/sockio.h>
+#endif
+
 #if defined(MACOSX)
 #include <sys/sysctl.h>
 #endif
@@ -51,6 +59,20 @@
 #define IPV6_FLOWINFO_SEND      33
 #endif
 
+#if defined(__solaris__) && !defined(MAXINT)
+#define MAXINT INT_MAX
+#endif
+
+/*
+ * EXCLBIND socket options only on Solaris
+ */
+#if defined(__solaris__) && !defined(TCP_EXCLBIND)
+#define TCP_EXCLBIND            0x21
+#endif
+#if defined(__solaris__) && !defined(UDP_EXCLBIND)
+#define UDP_EXCLBIND            0x0101
+#endif
+
 #define RESTARTABLE(_cmd, _result) do { \
     do { \
         _result = _cmd; \
@@ -63,6 +85,94 @@
     return result;
 }
 
+#ifdef __solaris__
+static int init_tcp_max_buf, init_udp_max_buf;
+static int tcp_max_buf;
+static int udp_max_buf;
+static int useExclBind = 0;
+
+/*
+ * Get the specified parameter from the specified driver. The value
+ * of the parameter is assumed to be an 'int'. If the parameter
+ * cannot be obtained return -1
+ */
+int net_getParam(char *driver, char *param)
+{
+    struct strioctl stri;
+    char buf [64];
+    int s;
+    int value;
+
+    s = open (driver, O_RDWR);
+    if (s < 0) {
+        return -1;
+    }
+    strncpy (buf, param, sizeof(buf));
+    stri.ic_cmd = ND_GET;
+    stri.ic_timout = 0;
+    stri.ic_dp = buf;
+    stri.ic_len = sizeof(buf);
+    if (ioctl (s, I_STR, &stri) < 0) {
+        value = -1;
+    } else {
+        value = atoi(buf);
+    }
+    close (s);
+    return value;
+}
+
+/*
+ * Iterative way to find the max value that SO_SNDBUF or SO_RCVBUF
+ * for Solaris versions that do not support the ioctl() in net_getParam().
+ * Ugly, but only called once (for each sotype).
+ *
+ * As an optimization, we make a guess using the default values for Solaris
+ * assuming they haven't been modified with ndd.
+ */
+
+#define MAX_TCP_GUESS 1024 * 1024
+#define MAX_UDP_GUESS 2 * 1024 * 1024
+
+#define FAIL_IF_NOT_ENOBUFS if (errno != ENOBUFS) return -1
+
+static int findMaxBuf(int fd, int opt, int sotype) {
+    int a = 0;
+    int b = MAXINT;
+    int initial_guess;
+    int limit = -1;
+
+    if (sotype == SOCK_DGRAM) {
+        initial_guess = MAX_UDP_GUESS;
+    } else {
+        initial_guess = MAX_TCP_GUESS;
+    }
+
+    if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess, sizeof(int)) == 0) {
+        initial_guess++;
+        if (setsockopt(fd, SOL_SOCKET, opt, &initial_guess,sizeof(int)) < 0) {
+            FAIL_IF_NOT_ENOBUFS;
+            return initial_guess - 1;
+        }
+        a = initial_guess;
+    } else {
+        FAIL_IF_NOT_ENOBUFS;
+        b = initial_guess - 1;
+    }
+    do {
+        int mid = a + (b-a)/2;
+        if (setsockopt(fd, SOL_SOCKET, opt, &mid, sizeof(int)) == 0) {
+            limit = mid;
+            a = mid + 1;
+        } else {
+            FAIL_IF_NOT_ENOBUFS;
+            b = mid - 1;
+        }
+    } while (b >= a);
+
+    return limit;
+}
+#endif
+
 void
 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                    const char *defaultDetail) {
@@ -173,6 +283,50 @@
     }
 #endif
 
+    /**
+     * On Solaris 8 it's possible to create INET6 sockets even
+     * though IPv6 is not enabled on all interfaces. Thus we
+     * query the number of IPv6 addresses to verify that IPv6
+     * has been configured on at least one interface.
+     *
+     * On Linux it doesn't matter - if IPv6 is built-in the
+     * kernel then IPv6 addresses will be bound automatically
+     * to all interfaces.
+     */
+#ifdef __solaris__
+
+#ifdef SIOCGLIFNUM
+    {
+        struct lifnum numifs;
+
+        numifs.lifn_family = AF_INET6;
+        numifs.lifn_flags = 0;
+        if (ioctl(fd, SIOCGLIFNUM, (char *)&numifs) < 0) {
+            /**
+             * SIOCGLIFNUM failed - assume IPv6 not configured
+             */
+            close(fd);
+            return JNI_FALSE;
+        }
+        /**
+         * If no IPv6 addresses then return false. If count > 0
+         * it's possible that all IPv6 addresses are "down" but
+         * that's okay as they may be brought "up" while the
+         * VM is running.
+         */
+        if (numifs.lifn_count == 0) {
+            close(fd);
+            return JNI_FALSE;
+        }
+    }
+#else
+    /* SIOCGLIFNUM not defined in build environment ??? */
+    close(fd);
+    return JNI_FALSE;
+#endif
+
+#endif /* __solaris */
+
     /*
      *  OK we may have the stack available in the kernel,
      *  we should also check if the APIs are available.
@@ -249,6 +403,26 @@
 
 #endif
 
+void parseExclusiveBindProperty(JNIEnv *env) {
+#ifdef __solaris__
+    jstring s, flagSet;
+    jclass iCls;
+    jmethodID mid;
+
+    s = (*env)->NewStringUTF(env, "sun.net.useExclusiveBind");
+    CHECK_NULL(s);
+    iCls = (*env)->FindClass(env, "java/lang/System");
+    CHECK_NULL(iCls);
+    mid = (*env)->GetStaticMethodID(env, iCls, "getProperty",
+                "(Ljava/lang/String;)Ljava/lang/String;");
+    CHECK_NULL(mid);
+    flagSet = (*env)->CallStaticObjectMethod(env, iCls, mid, s);
+    if (flagSet != NULL) {
+        useExclBind = 1;
+    }
+#endif
+}
+
 JNIEXPORT jint JNICALL
 NET_EnableFastTcpLoopback(int fd) {
     return 0;
@@ -414,7 +588,7 @@
                 *level = IPPROTO_IPV6;
                 *optname = IPV6_MULTICAST_LOOP;
                 return 0;
-#if defined(MACOSX)
+#if (defined(__solaris__) || defined(MACOSX))
             // Map IP_TOS request to IPV6_TCLASS
             case java_net_SocketOptions_IP_TOS:
                 *level = IPPROTO_IPV6;
@@ -563,6 +737,65 @@
         *iptos &= (IPTOS_TOS_MASK | IPTOS_PREC_MASK);
     }
 
+    /*
+     * SOL_SOCKET/{SO_SNDBUF,SO_RCVBUF} - On Solaris we may need to clamp
+     * the value when it exceeds the system limit.
+     */
+#ifdef __solaris__
+    if (level == SOL_SOCKET) {
+        if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
+            int sotype=0;
+            socklen_t arglen;
+            int *bufsize, maxbuf;
+            int ret;
+
+            /* Attempt with the original size */
+            ret = setsockopt(fd, level, opt, arg, len);
+            if ((ret == 0) || (ret == -1 && errno != ENOBUFS))
+                return ret;
+
+            /* Exceeded system limit so clamp and retry */
+
+            arglen = sizeof(sotype);
+            if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (void *)&sotype,
+                           &arglen) < 0) {
+                return -1;
+            }
+
+            /*
+             * We try to get tcp_maxbuf (and udp_max_buf) using
+             * an ioctl() that isn't available on all versions of Solaris.
+             * If that fails, we use the search algorithm in findMaxBuf()
+             */
+            if (!init_tcp_max_buf && sotype == SOCK_STREAM) {
+                tcp_max_buf = net_getParam("/dev/tcp", "tcp_max_buf");
+                if (tcp_max_buf == -1) {
+                    tcp_max_buf = findMaxBuf(fd, opt, SOCK_STREAM);
+                    if (tcp_max_buf == -1) {
+                        return -1;
+                    }
+                }
+                init_tcp_max_buf = 1;
+            } else if (!init_udp_max_buf && sotype == SOCK_DGRAM) {
+                udp_max_buf = net_getParam("/dev/udp", "udp_max_buf");
+                if (udp_max_buf == -1) {
+                    udp_max_buf = findMaxBuf(fd, opt, SOCK_DGRAM);
+                    if (udp_max_buf == -1) {
+                        return -1;
+                    }
+                }
+                init_udp_max_buf = 1;
+            }
+
+            maxbuf = (sotype == SOCK_STREAM) ? tcp_max_buf : udp_max_buf;
+            bufsize = (int *)arg;
+            if (*bufsize > maxbuf) {
+                *bufsize = maxbuf;
+            }
+        }
+    }
+#endif
+
 #ifdef _AIX
     if (level == SOL_SOCKET) {
         if (opt == SO_SNDBUF || opt == SO_RCVBUF) {
@@ -675,10 +908,19 @@
  *
  * Linux allows a socket to bind to 127.0.0.255 which must be
  * caught.
+ *
+ * On Solaris with IPv6 enabled we must use an exclusive
+ * bind to guarantee a unique port number across the IPv4 and
+ * IPv6 port spaces.
+ *
  */
 int
 NET_Bind(int fd, SOCKETADDRESS *sa, int len)
 {
+#if defined(__solaris__)
+    int level = -1;
+    int exclbind = -1;
+#endif
     int rv;
     int arg, alen;
 
@@ -696,8 +938,61 @@
     }
 #endif
 
+#if defined(__solaris__)
+    /*
+     * Solaris has separate IPv4 and IPv6 port spaces so we
+     * use an exclusive bind when SO_REUSEADDR is not used to
+     * give the illusion of a unified port space.
+     * This also avoids problems with IPv6 sockets connecting
+     * to IPv4 mapped addresses whereby the socket conversion
+     * results in a late bind that fails because the
+     * corresponding IPv4 port is in use.
+     */
+    alen = sizeof(arg);
+
+    if (useExclBind ||
+        getsockopt(fd, SOL_SOCKET, SO_REUSEADDR, (char *)&arg, &alen) == 0)
+    {
+        if (useExclBind || arg == 0) {
+            /*
+             * SO_REUSEADDR is disabled or sun.net.useExclusiveBind
+             * property is true so enable TCP_EXCLBIND or
+             * UDP_EXCLBIND
+             */
+            alen = sizeof(arg);
+            if (getsockopt(fd, SOL_SOCKET, SO_TYPE, (char *)&arg, &alen) == 0)
+            {
+                if (arg == SOCK_STREAM) {
+                    level = IPPROTO_TCP;
+                    exclbind = TCP_EXCLBIND;
+                } else {
+                    level = IPPROTO_UDP;
+                    exclbind = UDP_EXCLBIND;
+                }
+            }
+
+            arg = 1;
+            setsockopt(fd, level, exclbind, (char *)&arg, sizeof(arg));
+        }
+    }
+
+#endif
+
     rv = bind(fd, &sa->sa, len);
 
+#if defined(__solaris__)
+    if (rv < 0) {
+        int en = errno;
+        /* Restore *_EXCLBIND if the bind fails */
+        if (exclbind != -1) {
+            int arg = 0;
+            setsockopt(fd, level, exclbind, (char *)&arg,
+                       sizeof(arg));
+        }
+        errno = en;
+    }
+#endif
+
     return rv;
 }
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/net_util_md.h jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/net_util_md.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/net_util_md.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/net_util_md.h	2024-08-17 18:29:44.500619413 +0200
@@ -47,6 +47,8 @@
 #ifndef SO_REUSEPORT
 #ifdef __linux__
 #define SO_REUSEPORT 15
+#elif defined(__solaris__)
+#define SO_REUSEPORT 0x100e
 #elif defined(AIX) || defined(MACOSX)
 #define SO_REUSEPORT 0x0200
 #else
@@ -96,4 +98,8 @@
                                   const char *defaultDetail);
 void NET_SetTrafficClass(SOCKETADDRESS *sa, int trafficClass);
 
+#ifdef __solaris__
+int net_getParam(char *driver, char *param);
+#endif
+
 #endif /* NET_UTILS_MD_H */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/NetworkInterface.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/NetworkInterface.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/NetworkInterface.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/NetworkInterface.c	2024-08-17 18:29:44.497500628 +0200
@@ -37,6 +37,12 @@
 #include <strings.h>
 #endif
 
+#if defined(__solaris__)
+#include <stropts.h>
+#include <sys/dlpi.h>
+#include <sys/sockio.h>
+#endif
+
 #if defined(_ALLBSD_SOURCE)
 #include <net/ethernet.h>
 #include <net/if_dl.h>
@@ -49,6 +55,11 @@
 
 #if defined(__linux__)
     #define _PATH_PROCNET_IFINET6 "/proc/net/if_inet6"
+#elif defined(__solaris__)
+    #ifndef SIOCGLIFHWADDR
+        #define SIOCGLIFHWADDR _IOWR('i', 192, struct lifreq)
+    #endif
+    #define DEV_PREFIX "/dev/"
 #endif
 
 #ifdef LIFNAMSIZ
@@ -136,6 +147,11 @@
                              const struct in_addr *addr, unsigned char *buf);
 static int     getMTU(JNIEnv *env, int sock, const char *ifname);
 
+#if defined(__solaris__)
+static int     getMacFromDevice(JNIEnv *env, const char *ifname,
+                                unsigned char *retbuf);
+#endif
+
 /******************* Java entry points *****************************/
 
 /*
@@ -1663,6 +1679,372 @@
 
 #endif /* _AIX */
 
+/** Solaris **/
+#if defined(__solaris__)
+
+/*
+ * Opens a socket for further ioctl calls. Tries AF_INET socket first and
+ * if it fails return AF_INET6 socket.
+ */
+static int openSocketWithFallback(JNIEnv *env, const char *ifname) {
+    int sock, alreadyV6 = 0;
+    struct lifreq if2;
+
+    if ((sock = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {
+        if (errno == EPROTONOSUPPORT || errno == EAFNOSUPPORT) {
+            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+                JNU_ThrowByNameWithMessageAndLastError
+                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
+                return -1;
+            }
+            alreadyV6 = 1;
+        } else { // errno is not NOSUPPORT
+            JNU_ThrowByNameWithMessageAndLastError
+                (env, JNU_JAVANETPKG "SocketException", "IPV4 Socket creation failed");
+            return -1;
+        }
+    }
+
+    // Solaris requires that we have an IPv6 socket to query an  interface
+    // without an IPv4 address - check it here. POSIX 1 require the kernel to
+    // return ENOTTY if the call is inappropriate for a device e.g. the NETMASK
+    // for a device having IPv6 only address but not all devices follow the
+    // standard so fall back on any error. It's not an ecologically friendly
+    // gesture but more reliable.
+    if (!alreadyV6) {
+        memset((char *)&if2, 0, sizeof(if2));
+        strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
+        if (ioctl(sock, SIOCGLIFNETMASK, (char *)&if2) < 0) {
+            close(sock);
+            if ((sock = socket(AF_INET6, SOCK_DGRAM, 0)) < 0) {
+                JNU_ThrowByNameWithMessageAndLastError
+                    (env, JNU_JAVANETPKG "SocketException", "IPV6 Socket creation failed");
+                return -1;
+            }
+        }
+    }
+
+    return sock;
+}
+
+/*
+ * Enumerates and returns all IPv4 interfaces on Solaris.
+ */
+static netif *enumIPv4Interfaces(JNIEnv *env, int sock, netif *ifs) {
+    struct lifconf ifc;
+    struct lifreq *ifreqP;
+    struct lifnum numifs;
+    char *buf = NULL;
+    unsigned i;
+
+    // call SIOCGLIFNUM to get the interface count
+    numifs.lifn_family = AF_INET;
+    numifs.lifn_flags = 0;
+    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
+        return ifs;
+    }
+
+    // call SIOCGLIFCONF to enumerate the interfaces
+    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
+    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
+    ifc.lifc_buf = buf;
+    ifc.lifc_family = AF_INET;
+    ifc.lifc_flags = 0;
+    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
+        free(buf);
+        return ifs;
+    }
+
+    // iterate through each interface
+    ifreqP = ifc.lifc_req;
+    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
+        struct sockaddr addr, *broadaddrP = NULL;
+
+        // ignore non IPv4 addresses
+        if (ifreqP->lifr_addr.ss_family != AF_INET) {
+            continue;
+        }
+
+        // save socket address
+        memcpy(&addr, &(ifreqP->lifr_addr), sizeof(struct sockaddr));
+
+        // determine broadcast address, if applicable
+        if ((ioctl(sock, SIOCGLIFFLAGS, ifreqP) == 0) &&
+            ifreqP->lifr_flags & IFF_BROADCAST) {
+
+            // restore socket address to ifreqP
+            memcpy(&(ifreqP->lifr_addr), &addr, sizeof(struct sockaddr));
+
+            // query broadcast address and set pointer to it
+            if (ioctl(sock, SIOCGLIFBRDADDR, ifreqP) == 0) {
+                broadaddrP = (struct sockaddr *)&(ifreqP->lifr_broadaddr);
+            }
+        }
+
+        // add to the list
+        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
+                    &addr, broadaddrP, AF_INET, (short)ifreqP->lifr_addrlen);
+
+        // if an exception occurred we return immediately
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            return ifs;
+        }
+   }
+
+    // free buffer
+    free(buf);
+    return ifs;
+}
+
+/*
+ * Enumerates and returns all IPv6 interfaces on Solaris.
+ */
+static netif *enumIPv6Interfaces(JNIEnv *env, int sock, netif *ifs) {
+    struct lifconf ifc;
+    struct lifreq *ifreqP;
+    struct lifnum numifs;
+    char *buf = NULL;
+    unsigned i;
+
+    // call SIOCGLIFNUM to get the interface count
+    numifs.lifn_family = AF_INET6;
+    numifs.lifn_flags = 0;
+    if (ioctl(sock, SIOCGLIFNUM, (char *)&numifs) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFNUM) failed");
+        return ifs;
+    }
+
+    // call SIOCGLIFCONF to enumerate the interfaces
+    ifc.lifc_len = numifs.lifn_count * sizeof(struct lifreq);
+    CHECKED_MALLOC3(buf, char *, ifc.lifc_len);
+    ifc.lifc_buf = buf;
+    ifc.lifc_family = AF_INET6;
+    ifc.lifc_flags = 0;
+    if (ioctl(sock, SIOCGLIFCONF, (char *)&ifc) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFCONF) failed");
+        free(buf);
+        return ifs;
+    }
+
+    // iterate through each interface
+    ifreqP = ifc.lifc_req;
+    for (i = 0; i < numifs.lifn_count; i++, ifreqP++) {
+
+        // ignore non IPv6 addresses
+        if (ifreqP->lifr_addr.ss_family != AF_INET6) {
+            continue;
+        }
+
+        // set scope ID to interface index
+        ((struct sockaddr_in6 *)&(ifreqP->lifr_addr))->sin6_scope_id =
+            getIndex(sock, ifreqP->lifr_name);
+
+        // add to the list
+        ifs = addif(env, sock, ifreqP->lifr_name, ifs,
+                    (struct sockaddr *)&(ifreqP->lifr_addr),
+                    NULL, AF_INET6, (short)ifreqP->lifr_addrlen);
+
+        // if an exception occurred we return immediately
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            return ifs;
+        }
+    }
+
+    // free buffer
+    free(buf);
+    return ifs;
+}
+
+/*
+ * Try to get the interface index.
+ * (Not supported on Solaris 2.6 or 7)
+ */
+static int getIndex(int sock, const char *name) {
+    struct lifreq if2;
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.lifr_name, name, sizeof(if2.lifr_name) - 1);
+
+    if (ioctl(sock, SIOCGLIFINDEX, (char *)&if2) < 0) {
+        return -1;
+    }
+
+    return if2.lifr_index;
+}
+
+/*
+ * Solaris specific DLPI code to get hardware address from a device.
+ * Unfortunately, at least up to Solaris X, you have to have special
+ * privileges (i.e. be root).
+ */
+static int getMacFromDevice
+  (JNIEnv *env, const char *ifname, unsigned char *retbuf)
+{
+    char style1dev[MAXPATHLEN];
+    int fd;
+    dl_phys_addr_req_t dlpareq;
+    dl_phys_addr_ack_t *dlpaack;
+    dl_error_ack_t     *dlerack;
+    struct strbuf msg;
+    char buf[128];
+    int flags = 0;
+
+    // Device is in /dev.  e.g.: /dev/bge0
+    strcpy(style1dev, DEV_PREFIX);
+    strcat(style1dev, ifname);
+    if ((fd = open(style1dev, O_RDWR)) < 0) {
+        // Can't open it. We probably are missing the privilege.
+        // We'll have to try something else
+        return 0;
+    }
+
+    dlpareq.dl_primitive = DL_PHYS_ADDR_REQ;
+    dlpareq.dl_addr_type = DL_CURR_PHYS_ADDR;
+
+    msg.buf = (char *)&dlpareq;
+    msg.len = DL_PHYS_ADDR_REQ_SIZE;
+
+    if (putmsg(fd, &msg, NULL, 0) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "putmsg() failed");
+        return -1;
+    }
+
+    dlpaack = (dl_phys_addr_ack_t *)buf;
+
+    msg.buf = (char *)buf;
+    msg.len = 0;
+    msg.maxlen = sizeof (buf);
+    if (getmsg(fd, &msg, NULL, &flags) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "getmsg() failed");
+        return -1;
+    }
+
+    if (dlpaack->dl_primitive == DL_ERROR_ACK) {
+        dlerack = (dl_error_ack_t *)buf;
+        if (dlerack->dl_error_primitive != DL_PHYS_ADDR_REQ) {
+            JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                           "Couldn't obtain physical address\n");
+            return -1;
+        }
+        if (dlerack->dl_errno == DL_UNSUPPORTED) {
+            // fallback to lookup in the ARP table
+            return 0;
+        }
+    }
+
+    if (msg.len < DL_PHYS_ADDR_ACK_SIZE || dlpaack->dl_primitive != DL_PHYS_ADDR_ACK) {
+        JNU_ThrowByName(env, JNU_JAVANETPKG "SocketException",
+                        "Couldn't obtain phys addr\n");
+        return -1;
+    }
+
+    memcpy(retbuf, &buf[dlpaack->dl_addr_offset], dlpaack->dl_addr_length);
+    return dlpaack->dl_addr_length;
+}
+
+/*
+ * Gets the Hardware address (usually MAC address) for the named interface.
+ * On return puts the data in buf, and returns the length, in byte, of the
+ * MAC address. Returns -1 if there is no hardware address on that interface.
+ */
+static int getMacAddress
+  (JNIEnv *env, const char *ifname, const struct in_addr *addr,
+   unsigned char *buf)
+{
+    struct lifreq if2;
+    int len, i, sock;
+
+    if ((sock = openSocketWithFallback(env, ifname)) < 0) {
+        return -1;
+    }
+
+    // First, try the new (S11) SIOCGLIFHWADDR ioctl(). If that fails
+    // try the old way.
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
+
+    if (ioctl(sock, SIOCGLIFHWADDR, &if2) != -1) {
+        struct sockaddr_dl *sp;
+        sp = (struct sockaddr_dl *)&if2.lifr_addr;
+        memcpy(buf, &sp->sdl_data[0], sp->sdl_alen);
+        close(sock);
+        return sp->sdl_alen;
+    }
+
+    // On Solaris we have to use DLPI, but it will only work if we have
+    // privileged access (i.e. root). If that fails, we try a lookup
+    // in the ARP table, which requires an IPv4 address.
+    if (((len = getMacFromDevice(env, ifname, buf)) == 0) && (addr != NULL)) {
+        struct arpreq arpreq;
+        struct sockaddr_in *sin;
+        struct sockaddr_in ipAddr;
+
+        len = 6; //???
+
+        sin = (struct sockaddr_in *)&arpreq.arp_pa;
+        memset((char *)&arpreq, 0, sizeof(struct arpreq));
+        ipAddr.sin_port = 0;
+        ipAddr.sin_family = AF_INET;
+        memcpy(&ipAddr.sin_addr, addr, sizeof(struct in_addr));
+        memcpy(&arpreq.arp_pa, &ipAddr, sizeof(struct sockaddr_in));
+        arpreq.arp_flags= ATF_PUBL;
+
+        if (ioctl(sock, SIOCGARP, &arpreq) < 0) {
+            close(sock);
+            return -1;
+        }
+
+        memcpy(buf, &arpreq.arp_ha.sa_data[0], len);
+    }
+    close(sock);
+
+    // all bytes to 0 means no hardware address
+    for (i = 0; i < len; i++) {
+        if (buf[i] != 0)
+            return len;
+    }
+
+    return -1;
+}
+
+static int getMTU(JNIEnv *env, int sock, const char *ifname) {
+    struct lifreq if2;
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
+
+    if (ioctl(sock, SIOCGLIFMTU, (char *)&if2) < 0) {
+        JNU_ThrowByNameWithMessageAndLastError
+            (env, JNU_JAVANETPKG "SocketException", "ioctl(SIOCGLIFMTU) failed");
+        return -1;
+    }
+
+    return if2.lifr_mtu;
+}
+
+static int getFlags(int sock, const char *ifname, int *flags) {
+    struct lifreq if2;
+    memset((char *)&if2, 0, sizeof(if2));
+    strncpy(if2.lifr_name, ifname, sizeof(if2.lifr_name) - 1);
+
+    if (ioctl(sock, SIOCGLIFFLAGS, (char *)&if2) < 0) {
+        return -1;
+    }
+
+    *flags = if2.lifr_flags;
+    return 0;
+}
+
+#endif /* __solaris__ */
+
 /** BSD **/
 #if defined(_ALLBSD_SOURCE)
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/portconfig.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/portconfig.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/portconfig.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/portconfig.c	2024-08-17 18:29:44.501026025 +0200
@@ -60,6 +60,13 @@
         }
         return -1;
     }
+
+#elif defined(__solaris__)
+    {
+        range->higher = net_getParam("/dev/tcp", "tcp_largest_anon_port");
+        range->lower = net_getParam("/dev/tcp", "tcp_smallest_anon_port");
+        return 0;
+    }
 #elif defined(_ALLBSD_SOURCE)
     {
         int ret;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/ResolverConfigurationImpl.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/ResolverConfigurationImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/ResolverConfigurationImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/ResolverConfigurationImpl.c	2024-08-17 18:29:44.498041684 +0200
@@ -28,6 +28,10 @@
 #include <unistd.h>
 #include <errno.h>
 
+#ifdef __solaris__
+#include <sys/systeminfo.h>
+#endif
+
 #include <string.h>
 
 #include "jni.h"
@@ -39,6 +43,30 @@
 
 /*
  * Class:     sun_net_dns_ResolverConfigurationImpl
+ * Method:    localDomain0
+ * Signature: ()Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL
+Java_sun_net_dns_ResolverConfigurationImpl_localDomain0(JNIEnv *env, jclass cls)
+{
+    /*
+     * On Solaris the LOCALDOMAIN environment variable has absolute
+     * priority.
+     */
+#ifdef __solaris__
+    {
+        char *cp = getenv("LOCALDOMAIN");
+        if (cp != NULL) {
+            jstring s = (*env)->NewStringUTF(env, cp);
+            return s;
+        }
+    }
+#endif
+    return (jstring)NULL;
+}
+
+/*
+ * Class:     sun_net_dns_ResolverConfigurationImpl
  * Method:    loadConfig0
  * Signature: ()Ljava/lang/String;
  */
@@ -48,10 +76,36 @@
     char buf[MAXDNAME];
 
     /*
-     * If domain or search directives aren't specified
+     * On Solaris if domain or search directives aren't specified
+     * in /etc/resolv.conf then sysinfo or gethostname is used to
+     * determine the domain name.
+     *
+     * On Linux if domain or search directives aren't specified
      * then gethostname is used.
      */
 
+#ifdef __solaris__
+    {
+        int ret = sysinfo(SI_SRPC_DOMAIN, buf, sizeof(buf));
+
+        if ((ret > 0) && (ret<sizeof(buf))) {
+            char *cp;
+            jstring s;
+
+            if (buf[0] == '+') {
+                buf[0] = '.';
+            }
+            cp = strchr(buf, '.');
+            if (cp == NULL) {
+                s = (*env)->NewStringUTF(env, buf);
+            } else {
+                s = (*env)->NewStringUTF(env, cp+1);
+            }
+            return s;
+        }
+    }
+#endif
+
     if (gethostname(buf, sizeof(buf)) == 0) {
         char *cp;
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/SdpSupport.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/SdpSupport.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnet/SdpSupport.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnet/SdpSupport.c	2024-08-17 18:29:44.498541845 +0200
@@ -27,7 +27,11 @@
 #include <sys/socket.h>
 #include <errno.h>
 
-#if defined(__linux__)
+#if defined(__solaris__)
+  #if !defined(PROTO_SDP)
+    #define PROTO_SDP       257
+  #endif
+#elif defined(__linux__)
   #if !defined(AF_INET_SDP)
     #define AF_INET_SDP     27
   #endif
@@ -51,7 +55,10 @@
 {
     int s;
 
-#if defined(__linux__)
+#if defined(__solaris__)
+    int domain = ipv6_available() ? AF_INET6 : AF_INET;
+    s = socket(domain, SOCK_STREAM, PROTO_SDP);
+#elif defined(__linux__)
     /**
      * IPv6 not supported by SDP on Linux
      */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c	2024-08-17 18:29:44.501593091 +0200
@@ -50,6 +50,9 @@
     jint fd = fdval(env, fdo);
     int rv;
 
+#if defined(__solaris__)
+    rv = connect(fd, 0, 0);
+#else
 #if defined(__APPLE__)
     // On macOS systems we use disconnectx
     rv = disconnectx(fd, SAE_ASSOCID_ANY, SAE_CONNID_ANY);
@@ -83,6 +86,8 @@
         rv = errno = 0;
 #endif // defined(_ALLBSD_SOURCE) || defined(_AIX)
 
+#endif // defined(__solaris__)
+
     if (rv < 0)
         handleSocketError(env, errno);
 }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/FileChannelImpl.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/FileChannelImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/FileChannelImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/FileChannelImpl.c	2024-08-17 18:29:44.502084642 +0200
@@ -29,7 +29,7 @@
 #include <sys/types.h>
 #include <unistd.h>
 
-#if defined(__linux__)
+#if defined(__linux__) || defined(__solaris__)
 #include <sys/sendfile.h>
 #elif defined(_AIX)
 #include <string.h>
@@ -182,6 +182,36 @@
         return IOS_THROWN;
     }
     return n;
+#elif defined (__solaris__)
+    sendfilevec64_t sfv;
+    size_t numBytes = 0;
+    jlong result;
+
+    sfv.sfv_fd = srcFD;
+    sfv.sfv_flag = 0;
+    sfv.sfv_off = (off64_t)position;
+    sfv.sfv_len = count;
+
+    result = sendfilev64(dstFD, &sfv, 1, &numBytes);
+
+    /* Solaris sendfilev() will return -1 even if some bytes have been
+     * transferred, so we check numBytes first.
+     */
+    if (numBytes > 0)
+        return numBytes;
+    if (result < 0) {
+        if (errno == EAGAIN)
+            return IOS_UNAVAILABLE;
+        if (errno == EOPNOTSUPP)
+            return IOS_UNSUPPORTED_CASE;
+        if ((errno == EINVAL) && ((ssize_t)count >= 0))
+            return IOS_UNSUPPORTED_CASE;
+        if (errno == EINTR)
+            return IOS_INTERRUPTED;
+        JNU_ThrowIOExceptionWithLastError(env, "Transfer failed");
+        return IOS_THROWN;
+    }
+    return result;
 #elif defined(__APPLE__)
     off_t numBytes;
     int result;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/NativeThread.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/NativeThread.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/NativeThread.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/NativeThread.c	2024-08-17 18:29:44.502566358 +0200
@@ -40,6 +40,9 @@
 #elif defined(_AIX)
   /* Also defined in net/aix_close.c */
   #define INTERRUPT_SIGNAL (SIGRTMAX - 1)
+#elif defined(__solaris__)
+  #include <thread.h>
+  #define INTERRUPT_SIGNAL (SIGRTMAX - 2)
 #elif defined(_ALLBSD_SOURCE)
   /* Also defined in net/bsd_close.c */
   #define INTERRUPT_SIGNAL SIGIO
@@ -74,14 +77,22 @@
 JNIEXPORT jlong JNICALL
 Java_sun_nio_ch_NativeThread_current(JNIEnv *env, jclass cl)
 {
+#ifdef __solaris__
+    return (jlong)thr_self();
+#else
     return (jlong)pthread_self();
+#endif
 }
 
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_NativeThread_signal(JNIEnv *env, jclass cl, jlong thread)
 {
     int ret;
+#ifdef __solaris__
+    ret = thr_kill((thread_t)thread, INTERRUPT_SIGNAL);
+#else
     ret = pthread_kill((pthread_t)thread, INTERRUPT_SIGNAL);
+#endif
 #ifdef MACOSX
     if (ret != 0 && ret != ESRCH)
 #else
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/Net.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/Net.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/Net.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/Net.c	2024-08-17 18:29:44.503172913 +0200
@@ -170,7 +170,7 @@
 JNIEXPORT jboolean JNICALL
 Java_sun_nio_ch_Net_canIPv6SocketJoinIPv4Group0(JNIEnv* env, jclass cl)
 {
-#if defined(__linux__) || defined(__APPLE__)
+#if defined(__linux__) || defined(__APPLE__) || defined(__solaris__)
     /* IPv6 sockets can join IPv4 multicast groups */
     return JNI_TRUE;
 #else
@@ -182,7 +182,7 @@
 JNIEXPORT jboolean JNICALL
 Java_sun_nio_ch_Net_canJoin6WithIPv4Group0(JNIEnv* env, jclass cl)
 {
-#if defined(__APPLE__)
+#if defined(__APPLE__) || defined(__solaris__)
     /* IPV6_ADD_MEMBERSHIP can be used to join IPv4 multicast groups */
     return JNI_TRUE;
 #else
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/nio_util.h jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/nio_util.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/ch/nio_util.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/ch/nio_util.h	2024-08-17 18:29:44.503568527 +0200
@@ -41,6 +41,8 @@
 #ifndef SO_REUSEPORT
 #ifdef __linux__
 #define SO_REUSEPORT 15
+#elif defined(__solaris__)
+#define SO_REUSEPORT 0x100e
 #elif defined(AIX) || defined(MACOSX)
 #define SO_REUSEPORT 0x0200
 #else
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c	2024-08-17 18:29:44.504282601 +0200
@@ -45,10 +45,17 @@
 #include <sys/xattr.h>
 #endif
 
-/* For POSIX-compliant getpwuid_r */
+/* For POSIX-compliant getpwuid_r, getgrgid_r on Solaris */
+#if defined(__solaris__)
+#define _POSIX_PTHREAD_SEMANTICS
+#endif
 #include <pwd.h>
 #include <grp.h>
 
+#ifdef __solaris__
+#include <strings.h>
+#endif
+
 #ifdef __linux__
 #include <sys/syscall.h>
 #endif
@@ -260,7 +267,8 @@
 
     /* system calls that might not be available at run time */
 
-#if defined(_ALLBSD_SOURCE)
+#if (defined(__solaris__) && defined(_LP64)) || defined(_ALLBSD_SOURCE)
+    /* Solaris 64-bit does not have openat64/fstatat64 */
     my_openat64_func = (openat64_func*)dlsym(RTLD_DEFAULT, "openat");
     my_fstatat64_func = (fstatat64_func*)dlsym(RTLD_DEFAULT, "fstatat");
 #else
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/windows/native/libnet/net_util_md.c jdk18u-jdk-18.0.2.1-ga/src/java.base/windows/native/libnet/net_util_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.base/windows/native/libnet/net_util_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.base/windows/native/libnet/net_util_md.c	2024-08-17 18:29:44.504946014 +0200
@@ -127,6 +127,7 @@
 }
 
 void platformInit() {}
+void parseExclusiveBindProperty(JNIEnv *env) {}
 
 /*
  * Since winsock doesn't have the equivalent of strerror(errno)
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/awt/FontConfiguration.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/awt/FontConfiguration.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/awt/FontConfiguration.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/awt/FontConfiguration.java	2024-08-17 18:29:44.505998508 +0200
@@ -1429,6 +1429,22 @@
                 }
             }
         }
+        if ("SunOS".equals(osName)) {
+            for (int ii = 0; ii < table_awtfontpaths.length; ii++) {
+                if (table_awtfontpaths[ii] == 0) {
+                    String script = getString(table_scriptIDs[ii]);
+                    if (script.contains("dingbats") ||
+                        script.contains("symbol")) {
+                        continue;
+                    }
+                    System.err.println("\nError: "
+                                       + "<awtfontpath."
+                                       + script
+                                       + "> entry is missing!!!");
+                    errors++;
+                }
+            }
+        }
         if (errors != 0) {
             System.err.println("!!THERE ARE " + errors + " ERROR(S) IN "
                                + "THE FONTCONFIG FILE, PLEASE CHECK ITS CONTENT!!\n");
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/awt/OSInfo.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/awt/OSInfo.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/awt/OSInfo.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/awt/OSInfo.java	2024-08-17 18:29:44.506504771 +0200
@@ -38,6 +38,7 @@
     public static enum OSType {
         WINDOWS,
         LINUX,
+        SOLARIS,
         MACOSX,
         AIX,
         UNKNOWN
@@ -99,6 +100,10 @@
                 return LINUX;
             }
 
+            if (osName.contains("Solaris") || osName.contains("SunOS")) {
+                return SOLARIS;
+            }
+
             if (osName.contains("OS X")) {
                 return MACOSX;
             }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/CMap.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/CMap.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/CMap.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/CMap.java	2024-08-17 18:29:44.507238168 +0200
@@ -234,8 +234,26 @@
                                   getConverterMap(GBKEncoding));
             }
             else if (three4 != 0) {
-                cmap = createCMap(cmapBuffer, three4,
-                                  getConverterMap(Big5Encoding));
+                /* GB2312 TrueType fonts on Solaris have wrong encoding ID for
+                 * cmap table, these fonts have EncodingID 4 which is Big5
+                 * encoding according the TrueType spec, but actually the
+                 * fonts are using gb2312 encoding, have to use this
+                 * workaround to make Solaris zh_CN locale work.  -sherman
+                 */
+                if (FontUtilities.isSolaris && font.platName != null &&
+                    (font.platName.startsWith(
+                     "/usr/openwin/lib/locale/zh_CN.EUC/X11/fonts/TrueType") ||
+                     font.platName.startsWith(
+                     "/usr/openwin/lib/locale/zh_CN/X11/fonts/TrueType") ||
+                     font.platName.startsWith(
+                     "/usr/openwin/lib/locale/zh/X11/fonts/TrueType"))) {
+                    cmap = createCMap(cmapBuffer, three4,
+                                       getConverterMap(GBKEncoding));
+                }
+                else {
+                    cmap = createCMap(cmapBuffer, three4,
+                                      getConverterMap(Big5Encoding));
+                }
             }
             else if (three5 != 0) {
                 cmap = createCMap(cmapBuffer, three5,
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/FileFont.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/FileFont.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/FileFont.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/FileFont.java	2024-08-17 18:29:44.507751944 +0200
@@ -76,6 +76,8 @@
      * the native path, since fonts have contiguous zero-based glyph indexes,
      * and these obviously do all exist in the font.
      */
+    protected boolean checkedNatives;
+    protected boolean useNatives;
     protected NativeFont[] nativeFonts;
     protected char[] glyphToCharMap;
     /*
@@ -88,9 +90,17 @@
     }
 
     FontStrike createStrike(FontStrikeDesc desc) {
+        if (!checkedNatives) {
+           checkUseNatives();
+        }
         return new FileFontStrike(this, desc);
     }
 
+    protected boolean checkUseNatives() {
+        checkedNatives = true;
+        return useNatives;
+    }
+
     /* This method needs to be accessible to FontManager if there is
      * file pool management. It may be a no-op.
      */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/FileFontStrike.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/FileFontStrike.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/FileFontStrike.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/FileFontStrike.java	2024-08-17 18:29:44.508339421 +0200
@@ -222,6 +222,24 @@
             !((TrueTypeFont)fileFont).useEmbeddedBitmapsForSize(intPtSize)) {
             useNatives = true;
         }
+        else if (fileFont.checkUseNatives() && desc.aaHint==0 && !algoStyle) {
+            /* Check its a simple scale of a pt size in the range
+             * where native bitmaps typically exist (6-36 pts) */
+            if (matrix[1] == 0.0 && matrix[2] == 0.0 &&
+                matrix[0] >= 6.0 && matrix[0] <= 36.0 &&
+                matrix[0] == matrix[3]) {
+                useNatives = true;
+                int numNatives = fileFont.nativeFonts.length;
+                nativeStrikes = new NativeStrike[numNatives];
+                /* Maybe initialise these strikes lazily?. But we
+                 * know we need at least one
+                 */
+                for (int i=0; i<numNatives; i++) {
+                    nativeStrikes[i] =
+                        new NativeStrike(fileFont.nativeFonts[i], desc, false);
+                }
+            }
+        }
         if (FontUtilities.isLogging() && FontUtilities.isWindows) {
             FontUtilities.logInfo("Strike for " + fileFont + " at size = " + intPtSize +
                  " use natives = " + useNatives +
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/FontUtilities.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/FontUtilities.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/FontUtilities.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/FontUtilities.java	2024-08-17 18:29:44.508893407 +0200
@@ -40,6 +40,8 @@
  */
 public final class FontUtilities {
 
+    public static boolean isSolaris;
+
     public static boolean isLinux;
 
     public static boolean isMacOSX;
@@ -65,6 +67,7 @@
             @Override
             public Object run() {
                 String osName = System.getProperty("os.name", "unknownOS");
+                isSolaris = osName.startsWith("SunOS");
 
                 isLinux = osName.startsWith("Linux");
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/SunFontManager.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/SunFontManager.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/SunFontManager.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/SunFontManager.java	2024-08-17 18:29:44.510340896 +0200
@@ -442,6 +442,24 @@
                     registerFontDirs(extraFontPath);
                 }
 
+                /* On Solaris, we need to register the Japanese TrueType
+                 * directory so that we can find the corresponding
+                 * bitmap fonts. This could be done by listing the
+                 * directory in the font configuration file, but we
+                 * don't want to confuse users with this quirk. There
+                 * are no bitmap fonts for other writing systems that
+                 * correspond to TrueType fonts and have matching XLFDs.
+                 * We need to register the bitmap fonts only in
+                 * environments where they're on the X font path, i.e.,
+                 * in the Japanese locale. Note that if the X Toolkit
+                 * is in use the font path isn't set up by JDK, but
+                 * users of a JA locale should have it
+                 * set up already by their login environment.
+                 */
+                if (FontUtilities.isSolaris && Locale.JAPAN.equals(Locale.getDefault())) {
+                    registerFontDir("/usr/openwin/lib/locale/ja/X11/fonts/TT");
+                }
+
                 initCompositeFonts(fontConfig, null);
 
                 return null;
@@ -2044,6 +2062,33 @@
             }
         }
 
+        /* Some apps use deprecated 1.0 names such as helvetica and courier. On
+         * Solaris these are Type1 fonts in /usr/openwin/lib/X11/fonts/Type1.
+         * If running on Solaris will register all the fonts in this
+         * directory.
+         * May as well register the whole directory without actually testing
+         * the font name is one of the deprecated names as the next step would
+         * load all fonts which are in this directory anyway.
+         * In the event that this lookup is successful it potentially "hides"
+         * TrueType versions of such fonts that are elsewhere but since they
+         * do not exist on Solaris this is not a problem.
+         * Set a flag to indicate we've done this registration to avoid
+         * repetition and more seriously, to avoid recursion.
+         */
+        if (FontUtilities.isSolaris &&!loaded1dot0Fonts) {
+            /* "timesroman" is a special case since that's not the
+             * name of any known font on Solaris or elsewhere.
+             */
+            if (lowerCaseName.equals("timesroman")) {
+                font = findFont2D("serif", style, fallback);
+                fontNameCache.put(mapName, font);
+            }
+            register1dot0Fonts();
+            loaded1dot0Fonts = true;
+            Font2D ff = findFont2D(name, style, fallback);
+            return ff;
+        }
+
         /* We check for application registered fonts before
          * explicitly loading all fonts as if necessary the registration
          * code will have done so anyway. And we don't want to needlessly
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/TrueTypeFont.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/TrueTypeFont.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/TrueTypeFont.java	2024-08-17 18:29:44.511210017 +0200
@@ -229,9 +229,84 @@
         Disposer.addObjectRecord(this, disposerRecord);
     }
 
+    /* Enable natives just for fonts picked up from the platform that
+     * may have external bitmaps on Solaris. Could do this just for
+     * the fonts that are specified in font configuration files which
+     * would lighten the burden (think about that).
+     * The EBLCTag is used to skip natives for fonts that contain embedded
+     * bitmaps as there's no need to use X11 for those fonts.
+     * Skip all the latin fonts as they don't need this treatment.
+     * Further refine this to fonts that are natively accessible (ie
+     * as PCF bitmap fonts on the X11 font path).
+     * This method is called when creating the first strike for this font.
+     */
+    @Override
+    protected boolean checkUseNatives() {
+        if (checkedNatives) {
+            return useNatives;
+        }
+        if (!FontUtilities.isSolaris || useJavaRasterizer ||
+            FontUtilities.useJDKScaler || nativeNames == null ||
+            getDirectoryEntry(EBLCTag) != null ||
+            GraphicsEnvironment.isHeadless()) {
+            checkedNatives = true;
+            return false; /* useNatives is false */
+        } else if (nativeNames instanceof String) {
+            String name = (String)nativeNames;
+            /* Don't do this for Latin fonts */
+            if (name.indexOf("8859") > 0) {
+                checkedNatives = true;
+                return false;
+            } else if (NativeFont.hasExternalBitmaps(name)) {
+                nativeFonts = new NativeFont[1];
+                try {
+                    nativeFonts[0] = new NativeFont(name, true);
+                    /* If reach here we have an non-latin font that has
+                     * external bitmaps and we successfully created it.
+                     */
+                    useNatives = true;
+                } catch (FontFormatException e) {
+                    nativeFonts = null;
+                }
+            }
+        } else if (nativeNames instanceof String[]) {
+            String[] natNames = (String[])nativeNames;
+            int numNames = natNames.length;
+            boolean externalBitmaps = false;
+            for (int nn = 0; nn < numNames; nn++) {
+                if (natNames[nn].indexOf("8859") > 0) {
+                    checkedNatives = true;
+                    return false;
+                } else if (NativeFont.hasExternalBitmaps(natNames[nn])) {
+                    externalBitmaps = true;
+                }
+            }
+            if (!externalBitmaps) {
+                checkedNatives = true;
+                return false;
+            }
+            useNatives = true;
+            nativeFonts = new NativeFont[numNames];
+            for (int nn = 0; nn < numNames; nn++) {
+                try {
+                    nativeFonts[nn] = new NativeFont(natNames[nn], true);
+                } catch (FontFormatException e) {
+                    useNatives = false;
+                    nativeFonts = null;
+                }
+            }
+        }
+        if (useNatives) {
+            glyphToCharMap = new char[getMapper().getNumGlyphs()];
+        }
+        checkedNatives = true;
+        return useNatives;
+    }
+
+
     private synchronized FileChannel open() throws FontFormatException {
         return open(true);
-    }
+     }
 
     /* This is intended to be called, and the returned value used,
      * from within a block synchronized on this font object.
@@ -982,7 +1057,14 @@
             style = Font.ITALIC;
             break;
         case fsSelectionBoldBit:
-            style = Font.BOLD;
+            if (FontUtilities.isSolaris && platName.endsWith("HG-GothicB.ttf")) {
+                /* Workaround for Solaris's use of a JA font that's marked as
+                 * being designed bold, but is used as a PLAIN font.
+                 */
+                style = Font.PLAIN;
+            } else {
+                style = Font.BOLD;
+            }
             break;
         case fsSelectionBoldBit|fsSelectionItalicBit:
             style = Font.BOLD|Font.ITALIC;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/Type1Font.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/Type1Font.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/classes/sun/font/Type1Font.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/classes/sun/font/Type1Font.java	2024-08-17 18:29:44.511771622 +0200
@@ -168,6 +168,7 @@
         throws FontFormatException {
         super(platname, nativeNames);
         fontRank = Font2D.TYPE1_RANK;
+        checkedNatives = true;
         try {
             verify();
         } catch (Throwable t) {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/native/libjsound/SoundDefs.h jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/native/libjsound/SoundDefs.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/share/native/libjsound/SoundDefs.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/share/native/libjsound/SoundDefs.h	2024-08-17 18:29:44.512350490 +0200
@@ -29,9 +29,10 @@
 
 // types for X_PLATFORM
 #define X_WINDOWS       1
-#define X_LINUX         2
-#define X_BSD           3
-#define X_MACOSX        4
+#define X_SOLARIS       2
+#define X_LINUX         3
+#define X_BSD           4
+#define X_MACOSX        5
 
 // **********************************
 // Make sure you set X_PLATFORM defines correctly.
@@ -44,7 +45,7 @@
 
 
 // following is needed for _LP64
-#if ((X_PLATFORM == X_LINUX) || (X_PLATFORM == X_MACOSX))
+#if ((X_PLATFORM == X_SOLARIS) || (X_PLATFORM == X_LINUX) || (X_PLATFORM == X_MACOSX))
 #include <sys/types.h>
 #endif
 
@@ -114,6 +115,11 @@
 #endif
 
 
+#if X_PLATFORM == X_SOLARIS
+#define INLINE
+#endif
+
+
 #if X_PLATFORM == X_LINUX
 #define INLINE          inline
 #endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java	2024-08-17 18:29:44.566067764 +0200
@@ -0,0 +1,178 @@
+/*
+ * Copyright (c) 2001, 2008, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.font;
+
+import java.nio.CharBuffer;
+import java.nio.ByteBuffer;
+import java.nio.charset.*;
+import sun.nio.cs.*;
+
+public abstract class X11CNS11643 extends Charset {
+    private final int plane;
+    public X11CNS11643 (int plane, String name) {
+        super(name, null);
+        switch (plane) {
+        case 1:
+            this.plane = 0; // CS1
+            break;
+        case 2:
+        case 3:
+            this.plane = plane;
+            break;
+        default:
+            throw new IllegalArgumentException
+                ("Only planes 1, 2, and 3 supported");
+        }
+    }
+
+    public CharsetEncoder newEncoder() {
+        return new Encoder(this, plane);
+    }
+
+    public CharsetDecoder newDecoder() {
+        return new Decoder(this, plane);
+    }
+
+    public boolean contains(Charset cs) {
+        return cs instanceof X11CNS11643;
+    }
+
+    private class Encoder extends EUC_TW.Encoder {
+        private int plane;
+        public Encoder(Charset cs, int plane) {
+            super(cs);
+            this.plane = plane;
+        }
+
+        private byte[] bb = new byte[4];
+        public boolean canEncode(char c) {
+            if (c <= 0x7F) {
+                return false;
+            }
+            int nb = toEUC(c, bb);
+            if (nb == -1)
+                return false;
+            int p = 0;
+            if (nb == 4)
+                p = (bb[1] & 0xff) - 0xa0;
+            return (p == plane);
+        }
+
+        public boolean isLegalReplacement(byte[] repl) {
+            return true;
+        }
+
+        protected CoderResult encodeLoop(CharBuffer src, ByteBuffer dst) {
+            char[] sa = src.array();
+            int sp = src.arrayOffset() + src.position();
+            int sl = src.arrayOffset() + src.limit();
+            byte[] da = dst.array();
+            int dp = dst.arrayOffset() + dst.position();
+            int dl = dst.arrayOffset() + dst.limit();
+
+            try {
+                while (sp < sl) {
+                    char c = sa[sp];
+                    if ( c > '\u007f'&& c < '\uFFFE') {
+                        int nb = toEUC(c, bb);
+                        if (nb != -1) {
+                            int p = 0;
+                            if (nb == 4)
+                                p = (bb[1] & 0xff) - 0xa0;
+                            if (p == plane) {
+                                if (dl - dp < 2)
+                                    return CoderResult.OVERFLOW;
+                                if (nb == 2) {
+                                    da[dp++] = (byte)(bb[0] & 0x7f);
+                                    da[dp++] = (byte)(bb[1] & 0x7f);
+                                } else {
+                                    da[dp++] = (byte)(bb[2] & 0x7f);
+                                    da[dp++] = (byte)(bb[3] & 0x7f);
+                                }
+                                sp++;
+                                continue;
+                            }
+                        }
+                    }
+                    return CoderResult.unmappableForLength(1);
+                }
+                return CoderResult.UNDERFLOW;
+            } finally {
+                src.position(sp - src.arrayOffset());
+                dst.position(dp - dst.arrayOffset());
+            }
+        }
+    }
+
+    private class Decoder extends EUC_TW.Decoder {
+        int plane;
+        private String table;
+        protected Decoder(Charset cs, int plane) {
+            super(cs);
+            if (plane == 0)
+                this.plane = plane;
+            else if (plane == 2 || plane == 3)
+                this.plane = plane - 1;
+            else
+                throw new IllegalArgumentException
+                    ("Only planes 1, 2, and 3 supported");
+        }
+
+        //we only work on array backed buffer.
+        protected CoderResult decodeLoop(ByteBuffer src, CharBuffer dst) {
+            byte[] sa = src.array();
+            int sp = src.arrayOffset() + src.position();
+            int sl = src.arrayOffset() + src.limit();
+
+            char[] da = dst.array();
+            int dp = dst.arrayOffset() + dst.position();
+            int dl = dst.arrayOffset() + dst.limit();
+
+            try {
+                while (sp < sl) {
+                    if ( sl - sp < 2) {
+                        return CoderResult.UNDERFLOW;
+                    }
+                    int b1 = (sa[sp] & 0xff) | 0x80;
+                    int b2 = (sa[sp + 1] & 0xff) | 0x80;
+                    char[] cc = toUnicode(b1, b2, plane);
+                    // plane3 has non-bmp characters(added), x11cnsp3
+                    // however does not support them
+                    if (cc == null || cc.length == 2)
+                        return CoderResult.unmappableForLength(2);
+                    if (dl - dp < 1)
+                        return CoderResult.OVERFLOW;
+                    da[dp++] = cc[0];
+                    sp +=2;
+                }
+                return CoderResult.UNDERFLOW;
+            } finally {
+                src.position(sp - src.arrayOffset());
+                dst.position(dp - dst.arrayOffset());
+            }
+        }
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java	2024-08-17 18:29:44.566369468 +0200
@@ -0,0 +1,33 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+
+package sun.font;
+
+public class X11CNS11643P1 extends X11CNS11643 {
+    public X11CNS11643P1() {
+        super(1, "X11CNS11643P1");
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java	2024-08-17 18:29:44.566669691 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1996, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.font;
+
+public class X11CNS11643P2 extends X11CNS11643 {
+    public X11CNS11643P2() {
+        super(2, "X11CNS11643P2");
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java	2024-08-17 18:29:44.566966269 +0200
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 1997, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+package sun.font;
+
+public class X11CNS11643P3 extends X11CNS11643 {
+    public X11CNS11643P3() {
+        super(3, "X11CNS11643P3");
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c	2024-08-17 18:29:44.567667218 +0200
@@ -0,0 +1,627 @@
+/*
+ * Copyright (c) 2003, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#include "PLATFORM_API_SolarisOS_Utils.h"
+#include "DirectAudio.h"
+
+#if USE_DAUDIO == TRUE
+
+
+// The default buffer time
+#define DEFAULT_PERIOD_TIME_MILLIS 50
+
+///// implemented functions of DirectAudio.h
+
+INT32 DAUDIO_GetDirectAudioDeviceCount() {
+    return (INT32) getAudioDeviceCount();
+}
+
+
+INT32 DAUDIO_GetDirectAudioDeviceDescription(INT32 mixerIndex,
+                                             DirectAudioDeviceDescription* description) {
+    AudioDeviceDescription desc;
+
+    if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
+        description->maxSimulLines = desc.maxSimulLines;
+        strncpy(description->name, desc.name, DAUDIO_STRING_LENGTH-1);
+        description->name[DAUDIO_STRING_LENGTH-1] = 0;
+        strncpy(description->vendor, desc.vendor, DAUDIO_STRING_LENGTH-1);
+        description->vendor[DAUDIO_STRING_LENGTH-1] = 0;
+        strncpy(description->version, desc.version, DAUDIO_STRING_LENGTH-1);
+        description->version[DAUDIO_STRING_LENGTH-1] = 0;
+        /*strncpy(description->description, desc.description, DAUDIO_STRING_LENGTH-1);*/
+        strncpy(description->description, "Solaris Mixer", DAUDIO_STRING_LENGTH-1);
+        description->description[DAUDIO_STRING_LENGTH-1] = 0;
+        return TRUE;
+    }
+    return FALSE;
+
+}
+
+#define MAX_SAMPLE_RATES   20
+
+void DAUDIO_GetFormats(INT32 mixerIndex, INT32 deviceID, int isSource, void* creator) {
+    int fd = -1;
+    AudioDeviceDescription desc;
+    am_sample_rates_t      *sr;
+    /* hardcoded bits and channels */
+    int bits[] = {8, 16};
+    int bitsCount = 2;
+    int channels[] = {1, 2};
+    int channelsCount = 2;
+    /* for querying sample rates */
+    int err;
+    int ch, b;
+    uint_t s;
+
+    TRACE2("DAUDIO_GetFormats, mixer %d, isSource=%d\n", mixerIndex, isSource);
+    if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
+        fd = open(desc.pathctl, O_RDONLY);
+    }
+    if (fd < 0) {
+        ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
+        return;
+    }
+
+    /* get sample rates */
+    sr = (am_sample_rates_t*) malloc(AUDIO_MIXER_SAMP_RATES_STRUCT_SIZE(MAX_SAMPLE_RATES));
+    if (sr == NULL) {
+        ERROR1("DAUDIO_GetFormats: out of memory for mixer %d\n", (int) mixerIndex);
+        close(fd);
+        return;
+    }
+
+    sr->num_samp_rates = MAX_SAMPLE_RATES;
+    sr->type = isSource?AUDIO_PLAY:AUDIO_RECORD;
+    sr->samp_rates[0] = -2;
+    err = ioctl(fd, AUDIO_MIXER_GET_SAMPLE_RATES, sr);
+    if (err < 0) {
+        ERROR1("  DAUDIO_GetFormats: AUDIO_MIXER_GET_SAMPLE_RATES failed for mixer %d!\n",
+               (int)mixerIndex);
+        ERROR2(" -> num_sample_rates=%d sample_rates[0] = %d\n",
+               (int) sr->num_samp_rates,
+               (int) sr->samp_rates[0]);
+        /* Some Solaris 8 drivers fail for get sample rates!
+         * Do as if we support all sample rates
+         */
+        sr->flags = MIXER_SR_LIMITS;
+    }
+    if ((sr->flags & MIXER_SR_LIMITS)
+        || (sr->num_samp_rates > MAX_SAMPLE_RATES)) {
+#ifdef USE_TRACE
+        if ((sr->flags & MIXER_SR_LIMITS)) {
+            TRACE1("  DAUDIO_GetFormats: floating sample rate allowed by mixer %d\n",
+                   (int)mixerIndex);
+        }
+        if (sr->num_samp_rates > MAX_SAMPLE_RATES) {
+            TRACE2("  DAUDIO_GetFormats: more than %d formats. Use -1 for sample rates mixer %d\n",
+                   MAX_SAMPLE_RATES, (int)mixerIndex);
+        }
+#endif
+        /*
+         * Fake it to have only one sample rate: -1
+         */
+        sr->num_samp_rates = 1;
+        sr->samp_rates[0] = -1;
+    }
+    close(fd);
+
+    for (ch = 0; ch < channelsCount; ch++) {
+        for (b = 0; b < bitsCount; b++) {
+            for (s = 0; s < sr->num_samp_rates; s++) {
+                DAUDIO_AddAudioFormat(creator,
+                                      bits[b], /* significant bits */
+                                      0, /* frameSize: let it be calculated */
+                                      channels[ch],
+                                      (float) ((int) sr->samp_rates[s]),
+                                      DAUDIO_PCM, /* encoding - let's only do PCM */
+                                      (bits[b] > 8)?TRUE:TRUE, /* isSigned */
+#ifdef _LITTLE_ENDIAN
+                                      FALSE /* little endian */
+#else
+                                      (bits[b] > 8)?TRUE:FALSE  /* big endian */
+#endif
+                                      );
+            }
+        }
+    }
+    free(sr);
+}
+
+
+typedef struct {
+    int fd;
+    audio_info_t info;
+    int bufferSizeInBytes;
+    int frameSize; /* storage size in Bytes */
+    /* how many bytes were written or read */
+    INT32 transferedBytes;
+    /* if transferedBytes exceed 32-bit boundary,
+     * it will be reset and positionOffset will receive
+     * the offset
+     */
+    INT64 positionOffset;
+} SolPcmInfo;
+
+
+void* DAUDIO_Open(INT32 mixerIndex, INT32 deviceID, int isSource,
+                  int encoding, float sampleRate, int sampleSizeInBits,
+                  int frameSize, int channels,
+                  int isSigned, int isBigEndian, int bufferSizeInBytes) {
+    int err = 0;
+    int openMode;
+    AudioDeviceDescription desc;
+    SolPcmInfo* info;
+
+    TRACE0("> DAUDIO_Open\n");
+    if (encoding != DAUDIO_PCM) {
+        ERROR1(" DAUDIO_Open: invalid encoding %d\n", (int) encoding);
+        return NULL;
+    }
+    if (channels <= 0) {
+        ERROR1(" DAUDIO_Open: Invalid number of channels=%d!\n", channels);
+        return NULL;
+    }
+
+    info = (SolPcmInfo*) malloc(sizeof(SolPcmInfo));
+    if (!info) {
+        ERROR0("Out of memory\n");
+        return NULL;
+    }
+    memset(info, 0, sizeof(SolPcmInfo));
+    info->frameSize = frameSize;
+    info->fd = -1;
+
+    if (isSource) {
+        openMode = O_WRONLY;
+    } else {
+        openMode = O_RDONLY;
+    }
+
+#ifndef __linux__
+    /* blackdown does not use NONBLOCK */
+    openMode |= O_NONBLOCK;
+#endif
+
+    if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
+        info->fd = open(desc.path, openMode);
+    }
+    if (info->fd < 0) {
+        ERROR1("Couldn't open audio device for mixer %d!\n", mixerIndex);
+        free(info);
+        return NULL;
+    }
+    /* set to multiple open */
+    if (ioctl(info->fd, AUDIO_MIXER_MULTIPLE_OPEN, NULL) >= 0) {
+        TRACE1("DAUDIO_Open: %s set to multiple open\n", desc.path);
+    } else {
+        ERROR1("DAUDIO_Open: ioctl AUDIO_MIXER_MULTIPLE_OPEN failed on %s!\n", desc.path);
+    }
+
+    AUDIO_INITINFO(&(info->info));
+    /* need AUDIO_GETINFO ioctl to get this to work on solaris x86  */
+    err = ioctl(info->fd, AUDIO_GETINFO, &(info->info));
+
+    /* not valid to call AUDIO_SETINFO ioctl with all the fields from AUDIO_GETINFO. */
+    AUDIO_INITINFO(&(info->info));
+
+    if (isSource) {
+        info->info.play.sample_rate = sampleRate;
+        info->info.play.precision = sampleSizeInBits;
+        info->info.play.channels = channels;
+        info->info.play.encoding = AUDIO_ENCODING_LINEAR;
+        info->info.play.buffer_size = bufferSizeInBytes;
+        info->info.play.pause = 1;
+    } else {
+        info->info.record.sample_rate = sampleRate;
+        info->info.record.precision = sampleSizeInBits;
+        info->info.record.channels = channels;
+        info->info.record.encoding = AUDIO_ENCODING_LINEAR;
+        info->info.record.buffer_size = bufferSizeInBytes;
+        info->info.record.pause = 1;
+    }
+    err = ioctl(info->fd, AUDIO_SETINFO,  &(info->info));
+    if (err < 0) {
+        ERROR0("DAUDIO_Open: could not set info!\n");
+        DAUDIO_Close((void*) info, isSource);
+        return NULL;
+    }
+    DAUDIO_Flush((void*) info, isSource);
+
+    err = ioctl(info->fd, AUDIO_GETINFO, &(info->info));
+    if (err >= 0) {
+        if (isSource) {
+            info->bufferSizeInBytes = info->info.play.buffer_size;
+        } else {
+            info->bufferSizeInBytes = info->info.record.buffer_size;
+        }
+        TRACE2("DAUDIO: buffersize in bytes: requested=%d, got %d\n",
+               (int) bufferSizeInBytes,
+               (int) info->bufferSizeInBytes);
+    } else {
+        ERROR0("DAUDIO_Open: cannot get info!\n");
+        DAUDIO_Close((void*) info, isSource);
+        return NULL;
+    }
+    TRACE0("< DAUDIO_Open: Opened device successfully.\n");
+    return (void*) info;
+}
+
+
+int DAUDIO_Start(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int err, modified;
+    audio_info_t audioInfo;
+
+    TRACE0("> DAUDIO_Start\n");
+
+    AUDIO_INITINFO(&audioInfo);
+    err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+    if (err >= 0) {
+        // unpause
+        modified = FALSE;
+        if (isSource && audioInfo.play.pause) {
+            audioInfo.play.pause = 0;
+            modified = TRUE;
+        }
+        if (!isSource && audioInfo.record.pause) {
+            audioInfo.record.pause = 0;
+            modified = TRUE;
+        }
+        if (modified) {
+            err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
+        }
+    }
+
+    TRACE1("< DAUDIO_Start %s\n", (err>=0)?"success":"error");
+    return (err >= 0)?TRUE:FALSE;
+}
+
+int DAUDIO_Stop(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int err, modified;
+    audio_info_t audioInfo;
+
+    TRACE0("> DAUDIO_Stop\n");
+
+    AUDIO_INITINFO(&audioInfo);
+    err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+    if (err >= 0) {
+        // pause
+        modified = FALSE;
+        if (isSource && !audioInfo.play.pause) {
+            audioInfo.play.pause = 1;
+            modified = TRUE;
+        }
+        if (!isSource && !audioInfo.record.pause) {
+            audioInfo.record.pause = 1;
+            modified = TRUE;
+        }
+        if (modified) {
+            err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
+        }
+    }
+
+    TRACE1("< DAUDIO_Stop %s\n", (err>=0)?"success":"error");
+    return (err >= 0)?TRUE:FALSE;
+}
+
+void DAUDIO_Close(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+
+    TRACE0("DAUDIO_Close\n");
+    if (info != NULL) {
+        if (info->fd >= 0) {
+            DAUDIO_Flush(id, isSource);
+            close(info->fd);
+        }
+        free(info);
+    }
+}
+
+#ifndef USE_TRACE
+/* close to 2^31 */
+#define POSITION_MAX 2000000000
+#else
+/* for testing */
+#define POSITION_MAX 1000000
+#endif
+
+void resetErrorFlagAndAdjustPosition(SolPcmInfo* info, int isSource, int count) {
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+    int err;
+    int offset = -1;
+    int underrun = FALSE;
+    int devBytes = 0;
+
+    if (count > 0) {
+        info->transferedBytes += count;
+
+        if (isSource) {
+            prinfo = &(audioInfo.play);
+        } else {
+            prinfo = &(audioInfo.record);
+        }
+        AUDIO_INITINFO(&audioInfo);
+        err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+        if (err >= 0) {
+            underrun = prinfo->error;
+            devBytes = prinfo->samples * info->frameSize;
+        }
+        AUDIO_INITINFO(&audioInfo);
+        if (underrun) {
+            /* if an underrun occurred, reset */
+            ERROR1("DAUDIO_Write/Read: Underrun/overflow: adjusting positionOffset by %d:\n",
+                   (devBytes - info->transferedBytes));
+            ERROR1("    devBytes from %d to 0, ", devBytes);
+            ERROR2(" positionOffset from %d to %d ",
+                   (int) info->positionOffset,
+                   (int) (info->positionOffset + info->transferedBytes));
+            ERROR1(" transferedBytes from %d to 0\n",
+                   (int) info->transferedBytes);
+            prinfo->samples = 0;
+            info->positionOffset += info->transferedBytes;
+            info->transferedBytes = 0;
+        }
+        else if (info->transferedBytes > POSITION_MAX) {
+            /* we will reset transferedBytes and
+             * the samples field in prinfo
+             */
+            offset = devBytes;
+            prinfo->samples = 0;
+        }
+        /* reset error flag */
+        prinfo->error = 0;
+
+        err = ioctl(info->fd, AUDIO_SETINFO, &audioInfo);
+        if (err >= 0) {
+            if (offset > 0) {
+                /* upon exit of AUDIO_SETINFO, the samples parameter
+                 * was set to the previous value. This is our
+                 * offset.
+                 */
+                TRACE1("Adjust samplePos: offset=%d, ", (int) offset);
+                TRACE2("transferedBytes=%d -> %d, ",
+                       (int) info->transferedBytes,
+                       (int) (info->transferedBytes - offset));
+                TRACE2("positionOffset=%d -> %d\n",
+                       (int) (info->positionOffset),
+                       (int) (((int) info->positionOffset) + offset));
+                info->transferedBytes -= offset;
+                info->positionOffset += offset;
+            }
+        } else {
+            ERROR0("DAUDIO: resetErrorFlagAndAdjustPosition ioctl failed!\n");
+        }
+    }
+}
+
+// returns -1 on error
+int DAUDIO_Write(void* id, char* data, int byteSize) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int ret = -1;
+
+    TRACE1("> DAUDIO_Write %d bytes\n", byteSize);
+    if (info!=NULL) {
+        ret = write(info->fd, data, byteSize);
+        resetErrorFlagAndAdjustPosition(info, TRUE, ret);
+        /* sets ret to -1 if buffer full, no error! */
+        if (ret < 0) {
+            ret = 0;
+        }
+    }
+    TRACE1("< DAUDIO_Write: returning %d bytes.\n", ret);
+    return ret;
+}
+
+// returns -1 on error
+int DAUDIO_Read(void* id, char* data, int byteSize) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int ret = -1;
+
+    TRACE1("> DAUDIO_Read %d bytes\n", byteSize);
+    if (info != NULL) {
+        ret = read(info->fd, data, byteSize);
+        resetErrorFlagAndAdjustPosition(info, TRUE, ret);
+        /* sets ret to -1 if buffer full, no error! */
+        if (ret < 0) {
+            ret = 0;
+        }
+    }
+    TRACE1("< DAUDIO_Read: returning %d bytes.\n", ret);
+    return ret;
+}
+
+
+int DAUDIO_GetBufferSize(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    if (info) {
+        return info->bufferSizeInBytes;
+    }
+    return 0;
+}
+
+int DAUDIO_StillDraining(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+    int ret = FALSE;
+
+    if (info!=NULL) {
+        if (isSource) {
+            prinfo = &(audioInfo.play);
+        } else {
+            prinfo = &(audioInfo.record);
+        }
+        /* check error flag */
+        AUDIO_INITINFO(&audioInfo);
+        ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+        ret = (prinfo->error != 0)?FALSE:TRUE;
+    }
+    return ret;
+}
+
+
+int getDevicePosition(SolPcmInfo* info, int isSource) {
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+    int err;
+
+    if (isSource) {
+        prinfo = &(audioInfo.play);
+    } else {
+        prinfo = &(audioInfo.record);
+    }
+    AUDIO_INITINFO(&audioInfo);
+    err = ioctl(info->fd, AUDIO_GETINFO, &audioInfo);
+    if (err >= 0) {
+        /*TRACE2("---> device paused: %d  eof=%d\n",
+               prinfo->pause, prinfo->eof);
+        */
+        return (int) (prinfo->samples * info->frameSize);
+    }
+    ERROR0("DAUDIO: getDevicePosition: ioctl failed!\n");
+    return -1;
+}
+
+int DAUDIO_Flush(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int err = -1;
+    int pos;
+
+    TRACE0("DAUDIO_Flush\n");
+    if (info) {
+        if (isSource) {
+            err = ioctl(info->fd, I_FLUSH, FLUSHW);
+        } else {
+            err = ioctl(info->fd, I_FLUSH, FLUSHR);
+        }
+        if (err >= 0) {
+            /* resets the transferedBytes parameter to
+             * the current samples count of the device
+             */
+            pos = getDevicePosition(info, isSource);
+            if (pos >= 0) {
+                info->transferedBytes = pos;
+            }
+        }
+    }
+    if (err < 0) {
+        ERROR0("ERROR in DAUDIO_Flush\n");
+    }
+    return (err < 0)?FALSE:TRUE;
+}
+
+int DAUDIO_GetAvailable(void* id, int isSource) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int ret = 0;
+    int pos;
+
+    if (info) {
+        /* unfortunately, the STREAMS architecture
+         * seems to not have a method for querying
+         * the available bytes to read/write!
+         * estimate it...
+         */
+        pos = getDevicePosition(info, isSource);
+        if (pos >= 0) {
+            if (isSource) {
+                /* we usually have written more bytes
+                 * to the queue than the device position should be
+                 */
+                ret = (info->bufferSizeInBytes) - (info->transferedBytes - pos);
+            } else {
+                /* for record, the device stream should
+                 * be usually ahead of our read actions
+                 */
+                ret = pos - info->transferedBytes;
+            }
+            if (ret > info->bufferSizeInBytes) {
+                ERROR2("DAUDIO_GetAvailable: available=%d, too big at bufferSize=%d!\n",
+                       (int) ret, (int) info->bufferSizeInBytes);
+                ERROR2("                     devicePos=%d, transferedBytes=%d\n",
+                       (int) pos, (int) info->transferedBytes);
+                ret = info->bufferSizeInBytes;
+            }
+            else if (ret < 0) {
+                ERROR1("DAUDIO_GetAvailable: available=%d, in theory not possible!\n",
+                       (int) ret);
+                ERROR2("                     devicePos=%d, transferedBytes=%d\n",
+                       (int) pos, (int) info->transferedBytes);
+                ret = 0;
+            }
+        }
+    }
+
+    TRACE1("DAUDIO_GetAvailable returns %d bytes\n", ret);
+    return ret;
+}
+
+INT64 DAUDIO_GetBytePosition(void* id, int isSource, INT64 javaBytePos) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int ret;
+    int pos;
+    INT64 result = javaBytePos;
+
+    if (info) {
+        pos = getDevicePosition(info, isSource);
+        if (pos >= 0) {
+            result = info->positionOffset + pos;
+        }
+    }
+
+    //printf("getbyteposition: javaBytePos=%d , return=%d\n", (int) javaBytePos, (int) result);
+    return result;
+}
+
+
+void DAUDIO_SetBytePosition(void* id, int isSource, INT64 javaBytePos) {
+    SolPcmInfo* info = (SolPcmInfo*) id;
+    int ret;
+    int pos;
+
+    if (info) {
+        pos = getDevicePosition(info, isSource);
+        if (pos >= 0) {
+            info->positionOffset = javaBytePos - pos;
+        }
+    }
+}
+
+int DAUDIO_RequiresServicing(void* id, int isSource) {
+    // never need servicing on Solaris
+    return FALSE;
+}
+
+void DAUDIO_Service(void* id, int isSource) {
+    // never need servicing on Solaris
+}
+
+
+#endif // USE_DAUDIO
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c	2024-08-17 18:29:44.568280652 +0200
@@ -0,0 +1,600 @@
+/*
+ * Copyright (c) 2002, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+//#define USE_TRACE
+
+#include "Ports.h"
+#include "PLATFORM_API_SolarisOS_Utils.h"
+
+#if USE_PORTS == TRUE
+
+#define MONITOR_GAIN_STRING "Monitor Gain"
+
+#define ALL_TARGET_PORT_COUNT 6
+
+// define the following to not use audio_prinfo_t.mod_ports
+#define SOLARIS7_COMPATIBLE
+
+// Solaris audio defines
+static int targetPorts[ALL_TARGET_PORT_COUNT] = {
+    AUDIO_SPEAKER,
+    AUDIO_HEADPHONE,
+    AUDIO_LINE_OUT,
+    AUDIO_AUX1_OUT,
+    AUDIO_AUX2_OUT,
+    AUDIO_SPDIF_OUT
+};
+
+static char* targetPortNames[ALL_TARGET_PORT_COUNT] = {
+    "Speaker",
+    "Headphone",
+    "Line Out",
+    "AUX1 Out",
+    "AUX2 Out",
+    "SPDIF Out"
+};
+
+// defined in Ports.h
+static int targetPortJavaSoundMapping[ALL_TARGET_PORT_COUNT] = {
+    PORT_DST_SPEAKER,
+    PORT_DST_HEADPHONE,
+    PORT_DST_LINE_OUT,
+    PORT_DST_UNKNOWN,
+    PORT_DST_UNKNOWN,
+    PORT_DST_UNKNOWN,
+};
+
+#define ALL_SOURCE_PORT_COUNT 7
+
+// Solaris audio defines
+static int sourcePorts[ALL_SOURCE_PORT_COUNT] = {
+    AUDIO_MICROPHONE,
+    AUDIO_LINE_IN,
+    AUDIO_CD,
+    AUDIO_AUX1_IN,
+    AUDIO_AUX2_IN,
+    AUDIO_SPDIF_IN,
+    AUDIO_CODEC_LOOPB_IN
+};
+
+static char* sourcePortNames[ALL_SOURCE_PORT_COUNT] = {
+    "Microphone In",
+    "Line In",
+    "Compact Disc In",
+    "AUX1 In",
+    "AUX2 In",
+    "SPDIF In",
+    "Internal Loopback"
+};
+
+// Ports.h defines
+static int sourcePortJavaSoundMapping[ALL_SOURCE_PORT_COUNT] = {
+    PORT_SRC_MICROPHONE,
+    PORT_SRC_LINE_IN,
+    PORT_SRC_COMPACT_DISC,
+    PORT_SRC_UNKNOWN,
+    PORT_SRC_UNKNOWN,
+    PORT_SRC_UNKNOWN,
+    PORT_SRC_UNKNOWN
+};
+
+struct tag_PortControlID;
+
+typedef struct tag_PortInfo {
+    int fd;                    // file descriptor of the pseudo device
+    audio_info_t audioInfo;
+    // ports
+    int targetPortCount;
+    int sourcePortCount;
+    // indexes to sourcePorts/targetPorts
+    // contains first target ports, then source ports
+    int ports[ALL_TARGET_PORT_COUNT + ALL_SOURCE_PORT_COUNT];
+    // controls
+    int maxControlCount;       // upper bound of number of controls
+    int usedControlIDs;        // number of items already filled in controlIDs
+    struct tag_PortControlID* controlIDs; // the control IDs themselves
+} PortInfo;
+
+#define PORT_CONTROL_TYPE_PLAY          0x4000000
+#define PORT_CONTROL_TYPE_RECORD        0x8000000
+#define PORT_CONTROL_TYPE_SELECT_PORT   1
+#define PORT_CONTROL_TYPE_GAIN          2
+#define PORT_CONTROL_TYPE_BALANCE       3
+#define PORT_CONTROL_TYPE_MONITOR_GAIN  10
+#define PORT_CONTROL_TYPE_OUTPUT_MUTED  11
+#define PORT_CONTROL_TYPE_PLAYRECORD_MASK PORT_CONTROL_TYPE_PLAY | PORT_CONTROL_TYPE_RECORD
+#define PORT_CONTROL_TYPE_MASK 0xFFFFFF
+
+
+typedef struct tag_PortControlID {
+    PortInfo*  portInfo;
+    INT32                 controlType;  // PORT_CONTROL_TYPE_XX
+    uint_t                port;
+} PortControlID;
+
+
+///// implemented functions of Ports.h
+
+INT32 PORT_GetPortMixerCount() {
+    return (INT32) getAudioDeviceCount();
+}
+
+
+INT32 PORT_GetPortMixerDescription(INT32 mixerIndex, PortMixerDescription* description) {
+    AudioDeviceDescription desc;
+
+    if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, TRUE)) {
+        strncpy(description->name, desc.name, PORT_STRING_LENGTH-1);
+        description->name[PORT_STRING_LENGTH-1] = 0;
+        strncpy(description->vendor, desc.vendor, PORT_STRING_LENGTH-1);
+        description->vendor[PORT_STRING_LENGTH-1] = 0;
+        strncpy(description->version, desc.version, PORT_STRING_LENGTH-1);
+        description->version[PORT_STRING_LENGTH-1] = 0;
+        /*strncpy(description->description, desc.description, PORT_STRING_LENGTH-1);*/
+        strncpy(description->description, "Solaris Ports", PORT_STRING_LENGTH-1);
+        description->description[PORT_STRING_LENGTH-1] = 0;
+        return TRUE;
+    }
+    return FALSE;
+}
+
+
+void* PORT_Open(INT32 mixerIndex) {
+    PortInfo* info = NULL;
+    int fd = -1;
+    AudioDeviceDescription desc;
+    int success = FALSE;
+
+    TRACE0("PORT_Open\n");
+    if (getAudioDeviceDescriptionByIndex(mixerIndex, &desc, FALSE)) {
+        fd = open(desc.pathctl, O_RDWR);
+    }
+    if (fd < 0) {
+        ERROR1("Couldn't open audio device ctl for device %d!\n", mixerIndex);
+        return NULL;
+    }
+
+    info = (PortInfo*) malloc(sizeof(PortInfo));
+    if (info != NULL) {
+        memset(info, 0, sizeof(PortInfo));
+        info->fd = fd;
+        success = TRUE;
+    }
+    if (!success) {
+        if (fd >= 0) {
+            close(fd);
+        }
+        PORT_Close((void*) info);
+        info = NULL;
+    }
+    return info;
+}
+
+void PORT_Close(void* id) {
+    TRACE0("PORT_Close\n");
+    if (id != NULL) {
+        PortInfo* info = (PortInfo*) id;
+        if (info->fd >= 0) {
+            close(info->fd);
+            info->fd = -1;
+        }
+        if (info->controlIDs) {
+            free(info->controlIDs);
+            info->controlIDs = NULL;
+        }
+        free(info);
+    }
+}
+
+
+
+INT32 PORT_GetPortCount(void* id) {
+    int ret = 0;
+    PortInfo* info = (PortInfo*) id;
+    if (info != NULL) {
+        if (!info->targetPortCount && !info->sourcePortCount) {
+            int i;
+            AUDIO_INITINFO(&info->audioInfo);
+            if (ioctl(info->fd, AUDIO_GETINFO, &info->audioInfo) >= 0) {
+                for (i = 0; i < ALL_TARGET_PORT_COUNT; i++) {
+                    if (info->audioInfo.play.avail_ports & targetPorts[i]) {
+                        info->ports[info->targetPortCount] = i;
+                        info->targetPortCount++;
+                    }
+#ifdef SOLARIS7_COMPATIBLE
+                    TRACE3("Target %d %s: avail=%d\n", i, targetPortNames[i],
+                           info->audioInfo.play.avail_ports & targetPorts[i]);
+#else
+                    TRACE4("Target %d %s: avail=%d  mod=%d\n", i, targetPortNames[i],
+                           info->audioInfo.play.avail_ports & targetPorts[i],
+                           info->audioInfo.play.mod_ports & targetPorts[i]);
+#endif
+                }
+                for (i = 0; i < ALL_SOURCE_PORT_COUNT; i++) {
+                    if (info->audioInfo.record.avail_ports & sourcePorts[i]) {
+                        info->ports[info->targetPortCount + info->sourcePortCount] = i;
+                        info->sourcePortCount++;
+                    }
+#ifdef SOLARIS7_COMPATIBLE
+                    TRACE3("Source %d %s: avail=%d\n", i, sourcePortNames[i],
+                           info->audioInfo.record.avail_ports & sourcePorts[i]);
+#else
+                    TRACE4("Source %d %s: avail=%d  mod=%d\n", i, sourcePortNames[i],
+                           info->audioInfo.record.avail_ports & sourcePorts[i],
+                           info->audioInfo.record.mod_ports & sourcePorts[i]);
+#endif
+                }
+            }
+        }
+        ret = info->targetPortCount + info->sourcePortCount;
+    }
+    return ret;
+}
+
+int isSourcePort(PortInfo* info, INT32 portIndex) {
+    return (portIndex >= info->targetPortCount);
+}
+
+INT32 PORT_GetPortType(void* id, INT32 portIndex) {
+    PortInfo* info = (PortInfo*) id;
+    if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
+        if (isSourcePort(info, portIndex)) {
+            return sourcePortJavaSoundMapping[info->ports[portIndex]];
+        } else {
+            return targetPortJavaSoundMapping[info->ports[portIndex]];
+        }
+    }
+    return 0;
+}
+
+// pre-condition: portIndex must have been verified!
+char* getPortName(PortInfo* info, INT32 portIndex) {
+    char* ret = NULL;
+
+    if (isSourcePort(info, portIndex)) {
+        ret = sourcePortNames[info->ports[portIndex]];
+    } else {
+        ret = targetPortNames[info->ports[portIndex]];
+    }
+    return ret;
+}
+
+INT32 PORT_GetPortName(void* id, INT32 portIndex, char* name, INT32 len) {
+    PortInfo* info = (PortInfo*) id;
+    char* n;
+
+    if ((portIndex >= 0) && (portIndex < PORT_GetPortCount(id))) {
+        n = getPortName(info, portIndex);
+        if (n) {
+            strncpy(name, n, len-1);
+            name[len-1] = 0;
+            return TRUE;
+        }
+    }
+    return FALSE;
+}
+
+void createPortControl(PortInfo* info, PortControlCreator* creator, INT32 portIndex,
+                       INT32 type, void** controlObjects, int* controlCount) {
+    PortControlID* controlID;
+    void* newControl = NULL;
+    int controlIndex;
+    char* jsType = NULL;
+    int isBoolean = FALSE;
+
+    TRACE0(">createPortControl\n");
+
+    // fill the ControlID structure and add this control
+    if (info->usedControlIDs >= info->maxControlCount) {
+        ERROR1("not enough free controlIDs !! maxControlIDs = %d\n", info->maxControlCount);
+        return;
+    }
+    controlID = &(info->controlIDs[info->usedControlIDs]);
+    controlID->portInfo = info;
+    controlID->controlType = type;
+    controlIndex = info->ports[portIndex];
+    if (isSourcePort(info, portIndex)) {
+        controlID->port = sourcePorts[controlIndex];
+    } else {
+        controlID->port = targetPorts[controlIndex];
+    }
+    switch (type & PORT_CONTROL_TYPE_MASK) {
+    case PORT_CONTROL_TYPE_SELECT_PORT:
+        jsType = CONTROL_TYPE_SELECT; isBoolean = TRUE; break;
+    case PORT_CONTROL_TYPE_GAIN:
+        jsType = CONTROL_TYPE_VOLUME;  break;
+    case PORT_CONTROL_TYPE_BALANCE:
+        jsType = CONTROL_TYPE_BALANCE; break;
+    case PORT_CONTROL_TYPE_MONITOR_GAIN:
+        jsType = CONTROL_TYPE_VOLUME; break;
+    case PORT_CONTROL_TYPE_OUTPUT_MUTED:
+        jsType = CONTROL_TYPE_MUTE; isBoolean = TRUE; break;
+    }
+    if (isBoolean) {
+        TRACE0(" PORT_CONTROL_TYPE_BOOLEAN\n");
+        newControl = (creator->newBooleanControl)(creator, controlID, jsType);
+    }
+    else if (jsType == CONTROL_TYPE_BALANCE) {
+        TRACE0(" PORT_CONTROL_TYPE_BALANCE\n");
+        newControl = (creator->newFloatControl)(creator, controlID, jsType,
+                                                -1.0f, 1.0f, 2.0f / 65.0f, "");
+    } else {
+        TRACE0(" PORT_CONTROL_TYPE_FLOAT\n");
+        newControl = (creator->newFloatControl)(creator, controlID, jsType,
+                                                0.0f, 1.0f, 1.0f / 256.0f, "");
+    }
+    if (newControl) {
+        controlObjects[*controlCount] = newControl;
+        (*controlCount)++;
+        info->usedControlIDs++;
+    }
+    TRACE0("<createPortControl\n");
+}
+
+
+void addCompoundControl(PortInfo* info, PortControlCreator* creator, char* name, void** controlObjects, int* controlCount) {
+    void* compControl;
+
+    TRACE1(">addCompoundControl %d controls\n", *controlCount);
+    if (*controlCount) {
+        // create compound control and add it to the vector
+        compControl = (creator->newCompoundControl)(creator, name, controlObjects, *controlCount);
+        if (compControl) {
+            TRACE1(" addCompoundControl: calling addControl %p\n", compControl);
+            (creator->addControl)(creator, compControl);
+        }
+        *controlCount = 0;
+    }
+    TRACE0("<addCompoundControl\n");
+}
+
+void addAllControls(PortInfo* info, PortControlCreator* creator, void** controlObjects, int* controlCount) {
+    int i = 0;
+
+    TRACE0(">addAllControl\n");
+    // go through all controls and add them to the vector
+    for (i = 0; i < *controlCount; i++) {
+        (creator->addControl)(creator, controlObjects[i]);
+    }
+    *controlCount = 0;
+    TRACE0("<addAllControl\n");
+}
+
+void PORT_GetControls(void* id, INT32 portIndex, PortControlCreator* creator) {
+    PortInfo* info = (PortInfo*) id;
+    int portCount = PORT_GetPortCount(id);
+    void* controls[4];
+    int controlCount = 0;
+    INT32 type;
+    int selectable = 1;
+    memset(controls, 0, sizeof(controls));
+
+    TRACE4(">PORT_GetControls(id=%p, portIndex=%d). controlIDs=%p, maxControlCount=%d\n",
+           id, portIndex, info->controlIDs, info->maxControlCount);
+    if ((portIndex >= 0) && (portIndex < portCount)) {
+        // if the memory isn't reserved for the control structures, allocate it
+        if (!info->controlIDs) {
+            int maxCount = 0;
+            TRACE0("getControl: allocate mem\n");
+            // get a maximum number of controls:
+            // each port has a select, balance, and volume control.
+            maxCount = 3 * portCount;
+            // then there is monitorGain and outputMuted
+            maxCount += (2 * info->targetPortCount);
+            info->maxControlCount = maxCount;
+            info->controlIDs = (PortControlID*) malloc(sizeof(PortControlID) * maxCount);
+        }
+        if (!isSourcePort(info, portIndex)) {
+            type = PORT_CONTROL_TYPE_PLAY;
+            // add master mute control
+            createPortControl(info, creator, portIndex,
+                              type | PORT_CONTROL_TYPE_OUTPUT_MUTED,
+                              controls, &controlCount);
+            addAllControls(info, creator, controls, &controlCount);
+#ifdef SOLARIS7_COMPATIBLE
+            selectable = info->audioInfo.play.avail_ports & targetPorts[info->ports[portIndex]];
+#else
+            selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]];
+#endif
+        } else {
+            type = PORT_CONTROL_TYPE_RECORD;
+#ifdef SOLARIS7_COMPATIBLE
+            selectable = info->audioInfo.record.avail_ports & sourcePorts[info->ports[portIndex]];
+#else
+            selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]];
+#endif
+        }
+        // add a mixer strip with volume, ...
+        createPortControl(info, creator, portIndex,
+                          type | PORT_CONTROL_TYPE_GAIN,
+                          controls, &controlCount);
+        // ... balance, ...
+        createPortControl(info, creator, portIndex,
+                          type | PORT_CONTROL_TYPE_BALANCE,
+                          controls, &controlCount);
+        // ... and select control (if not always on)...
+        if (selectable) {
+            createPortControl(info, creator, portIndex,
+                              type | PORT_CONTROL_TYPE_SELECT_PORT,
+                              controls, &controlCount);
+        }
+        // ... packaged in a compound control.
+        addCompoundControl(info, creator, getPortName(info, portIndex), controls, &controlCount);
+
+        if (type == PORT_CONTROL_TYPE_PLAY) {
+            // add a single strip for source ports with monitor gain
+            createPortControl(info, creator, portIndex,
+                              type | PORT_CONTROL_TYPE_MONITOR_GAIN,
+                              controls, &controlCount);
+            // also in a compound control
+            addCompoundControl(info, creator, MONITOR_GAIN_STRING, controls, &controlCount);
+        }
+    }
+    TRACE0("< PORT_getControls\n");
+}
+
+INT32 PORT_GetIntValue(void* controlIDV) {
+    PortControlID* controlID = (PortControlID*) controlIDV;
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+
+    AUDIO_INITINFO(&audioInfo);
+    if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
+        if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
+            prinfo = &(audioInfo.play);
+        } else {
+            prinfo = &(audioInfo.record);
+        }
+        switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
+        case PORT_CONTROL_TYPE_SELECT_PORT:
+            return (prinfo->port & controlID->port)?TRUE:FALSE;
+        case PORT_CONTROL_TYPE_OUTPUT_MUTED:
+            return (audioInfo.output_muted)?TRUE:FALSE;
+        default:
+            ERROR1("PORT_GetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
+        }
+    }
+    ERROR0("PORT_GetIntValue: Could not ioctl!\n");
+    return 0;
+}
+
+void PORT_SetIntValue(void* controlIDV, INT32 value) {
+    PortControlID* controlID = (PortControlID*) controlIDV;
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+    int setPort;
+
+    if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
+        prinfo = &(audioInfo.play);
+    } else {
+        prinfo = &(audioInfo.record);
+    }
+    switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
+    case PORT_CONTROL_TYPE_SELECT_PORT:
+        // first try to just add this port. if that fails, set ONLY to this port.
+        AUDIO_INITINFO(&audioInfo);
+        if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
+            if (value) {
+                setPort = (prinfo->port | controlID->port);
+            } else {
+                setPort = (prinfo->port - controlID->port);
+            }
+            AUDIO_INITINFO(&audioInfo);
+            prinfo->port = setPort;
+            if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
+                // didn't work. Either this line doesn't support to select several
+                // ports at once (e.g. record), or a real error
+                if (value) {
+                    // set to ONLY this port (and disable any other currently selected ports)
+                    AUDIO_INITINFO(&audioInfo);
+                    prinfo->port = controlID->port;
+                    if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
+                        ERROR2("Error setting output select port %d to port %d!\n", controlID->port, controlID->port);
+                    }
+                } else {
+                    // assume it's an error
+                    ERROR2("Error setting output select port %d to port %d!\n", controlID->port, setPort);
+                }
+            }
+            break;
+        case PORT_CONTROL_TYPE_OUTPUT_MUTED:
+            AUDIO_INITINFO(&audioInfo);
+            audioInfo.output_muted = (value?TRUE:FALSE);
+            if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
+                ERROR2("Error setting output muted on port %d to %d!\n", controlID->port, value);
+            }
+            break;
+        default:
+            ERROR1("PORT_SetIntValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
+        }
+    }
+}
+
+float PORT_GetFloatValue(void* controlIDV) {
+    PortControlID* controlID = (PortControlID*) controlIDV;
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+
+    AUDIO_INITINFO(&audioInfo);
+    if (ioctl(controlID->portInfo->fd, AUDIO_GETINFO, &audioInfo) >= 0) {
+        if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
+            prinfo = &(audioInfo.play);
+        } else {
+            prinfo = &(audioInfo.record);
+        }
+        switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
+        case PORT_CONTROL_TYPE_GAIN:
+            return ((float) (prinfo->gain - AUDIO_MIN_GAIN))
+                / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
+        case PORT_CONTROL_TYPE_BALANCE:
+            return ((float) ((prinfo->balance - AUDIO_LEFT_BALANCE - AUDIO_MID_BALANCE) << 1))
+                / ((float) (AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE));
+        case PORT_CONTROL_TYPE_MONITOR_GAIN:
+            return ((float) (audioInfo.monitor_gain - AUDIO_MIN_GAIN))
+                / ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN));
+        default:
+            ERROR1("PORT_GetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
+        }
+    }
+    ERROR0("PORT_GetFloatValue: Could not ioctl!\n");
+    return 0.0f;
+}
+
+void PORT_SetFloatValue(void* controlIDV, float value) {
+    PortControlID* controlID = (PortControlID*) controlIDV;
+    audio_info_t audioInfo;
+    audio_prinfo_t* prinfo;
+
+    AUDIO_INITINFO(&audioInfo);
+
+    if (controlID->controlType & PORT_CONTROL_TYPE_PLAY) {
+        prinfo = &(audioInfo.play);
+    } else {
+        prinfo = &(audioInfo.record);
+    }
+    switch (controlID->controlType & PORT_CONTROL_TYPE_MASK) {
+    case PORT_CONTROL_TYPE_GAIN:
+        prinfo->gain = AUDIO_MIN_GAIN
+            + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f);
+        break;
+    case PORT_CONTROL_TYPE_BALANCE:
+        prinfo->balance =  AUDIO_LEFT_BALANCE + AUDIO_MID_BALANCE
+            + ((int) (value * ((float) ((AUDIO_RIGHT_BALANCE - AUDIO_LEFT_BALANCE) >> 1))) + 0.5f);
+        break;
+    case PORT_CONTROL_TYPE_MONITOR_GAIN:
+        audioInfo.monitor_gain = AUDIO_MIN_GAIN
+            + (int) ((value * ((float) (AUDIO_MAX_GAIN - AUDIO_MIN_GAIN))) + 0.5f);
+        break;
+    default:
+        ERROR1("PORT_SetFloatValue: Wrong type %d !\n", controlID->controlType & PORT_CONTROL_TYPE_MASK);
+        return;
+    }
+    if (ioctl(controlID->portInfo->fd, AUDIO_SETINFO, &audioInfo) < 0) {
+        ERROR0("PORT_SetFloatValue: Could not ioctl!\n");
+    }
+}
+
+#endif // USE_PORTS
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c	2024-08-17 18:29:44.568675138 +0200
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2002, 2007, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#define USE_ERROR
+#define USE_TRACE
+
+#include "PLATFORM_API_SolarisOS_Utils.h"
+
+#define MAX_AUDIO_DEVICES 20
+
+// not thread safe...
+static AudioDevicePath globalADPaths[MAX_AUDIO_DEVICES];
+static int globalADCount = -1;
+static int globalADCacheTime = -1;
+/* how many seconds do we cache devices */
+#define AD_CACHE_TIME 30
+
+// return seconds
+long getTimeInSeconds() {
+    struct timeval tv;
+    gettimeofday(&tv, NULL);
+    return tv.tv_sec;
+}
+
+
+int getAudioDeviceCount() {
+    int count = MAX_AUDIO_DEVICES;
+
+    getAudioDevices(globalADPaths, &count);
+    return count;
+}
+
+/* returns TRUE if the path exists at all */
+int addAudioDevice(char* path, AudioDevicePath* adPath, int* count) {
+    int i;
+    int found = 0;
+    int fileExists = 0;
+    // not thread safe...
+    static struct stat statBuf;
+
+    // get stats on the file
+    if (stat(path, &statBuf) == 0) {
+        // file exists.
+        fileExists = 1;
+        // If it is not yet in the adPath array, add it to the array
+        for (i = 0; i < *count; i++) {
+            if (adPath[i].st_ino == statBuf.st_ino
+                && adPath[i].st_dev == statBuf.st_dev) {
+                found = 1;
+                break;
+            }
+        }
+        if (!found) {
+            adPath[*count].st_ino = statBuf.st_ino;
+            adPath[*count].st_dev = statBuf.st_dev;
+            strncpy(adPath[*count].path, path, MAX_NAME_LENGTH);
+            adPath[*count].path[MAX_NAME_LENGTH - 1] = 0;
+            (*count)++;
+            TRACE1("Added audio device %s\n", path);
+        }
+    }
+    return fileExists;
+}
+
+
+void getAudioDevices(AudioDevicePath* adPath, int* count) {
+    int maxCount = *count;
+    char* audiodev;
+    char devsound[15];
+    int i;
+    long timeInSeconds = getTimeInSeconds();
+
+    if (globalADCount < 0
+        || (getTimeInSeconds() - globalADCacheTime) > AD_CACHE_TIME
+        || (adPath != globalADPaths)) {
+        *count = 0;
+        // first device, if set, is AUDIODEV variable
+        audiodev = getenv("AUDIODEV");
+        if (audiodev != NULL && audiodev[0] != 0) {
+            addAudioDevice(audiodev, adPath, count);
+        }
+        // then try /dev/audio
+        addAudioDevice("/dev/audio", adPath, count);
+        // then go through all of the /dev/sound/? devices
+        for (i = 0; i < 100; i++) {
+            sprintf(devsound, "/dev/sound/%d", i);
+            if (!addAudioDevice(devsound, adPath, count)) {
+                break;
+            }
+        }
+        if (adPath == globalADPaths) {
+            /* commit cache */
+            globalADCount = *count;
+            /* set cache time */
+            globalADCacheTime = timeInSeconds;
+        }
+    } else {
+        /* return cache */
+        *count = globalADCount;
+    }
+    // that's it
+}
+
+int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames) {
+    int count = MAX_AUDIO_DEVICES;
+    int ret = 0;
+
+    getAudioDevices(globalADPaths, &count);
+    if (index>=0 && index < count) {
+        ret = getAudioDeviceDescription(globalADPaths[index].path, adDesc, getNames);
+    }
+    return ret;
+}
+
+int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames) {
+    int fd;
+    int mixerMode;
+    int len;
+    audio_info_t info;
+    audio_device_t deviceInfo;
+
+    strncpy(adDesc->path, path, MAX_NAME_LENGTH);
+    adDesc->path[MAX_NAME_LENGTH] = 0;
+    strcpy(adDesc->pathctl, adDesc->path);
+    strcat(adDesc->pathctl, "ctl");
+    strcpy(adDesc->name, adDesc->path);
+    adDesc->vendor[0] = 0;
+    adDesc->version[0] = 0;
+    adDesc->description[0] = 0;
+    adDesc->maxSimulLines = 1;
+
+    // try to open the pseudo device and get more information
+    fd = open(adDesc->pathctl, O_WRONLY | O_NONBLOCK);
+    if (fd >= 0) {
+        close(fd);
+        if (getNames) {
+            fd = open(adDesc->pathctl, O_RDONLY);
+            if (fd >= 0) {
+                if (ioctl(fd, AUDIO_GETDEV, &deviceInfo) >= 0) {
+                    strncpy(adDesc->vendor, deviceInfo.name, MAX_AUDIO_DEV_LEN);
+                    adDesc->vendor[MAX_AUDIO_DEV_LEN] = 0;
+                    strncpy(adDesc->version, deviceInfo.version, MAX_AUDIO_DEV_LEN);
+                    adDesc->version[MAX_AUDIO_DEV_LEN] = 0;
+                    /* add config string to the dev name
+                     * creates a string like "/dev/audio (onboard1)"
+                     */
+                    len = strlen(adDesc->name) + 1;
+                    if (MAX_NAME_LENGTH - len > 3) {
+                        strcat(adDesc->name, " (");
+                        strncat(adDesc->name, deviceInfo.config, MAX_NAME_LENGTH - len);
+                        strcat(adDesc->name, ")");
+                    }
+                    adDesc->name[MAX_NAME_LENGTH-1] = 0;
+                }
+                if (ioctl(fd, AUDIO_MIXERCTL_GET_MODE, &mixerMode) >= 0) {
+                    if (mixerMode == AM_MIXER_MODE) {
+                        TRACE1(" getAudioDeviceDescription: %s is in mixer mode\n", adDesc->path);
+                        adDesc->maxSimulLines = -1;
+                    }
+                } else {
+                    ERROR1("ioctl AUDIO_MIXERCTL_GET_MODE failed on %s!\n", adDesc->path);
+                }
+                close(fd);
+            } else {
+                ERROR1("could not open %s!\n", adDesc->pathctl);
+            }
+        }
+        return 1;
+    }
+    return 0;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h	2024-08-17 18:29:44.569009396 +0200
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2002, 2013, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <Utilities.h>
+#include <string.h>
+#include <stdlib.h>
+#include <fcntl.h>
+/* does not work on Solaris 2.7 */
+#include <sys/audio.h>
+#include <sys/mixer.h>
+#include <sys/types.h>
+#ifndef __linux__
+#include <stropts.h>
+#endif
+#include <sys/conf.h>
+#include <sys/stat.h>
+#include <unistd.h>
+
+#ifndef PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED
+#define PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED
+
+/* defines for Solaris 2.7
+   #ifndef AUDIO_AUX1_OUT
+   #define AUDIO_AUX1_OUT   (0x08)  // output to aux1 out
+   #define AUDIO_AUX2_OUT   (0x10)  // output to aux2 out
+   #define AUDIO_SPDIF_OUT  (0x20)  // output to SPDIF port
+   #define AUDIO_AUX1_IN    (0x08)    // input from aux1 in
+   #define AUDIO_AUX2_IN    (0x10)    // input from aux2 in
+   #define AUDIO_SPDIF_IN   (0x20)    // input from SPDIF port
+   #endif
+*/
+
+/* input from Codec inter. loopback */
+#ifndef AUDIO_CODEC_LOOPB_IN
+#define AUDIO_CODEC_LOOPB_IN       (0x40)
+#endif
+
+
+#define MAX_NAME_LENGTH 300
+
+typedef struct tag_AudioDevicePath {
+    char path[MAX_NAME_LENGTH];
+    ino_t st_ino; // inode number to detect duplicate devices
+    dev_t st_dev; // device ID to detect duplicate audio devices
+} AudioDevicePath;
+
+typedef struct tag_AudioDeviceDescription {
+    INT32 maxSimulLines;
+    char path[MAX_NAME_LENGTH+1];
+    char pathctl[MAX_NAME_LENGTH+4];
+    char name[MAX_NAME_LENGTH+1];
+    char vendor[MAX_NAME_LENGTH+1];
+    char version[MAX_NAME_LENGTH+1];
+    char description[MAX_NAME_LENGTH+1];
+} AudioDeviceDescription;
+
+int getAudioDeviceCount();
+
+/*
+ * adPath is an array of AudioDevicePath structures
+ * count contains initially the number of elements in adPath
+ *       and will be set to the returned number of paths.
+ */
+void getAudioDevices(AudioDevicePath* adPath, int* count);
+
+/*
+ * fills adDesc from the audio device given in path
+ * returns 0 if an error occurred
+ * if getNames is 0, only path and pathctl are filled
+ */
+int getAudioDeviceDescription(char* path, AudioDeviceDescription* adDesc, int getNames);
+int getAudioDeviceDescriptionByIndex(int index, AudioDeviceDescription* adDesc, int getNames);
+
+
+#endif // PLATFORM_API_SOLARISOS_UTILS_H_INCLUDED
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/awt/X11FontManager.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/awt/X11FontManager.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	2024-08-17 18:29:44.513036723 +0200
@@ -696,7 +696,8 @@
          * and do the best we can.
          */
         FontConfiguration mFontConfig = new MFontConfiguration(this);
-        if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile())) {
+        if ((FontUtilities.isLinux && !mFontConfig.foundOsSpecificFile()) ||
+            (FontUtilities.isSolaris && !mFontConfig.fontFilesArePresent())) {
             FcFontConfiguration fcFontConfig =
                 new FcFontConfiguration(this);
             if (fcFontConfig.init()) {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/awt/X11InputMethodBase.java	2024-08-17 18:29:44.513604102 +0200
@@ -674,6 +674,36 @@
             if (imIndex != -1) {
                 imInfo = xmodifiers.substring(imIndex + 4);
             }
+        } else if (System.getProperty("os.name").startsWith("SunOS")) {
+            File dtprofile = new File(System.getProperty("user.home") +
+                                      "/.dtprofile");
+            String languageEngineInfo = null;
+            try {
+                BufferedReader br = new BufferedReader(new FileReader(dtprofile));
+                String line = null;
+
+                while ( languageEngineInfo == null && (line = br.readLine()) != null) {
+                    if (line.contains("atok") || line.contains("wnn")) {
+                        StringTokenizer tokens =  new StringTokenizer(line);
+                        while (tokens.hasMoreTokens()) {
+                            String token = tokens.nextToken();
+                            if (Pattern.matches("atok.*setup", token) ||
+                                Pattern.matches("wnn.*setup", token)){
+                                languageEngineInfo = token.substring(0, token.indexOf("setup"));
+                                break;
+                            }
+                        }
+                    }
+                }
+
+                br.close();
+            } catch(IOException ioex) {
+                // Since this method is provided for internal testing only,
+                // we dump the stack trace for the ease of debugging.
+                ioex.printStackTrace();
+            }
+
+            imInfo = "htt " + languageEngineInfo;
         }
 
         return imInfo;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java	2024-08-17 18:29:44.514242456 +0200
@@ -70,7 +70,59 @@
      */
     protected void initReorderMap() {
         reorderMap = new HashMap<>();
+        if (osName == null) {  /* null means SunOS */
+            initReorderMapForSolaris();
+        } else {
+            initReorderMapForLinux();
+        }
+    }
+
+    private void initReorderMapForSolaris() {
+        /* Don't create a no-op entry, so we can optimize this case
+         * i.e. we don't need to do anything so can avoid slower paths in
+         * the code.
+         */
+//      reorderMap.put("UTF-8", "latin-1");
+        reorderMap.put("UTF-8.hi", "devanagari"); // NB is in Lucida.
+        reorderMap.put("UTF-8.ja",
+                       split("japanese-x0201,japanese-x0208,japanese-x0212"));
+        reorderMap.put("UTF-8.ko", "korean-johab");
+        reorderMap.put("UTF-8.th", "thai");
+        reorderMap.put("UTF-8.zh.TW", "chinese-big5");
+        reorderMap.put("UTF-8.zh.HK", split("chinese-big5,chinese-hkscs"));
+        reorderMap.put("UTF-8.zh.CN",
+                       split("chinese-gb18030-0,chinese-gb18030-1"));
+        reorderMap.put("UTF-8.zh",
+                       split("chinese-big5,chinese-hkscs,chinese-gb18030-0,chinese-gb18030-1"));
+        reorderMap.put("Big5", "chinese-big5");
+        reorderMap.put("Big5-HKSCS", split("chinese-big5,chinese-hkscs"));
+        reorderMap.put("GB2312", split("chinese-gbk,chinese-gb2312"));
+        reorderMap.put("x-EUC-TW",
+            split("chinese-cns11643-1,chinese-cns11643-2,chinese-cns11643-3"));
+        reorderMap.put("GBK", "chinese-gbk");
+        reorderMap.put("GB18030",split("chinese-gb18030-0,chinese-gb18030-1"));
+
+        reorderMap.put("TIS-620", "thai");
+        reorderMap.put("x-PCK",
+                       split("japanese-x0201,japanese-x0208,japanese-x0212"));
+        reorderMap.put("x-eucJP-Open",
+                       split("japanese-x0201,japanese-x0208,japanese-x0212"));
+        reorderMap.put("EUC-KR", "korean");
+        /* Don't create a no-op entry, so we can optimize this case */
+//      reorderMap.put("ISO-8859-1", "latin-1");
+        reorderMap.put("ISO-8859-2", "latin-2");
+        reorderMap.put("ISO-8859-5", "cyrillic-iso8859-5");
+        reorderMap.put("windows-1251", "cyrillic-cp1251");
+        reorderMap.put("KOI8-R", "cyrillic-koi8-r");
+        reorderMap.put("ISO-8859-6", "arabic");
+        reorderMap.put("ISO-8859-7", "greek");
+        reorderMap.put("ISO-8859-8", "hebrew");
+        reorderMap.put("ISO-8859-9", "latin-5");
+        reorderMap.put("ISO-8859-13", "latin-7");
+        reorderMap.put("ISO-8859-15", "latin-9");
+    }
 
+    private void initReorderMapForLinux() {
         reorderMap.put("UTF-8.ja.JP", "japanese-iso10646");
         reorderMap.put("UTF-8.ko.KR", "korean-iso10646");
         reorderMap.put("UTF-8.zh.TW", "chinese-tw-iso10646");
@@ -81,7 +133,12 @@
         reorderMap.put("GB2312", "chinese-gb18030");
         reorderMap.put("Big5", "chinese-big5");
         reorderMap.put("EUC-KR", "korean");
-        reorderMap.put("GB18030", "chinese-gb18030");
+        if (osName.equals("Sun")){
+            reorderMap.put("GB18030", "chinese-cn-iso10646");
+        }
+        else {
+            reorderMap.put("GB18030", "chinese-gb18030");
+        }
     }
 
     /**
@@ -90,7 +147,10 @@
     protected void setOsNameAndVersion(){
         super.setOsNameAndVersion();
 
-        if (osName.equals("Linux")) {
+        if (osName.equals("SunOS")) {
+            //don't care os name on Solaris
+            osName = null;
+        } else if (osName.equals("Linux")) {
             try {
                 File f;
                 if ((f = new File("/etc/fedora-release")).canRead()) {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java	2024-08-17 18:29:44.515070613 +0200
@@ -152,6 +152,10 @@
         return osname.startsWith("Mac");
     }
 
+    static boolean isSysV() {
+        return osname.equals("SunOS");
+    }
+
     static boolean isLinux() {
         return (osname.equals("Linux"));
     }
@@ -303,7 +307,7 @@
                 }
             }
         } else {
-            if (isMac()) {
+            if (isMac() || isSysV()) {
                 printers = getAllPrinterNamesSysV();
             } else if (isAIX()) {
                 printers = getAllPrinterNamesAIX();
@@ -487,7 +491,7 @@
         }
         /* fallback if nothing not having a printer at this point */
         PrintService printer = null;
-        if (isMac()) {
+        if (isMac() || isSysV()) {
             printer = getNamedPrinterNameSysV(name);
         } else if (isAIX()) {
             printer = getNamedPrinterNameAIX(name);
@@ -658,7 +662,7 @@
                 psuri = printerInfo[1];
             }
         } else {
-            if (isMac()) {
+            if (isMac() || isSysV()) {
                 defaultPrinter = getDefaultPrinterNameSysV();
             } else if (isAIX()) {
                 defaultPrinter = getDefaultPrinterNameAIX();
@@ -878,7 +882,7 @@
         ArrayList<String> results = null;
         try {
             final String[] cmd = new String[3];
-            if (isAIX()) {
+            if (isSysV() || isAIX()) {
                 cmd[0] = "/usr/bin/sh";
                 cmd[1] = "-c";
                 cmd[2] = "env LC_ALL=C " + command;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java	2024-08-17 18:29:44.515738617 +0200
@@ -881,25 +881,51 @@
                         isAttributeCategorySupported(JobSheets.class)) {
             ncomps+=1;
         }
-        execCmd = new String[ncomps];
-        execCmd[n++] = "/usr/bin/lpr";
-        if ((pFlags & PRINTER) != 0) {
-            execCmd[n++] = "-P" + printer;
-        }
-        if ((pFlags & JOBTITLE) != 0) {
-            execCmd[n++] = "-J "  + jobTitle;
-        }
-        if ((pFlags & COPIES) != 0) {
-            execCmd[n++] = "-#" + copies;
-        }
-        if ((pFlags & NOSHEET) != 0) {
-            execCmd[n++] = "-h";
-        } else if (getPrintService().
-                   isAttributeCategorySupported(JobSheets.class)) {
-            execCmd[n++] = "-o job-sheets=standard";
-        }
-        if ((pFlags & OPTIONS) != 0) {
-            execCmd[n++] = "-o" + options;
+        if (PrintServiceLookupProvider.osname.equals("SunOS")) {
+            ncomps+=1; // lp uses 1 more arg than lpr (make a copy)
+            execCmd = new String[ncomps];
+            execCmd[n++] = "/usr/bin/lp";
+            execCmd[n++] = "-c";           // make a copy of the spool file
+            if ((pFlags & PRINTER) != 0) {
+                execCmd[n++] = "-d" + printer;
+            }
+            if ((pFlags & JOBTITLE) != 0) {
+                String quoteChar = "\"";
+                execCmd[n++] = "-t "  + quoteChar+jobTitle+quoteChar;
+            }
+            if ((pFlags & COPIES) != 0) {
+                execCmd[n++] = "-n " + copies;
+            }
+            if ((pFlags & NOSHEET) != 0) {
+                execCmd[n++] = "-o nobanner";
+            } else if (getPrintService().
+                        isAttributeCategorySupported(JobSheets.class)) {
+                execCmd[n++] = "-o job-sheets=standard";
+            }
+            if ((pFlags & OPTIONS) != 0) {
+                execCmd[n++] = "-o " + options;
+            }
+        } else {
+            execCmd = new String[ncomps];
+            execCmd[n++] = "/usr/bin/lpr";
+            if ((pFlags & PRINTER) != 0) {
+                execCmd[n++] = "-P" + printer;
+            }
+            if ((pFlags & JOBTITLE) != 0) {
+                execCmd[n++] = "-J "  + jobTitle;
+            }
+            if ((pFlags & COPIES) != 0) {
+                execCmd[n++] = "-#" + copies;
+            }
+            if ((pFlags & NOSHEET) != 0) {
+                execCmd[n++] = "-h";
+            } else if (getPrintService().
+                        isAttributeCategorySupported(JobSheets.class)) {
+                execCmd[n++] = "-o job-sheets=standard";
+            }
+            if ((pFlags & OPTIONS) != 0) {
+                execCmd[n++] = "-o" + options;
+            }
         }
         execCmd[n++] = spoolFile;
         if (IPPPrintService.debugPrint) {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintService.java jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/print/UnixPrintService.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/classes/sun/print/UnixPrintService.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/classes/sun/print/UnixPrintService.java	2024-08-17 18:29:44.516591847 +0200
@@ -220,6 +220,31 @@
         return name;
     }
 
+    private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsSysV() {
+        String command = "/usr/bin/lpstat -a " + printer;
+        String[] results= PrintServiceLookupProvider.execCmd(command);
+
+        if (results != null && results.length > 0) {
+            if (results[0].startsWith(printer + " accepting requests")) {
+                return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
+            }
+            else if (results[0].startsWith(printer)) {
+                /* As well as "myprinter accepting requests", look for
+                 * "myprinter@somehost accepting requests".
+                 */
+                int index = printer.length();
+                String str = results[0];
+                if (str.length() > index &&
+                    str.charAt(index) == '@' &&
+                    str.indexOf(" accepting requests", index) > 0 &&
+                    str.indexOf(" not accepting requests", index) == -1) {
+                   return PrinterIsAcceptingJobs.ACCEPTING_JOBS;
+                }
+            }
+        }
+        return PrinterIsAcceptingJobs.NOT_ACCEPTING_JOBS ;
+    }
+
     private PrinterIsAcceptingJobs getPrinterIsAcceptingJobsBSD() {
         if (PrintServiceLookupProvider.cmdIndex ==
             PrintServiceLookupProvider.UNINITIALIZED) {
@@ -297,7 +322,9 @@
     }
 
     private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
-        if (PrintServiceLookupProvider.isBSD()) {
+        if (PrintServiceLookupProvider.isSysV()) {
+            return getPrinterIsAcceptingJobsSysV();
+        } else if (PrintServiceLookupProvider.isBSD()) {
             return getPrinterIsAcceptingJobsBSD();
         } else if (PrintServiceLookupProvider.isAIX()) {
             return getPrinterIsAcceptingJobsAIX();
@@ -324,6 +351,14 @@
         }
     }
 
+    private QueuedJobCount getQueuedJobCountSysV() {
+        String command = "/usr/bin/lpstat -R " + printer;
+        String[] results= PrintServiceLookupProvider.execCmd(command);
+        int qlen = (results == null) ? 0 : results.length;
+
+        return new QueuedJobCount(qlen);
+    }
+
     private QueuedJobCount getQueuedJobCountBSD() {
         if (PrintServiceLookupProvider.cmdIndex ==
             PrintServiceLookupProvider.UNINITIALIZED) {
@@ -380,7 +415,9 @@
     }
 
     private QueuedJobCount getQueuedJobCount() {
-        if (PrintServiceLookupProvider.isBSD()) {
+        if (PrintServiceLookupProvider.isSysV()) {
+            return getQueuedJobCountSysV();
+        } else if (PrintServiceLookupProvider.isBSD()) {
             return getQueuedJobCountBSD();
         } else if (PrintServiceLookupProvider.isAIX()) {
             return getQueuedJobCountAIX();
@@ -389,6 +426,13 @@
         }
     }
 
+    private PrintServiceAttributeSet getSysVServiceAttributes() {
+        PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
+        attrs.add(getQueuedJobCountSysV());
+        attrs.add(getPrinterIsAcceptingJobsSysV());
+        return attrs;
+    }
+
     private PrintServiceAttributeSet getBSDServiceAttributes() {
         PrintServiceAttributeSet attrs = new HashPrintServiceAttributeSet();
         attrs.add(getQueuedJobCountBSD());
@@ -427,7 +471,9 @@
     }
 
     private PrintServiceAttributeSet getDynamicAttributes() {
-        if (PrintServiceLookupProvider.isAIX()) {
+        if (PrintServiceLookupProvider.isSysV()) {
+            return getSysVServiceAttributes();
+        } else if (PrintServiceLookupProvider.isAIX()) {
             return getAIXServiceAttributes();
         } else {
             return getBSDServiceAttributes();
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/native/common/awt/fontpath.c jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/native/common/awt/fontpath.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/native/common/awt/fontpath.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/native/common/awt/fontpath.c	2024-08-17 18:29:44.517450937 +0200
@@ -61,7 +61,57 @@
 
 #define MAXFDIRS 512    /* Max number of directories that contain fonts */
 
-#if defined( __linux__)
+#if defined(__solaris__)
+/*
+ * This can be set in the makefile to "/usr/X11" if so desired.
+ */
+#ifndef OPENWINHOMELIB
+#define OPENWINHOMELIB "/usr/openwin/lib/"
+#endif
+
+/* This is all known Solaris X11 directories on Solaris 8, 9 and 10.
+ * It is ordered to give precedence to TrueType directories.
+ * It is needed if fontconfig is not installed or configured properly.
+ */
+static char *fullSolarisFontPath[] = {
+    OPENWINHOMELIB "X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/euro_fonts/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/iso_8859_15/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/ar/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/hi_IN.UTF-8/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/ja/X11/fonts/TT",
+    OPENWINHOMELIB "locale/ko/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/ko.UTF-8/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/KOI8-R/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/ru.ansi-1251/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/th_TH/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/zh_TW/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/zh_TW.BIG5/X11/fonts/TT",
+    OPENWINHOMELIB "locale/zh_HK.BIG5HK/X11/fonts/TT",
+    OPENWINHOMELIB "locale/zh_CN.GB18030/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/zh/X11/fonts/TrueType",
+    OPENWINHOMELIB "locale/zh.GBK/X11/fonts/TrueType",
+    OPENWINHOMELIB "X11/fonts/Type1",
+    OPENWINHOMELIB "X11/fonts/Type1/sun",
+    OPENWINHOMELIB "X11/fonts/Type1/sun/outline",
+    OPENWINHOMELIB "locale/iso_8859_2/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/iso_8859_4/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/iso_8859_5/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/iso_8859_7/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/iso_8859_8/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/iso_8859_9/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/iso_8859_13/X11/fonts/Type1",
+    OPENWINHOMELIB "locale/ar/X11/fonts/Type1",
+    NULL, /* terminates the list */
+};
+
+#elif defined( __linux__)
 /* All the known interesting locations we have discovered on
  * various flavors of Linux
  */
@@ -177,6 +227,14 @@
         if (strstr(x11Path[i], ".gnome") != NULL) {
             continue;
         }
+#ifdef __solaris__
+        if (strstr(x11Path[i], "/F3/") != NULL) {
+            continue;
+        }
+        if (strstr(x11Path[i], "bitmap") != NULL) {
+            continue;
+        }
+#endif
         fontdirs[pos] = strdup(x11Path[i]);
         slen = strlen(fontdirs[pos]);
         if (slen > 0 && fontdirs[pos][slen-1] == '/') {
@@ -326,6 +384,8 @@
 
 #if defined(__linux__)
     knowndirs = fullLinuxFontPath;
+#elif defined(__solaris__)
+    knowndirs = fullSolarisFontPath;
 #elif defined(_AIX)
     knowndirs = fullAixFontPath;
 #endif
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c	2024-08-17 18:29:44.518302464 +0200
@@ -399,7 +399,12 @@
             xrenderLibHandle = dlopen("libXrender.so", RTLD_LAZY | RTLD_GLOBAL);
         }
 
-#if defined(_AIX)
+#if defined(__solaris__)
+        if (xrenderLibHandle == NULL) {
+            xrenderLibHandle = dlopen("/usr/lib/libXrender.so.1",
+                                      RTLD_LAZY | RTLD_GLOBAL);
+        }
+#elif defined(_AIX)
         if (xrenderLibHandle == NULL) {
             xrenderLibHandle = dlopen("libXrender.a(libXrender.so.0)",
                                       RTLD_MEMBER | RTLD_LAZY | RTLD_GLOBAL);
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c	2024-08-17 18:29:44.519108910 +0200
@@ -61,6 +61,29 @@
 
 #include <dlfcn.h>
 
+#if defined(__solaris__)
+/* Solaris 10 will not have these symbols at compile time */
+
+typedef Picture (*XRenderCreateLinearGradientFuncType)
+                                     (Display *dpy,
+                                     const XLinearGradient *gradient,
+                                     const XFixed *stops,
+                                     const XRenderColor *colors,
+                                     int nstops);
+
+typedef Picture (*XRenderCreateRadialGradientFuncType)
+                                     (Display *dpy,
+                                     const XRadialGradient *gradient,
+                                     const XFixed *stops,
+                                     const XRenderColor *colors,
+                                     int nstops);
+
+static
+XRenderCreateLinearGradientFuncType XRenderCreateLinearGradientFunc = NULL;
+static
+ XRenderCreateRadialGradientFuncType XRenderCreateRadialGradientFunc = NULL;
+#endif
+
 #define BUILD_TRANSFORM_MATRIX(TRANSFORM, M00, M01, M02, M10, M11, M12)                        \
     {                                                                                          \
       TRANSFORM.matrix[0][0] = M00;                                                            \
@@ -128,6 +151,27 @@
     } else {
       available = JNI_FALSE;
     }
+#elif defined(__solaris__)
+    xrenderlib = dlopen("libXrender.so",RTLD_GLOBAL|RTLD_LAZY);
+    if (xrenderlib != NULL) {
+
+      XRenderCreateLinearGradientFunc =
+        (XRenderCreateLinearGradientFuncType)
+        dlsym(xrenderlib, "XRenderCreateLinearGradient");
+
+      XRenderCreateRadialGradientFunc =
+        (XRenderCreateRadialGradientFuncType)
+        dlsym(xrenderlib, "XRenderCreateRadialGradient");
+
+      if (XRenderCreateLinearGradientFunc == NULL ||
+          XRenderCreateRadialGradientFunc == NULL)
+      {
+        available = JNI_FALSE;
+      }
+      dlclose(xrenderlib);
+    } else {
+      available = JNI_FALSE;
+    }
 #else
     Dl_info info;
     jboolean versionInfoIsFound = JNI_FALSE;
@@ -534,7 +578,13 @@
       colors[i].green = pixels[i*4 + 2];
       colors[i].blue = pixels[i*4 + 3];
     }
+#ifdef __solaris__
+    if (XRenderCreateLinearGradientFunc!=NULL) {
+      gradient = (*XRenderCreateLinearGradientFunc)(awt_display, &grad, stops, colors, numStops);
+    }
+#else
     gradient = XRenderCreateLinearGradient(awt_display, &grad, stops, colors, numStops);
+#endif
     free(colors);
     free(stops);
 
@@ -612,7 +662,13 @@
       colors[i].green = pixels[i*4 + 2];
       colors[i].blue = pixels[i*4 + 3];
     }
+#ifdef __solaris__
+    if (XRenderCreateRadialGradientFunc != NULL) {
+        gradient = (jint) (*XRenderCreateRadialGradientFunc)(awt_display, &grad, stops, colors, numStops);
+    }
+#else
     gradient = (jint) XRenderCreateRadialGradient(awt_display, &grad, stops, colors, numStops);
+#endif
     free(colors);
     free(stops);
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java jdk18u-jdk-18.0.2.1-ga/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	2024-08-17 18:29:44.519728326 +0200
@@ -84,7 +84,9 @@
                                 = System.getProperty("sun.security.jgss.lib");
                         if (defaultLib == null || defaultLib.trim().equals("")) {
                             String osname = System.getProperty("os.name");
-                            if (osname.startsWith("Linux")) {
+                            if (osname.startsWith("SunOS")) {
+                                gssLibs = new String[]{ "libgss.so" };
+                            } else if (osname.startsWith("Linux")) {
                                 gssLibs = new String[]{
                                     "libgssapi.so",
                                     "libgssapi_krb5.so",
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/Config.java jdk18u-jdk-18.0.2.1-ga/src/java.security.jgss/share/classes/sun/security/krb5/Config.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	2024-08-17 18:29:44.520468509 +0200
@@ -926,6 +926,8 @@
             if (name == null) {
                 name = "c:\\winnt\\krb5.ini";
             }
+        } else if (osname.startsWith("SunOS")) {
+            name =  "/etc/krb5/krb5.conf";
         } else if (osname.contains("OS X")) {
             name = findMacosConfigFile();
         } else {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java jdk18u-jdk-18.0.2.1-ga/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java	2024-08-17 18:29:44.520987842 +0200
@@ -107,7 +107,7 @@
 
     private static long uid;
     static {
-        // Available on Linux and Mac. Otherwise, -1 and no _euid suffix
+        // Available on Solaris, Linux and Mac. Otherwise, -1 and no _euid suffix
         uid = jdk.internal.misc.VM.geteuid();
     }
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java jdk18u-jdk-18.0.2.1-ga/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java	2024-08-17 18:29:44.521544416 +0200
@@ -82,8 +82,12 @@
         String s2 = lib.substring(k + 7);
         String libDir;
         if ("64".equals(System.getProperty("sun.arch.data.model"))) {
-            // assume Linux convention
-            libDir = "lib64";
+            if ("SunOS".equals(System.getProperty("os.name"))) {
+                libDir = "lib/64";
+            } else {
+                // assume Linux convention
+                libDir = "lib64";
+            }
         } else {
             // must be 32-bit
             libDir = "lib";
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java jdk18u-jdk-18.0.2.1-ga/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java	2024-08-17 18:29:44.522193918 +0200
@@ -33,12 +33,21 @@
     private static final int KB = 1024;
     private static int BUFFER_SIZE = 4 * KB;
 
+    static {
+        // Set a larger buffer size for Solaris
+        final String osName = SecuritySupport.getSystemProperty("os.name");
+        if (osName.equalsIgnoreCase("solaris")) {
+            BUFFER_SIZE = 32 * KB;
+        }
+    }
+
     private Writer _writer;
 
     /**
      * Initializes a WriterOutputBuffer by creating an instance of a
      * BufferedWriter. The size of the buffer in this writer may have
-     * a significant impact on throughput.
+     * a significant impact on throughput. Solaris prefers a larger
+     * buffer, while Linux works better with a smaller one.
      */
     public WriterOutputBuffer(Writer writer) {
         _writer = new BufferedWriter(writer, BUFFER_SIZE);
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java jdk18u-jdk-18.0.2.1-ga/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java	2024-08-17 18:29:44.569653110 +0200
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.tools.attach;
+
+import com.sun.tools.attach.VirtualMachine;
+import com.sun.tools.attach.VirtualMachineDescriptor;
+import com.sun.tools.attach.AttachNotSupportedException;
+import java.io.IOException;
+
+/*
+ * An AttachProvider implementation for Solaris that use the doors
+ * interface to the VM.
+ */
+public class AttachProviderImpl extends HotSpotAttachProvider {
+
+    public AttachProviderImpl() {
+    }
+
+    public String name() {
+        return "sun";
+    }
+
+    public String type() {
+        return "doors";
+    }
+
+    public VirtualMachine attachVirtualMachine(String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        checkAttachPermission();
+
+        // AttachNotSupportedException will be thrown if the target VM can be determined
+        // to be not attachable.
+        testAttachable(vmid);
+
+        return new VirtualMachineImpl(this, vmid);
+    }
+
+    public VirtualMachine attachVirtualMachine(VirtualMachineDescriptor vmd)
+        throws AttachNotSupportedException, IOException
+    {
+        if (vmd.provider() != this) {
+            throw new AttachNotSupportedException("provider mismatch");
+        }
+        // To avoid re-checking if the VM if attachable, we check if the descriptor
+        // is for a hotspot VM - these descriptors are created by the listVirtualMachines
+        // implementation which only returns a list of attachable VMs.
+        if (vmd instanceof HotSpotVirtualMachineDescriptor) {
+            assert ((HotSpotVirtualMachineDescriptor)vmd).isAttachable();
+            checkAttachPermission();
+            return new VirtualMachineImpl(this, vmd.id());
+        } else {
+            return attachVirtualMachine(vmd.id());
+        }
+    }
+
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java jdk18u-jdk-18.0.2.1-ga/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java	2024-08-17 18:29:44.570091779 +0200
@@ -0,0 +1,272 @@
+/*
+ * Copyright (c) 2005, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+package sun.tools.attach;
+
+import com.sun.tools.attach.AttachOperationFailedException;
+import com.sun.tools.attach.AgentLoadException;
+import com.sun.tools.attach.AttachNotSupportedException;
+import com.sun.tools.attach.spi.AttachProvider;
+
+import java.io.InputStream;
+import java.io.IOException;
+import java.io.File;
+import java.io.FileNotFoundException;
+
+/*
+ * Solaris implementation of HotSpotVirtualMachine.
+ */
+public class VirtualMachineImpl extends HotSpotVirtualMachine {
+    // "/tmp" is used as a global well-known location for the files
+    // .java_pid<pid>. and .attach_pid<pid>. It is important that this
+    // location is the same for all processes, otherwise the tools
+    // will not be able to find all Hotspot processes.
+    // Any changes to this needs to be synchronized with HotSpot.
+    private static final String tmpdir = "/tmp";
+
+    // door descriptor;
+    private int fd = -1;
+    String socket_path;
+
+    /**
+     * Attaches to the target VM
+     */
+    VirtualMachineImpl(AttachProvider provider, String vmid)
+        throws AttachNotSupportedException, IOException
+    {
+        super(provider, vmid);
+        // This provider only understands process-ids (pids).
+        int pid;
+        try {
+            pid = Integer.parseInt(vmid);
+            if (pid < 1) {
+                throw new NumberFormatException();
+            }
+        } catch (NumberFormatException x) {
+            throw new AttachNotSupportedException("Invalid process identifier: " + vmid);
+        }
+
+        // Opens the door file to the target VM. If the file is not
+        // found it might mean that the attach mechanism isn't started in the
+        // target VM so we attempt to start it and retry.
+        try {
+            fd = openDoor(pid);
+        } catch (FileNotFoundException fnf1) {
+            File f = createAttachFile(pid);
+            try {
+                sigquit(pid);
+
+                // give the target VM time to start the attach mechanism
+                final int delay_step = 100;
+                final long timeout = attachTimeout();
+                long time_spend = 0;
+                long delay = 0;
+                do {
+                    // Increase timeout on each attempt to reduce polling
+                    delay += delay_step;
+                    try {
+                        Thread.sleep(delay);
+                    } catch (InterruptedException x) { }
+                    try {
+                        fd = openDoor(pid);
+                    } catch (FileNotFoundException fnf2) {
+                        // pass
+                    }
+
+                    time_spend += delay;
+                    if (time_spend > timeout/2 && fd == -1) {
+                        // Send QUIT again to give target VM the last chance to react
+                        sigquit(pid);
+                    }
+                } while (time_spend <= timeout && fd == -1);
+                if (fd  == -1) {
+                    throw new AttachNotSupportedException(
+                        String.format("Unable to open door %s: " +
+                          "target process %d doesn't respond within %dms " +
+                          "or HotSpot VM not loaded", socket_path, pid, time_spend));
+                }
+            } finally {
+                f.delete();
+            }
+        }
+        assert fd >= 0;
+    }
+
+    /**
+     * Detach from the target VM
+     */
+    public void detach() throws IOException {
+        synchronized (this) {
+            if (fd != -1) {
+                close(fd);
+                fd = -1;
+            }
+        }
+    }
+
+    /**
+     * Execute the given command in the target VM.
+     */
+    InputStream execute(String cmd, Object ... args) throws AgentLoadException, IOException {
+        assert args.length <= 3;                // includes null
+
+        // first check that we are still attached
+        int door;
+        synchronized (this) {
+            if (fd == -1) {
+                throw new IOException("Detached from target VM");
+            }
+            door = fd;
+        }
+
+        // enqueue the command via a door call
+        int s = enqueue(door, cmd, args);
+        assert s >= 0;                          // valid file descriptor
+
+        // The door call returns a file descriptor (one end of a socket pair).
+        // Create an input stream around it.
+        SocketInputStream sis = new SocketInputStream(s);
+
+        // Read the command completion status
+        int completionStatus;
+        try {
+            completionStatus = readInt(sis);
+        } catch (IOException ioe) {
+            sis.close();
+            throw ioe;
+        }
+
+        // If non-0 it means an error but we need to special-case the
+        // "load" command to ensure that the right exception is thrown.
+        if (completionStatus != 0) {
+            // read from the stream and use that as the error message
+            String message = readErrorMessage(sis);
+            sis.close();
+            if (cmd.equals("load")) {
+                String msg = "Failed to load agent library";
+                if (!message.isEmpty())
+                    msg += ": " + message;
+                throw new AgentLoadException(msg);
+            } else {
+                if (message.isEmpty())
+                    message = "Command failed in target VM";
+                throw new AttachOperationFailedException(message);
+            }
+        }
+
+        // Return the input stream so that the command output can be read
+        return sis;
+    }
+
+    // InputStream over a socket
+    private class SocketInputStream extends InputStream {
+        int s;
+
+        public SocketInputStream(int s) {
+            this.s = s;
+        }
+
+        public synchronized int read() throws IOException {
+            byte b[] = new byte[1];
+            int n = this.read(b, 0, 1);
+            if (n == 1) {
+                return b[0] & 0xff;
+            } else {
+                return -1;
+            }
+        }
+
+        public synchronized int read(byte[] bs, int off, int len) throws IOException {
+            if ((off < 0) || (off > bs.length) || (len < 0) ||
+                ((off + len) > bs.length) || ((off + len) < 0)) {
+                throw new IndexOutOfBoundsException();
+            } else if (len == 0)
+                return 0;
+
+            return VirtualMachineImpl.read(s, bs, off, len);
+        }
+
+        public synchronized void close() throws IOException {
+            if (s != -1) {
+                int toClose = s;
+                s = -1;
+                VirtualMachineImpl.close(toClose);
+            }
+        }
+    }
+
+    // The door is attached to .java_pid<pid> in the temporary directory.
+    private int openDoor(int pid) throws IOException {
+        socket_path = tmpdir + "/.java_pid" + pid;
+        fd = open(socket_path);
+
+        // Check that the file owner/permission to avoid attaching to
+        // bogus process
+        try {
+            checkPermissions(socket_path);
+        } catch (IOException ioe) {
+            close(fd);
+            throw ioe;
+        }
+        return fd;
+    }
+
+    // On Solaris a simple handshake is used to start the attach mechanism
+    // if not already started. The client creates a .attach_pid<pid> file in the
+    // target VM's working directory (or temporary directory), and the SIGQUIT
+    // handler checks for the file.
+    private File createAttachFile(int pid) throws IOException {
+        String fn = ".attach_pid" + pid;
+        String path = "/proc/" + pid + "/cwd/" + fn;
+        File f = new File(path);
+        try {
+            f = f.getCanonicalFile();
+            f.createNewFile();
+        } catch (IOException x) {
+            f = new File(tmpdir, fn);
+            f.createNewFile();
+        }
+        return f;
+    }
+
+    //-- native methods
+
+    static native int open(String path) throws IOException;
+
+    static native void close(int fd) throws IOException;
+
+    static native int read(int fd, byte buf[], int off, int buflen) throws IOException;
+
+    static native void checkPermissions(String path) throws IOException;
+
+    static native void sigquit(int pid) throws IOException;
+
+    // enqueue a command (and arguments) to the given door
+    static native int enqueue(int fd, String cmd, Object ... args)
+        throws IOException;
+
+    static {
+        System.loadLibrary("attach");
+    }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c jdk18u-jdk-18.0.2.1-ga/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c	2024-08-17 18:29:44.571093884 +0200
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2005, 2018, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include "jni_util.h"
+
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <door.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <limits.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "sun_tools_attach_VirtualMachineImpl.h"
+
+#define ROOT_UID 0
+
+#define RESTARTABLE(_cmd, _result) do { \
+  do { \
+    _result = _cmd; \
+  } while((_result == -1) && (errno == EINTR)); \
+} while(0)
+
+/*
+ * Declare library specific JNI_Onload entry if static build
+ */
+DEF_STATIC_JNI_OnLoad
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    open
+ * Signature: (Ljava/lang/String;)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_open
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p == NULL) {
+        return 0;
+    } else {
+        int fd;
+        int err = 0;
+
+        fd = open(p, O_RDWR);
+        if (fd == -1) {
+            err = errno;
+        }
+
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+
+        if (fd == -1) {
+            if (err == ENOENT) {
+                JNU_ThrowByName(env, "java/io/FileNotFoundException", NULL);
+            } else {
+                char* msg = strdup(strerror(err));
+                JNU_ThrowIOException(env, msg);
+                if (msg != NULL) {
+                    free(msg);
+                }
+            }
+        }
+        return fd;
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    checkPermissions
+ * Signature: (Ljava/lang/String;)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_checkPermissions
+  (JNIEnv *env, jclass cls, jstring path)
+{
+    jboolean isCopy;
+    const char* p = GetStringPlatformChars(env, path, &isCopy);
+    if (p != NULL) {
+        struct stat64 sb;
+        uid_t uid, gid;
+        int res;
+
+        memset(&sb, 0, sizeof(struct stat64));
+
+        /*
+         * Check that the path is owned by the effective uid/gid of this
+         * process. Also check that group/other access is not allowed.
+         */
+        uid = geteuid();
+        gid = getegid();
+
+        res = stat64(p, &sb);
+        if (res != 0) {
+            /* save errno */
+            res = errno;
+        }
+
+        if (res == 0) {
+            char msg[100];
+            jboolean isError = JNI_FALSE;
+            if (sb.st_uid != uid && uid != ROOT_UID) {
+                snprintf(msg, sizeof(msg),
+                    "file should be owned by the current user (which is %d) but is owned by %d", uid, sb.st_uid);
+                isError = JNI_TRUE;
+            } else if (sb.st_gid != gid && uid != ROOT_UID) {
+                snprintf(msg, sizeof(msg),
+                    "file's group should be the current group (which is %d) but the group is %d", gid, sb.st_gid);
+                isError = JNI_TRUE;
+            } else if ((sb.st_mode & (S_IRGRP|S_IWGRP|S_IROTH|S_IWOTH)) != 0) {
+                snprintf(msg, sizeof(msg),
+                    "file should only be readable and writable by the owner but has 0%03o access", sb.st_mode & 0777);
+                isError = JNI_TRUE;
+            }
+            if (isError) {
+                char buf[256];
+                snprintf(buf, sizeof(buf), "well-known file %s is not secure: %s", p, msg);
+                JNU_ThrowIOException(env, buf);
+            }
+        } else {
+            char* msg = strdup(strerror(res));
+            JNU_ThrowIOException(env, msg);
+            if (msg != NULL) {
+                free(msg);
+            }
+        }
+
+        if (isCopy) {
+            JNU_ReleaseStringPlatformChars(env, path, p);
+        }
+    }
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    close
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_close
+  (JNIEnv *env, jclass cls, jint fd)
+{
+    int ret;
+    RESTARTABLE(close(fd), ret);
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    read
+ * Signature: (I[BI)I
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_read
+  (JNIEnv *env, jclass cls, jint fd, jbyteArray ba, jint off, jint baLen)
+{
+    unsigned char buf[128];
+    size_t len = sizeof(buf);
+    ssize_t n;
+
+    size_t remaining = (size_t)(baLen - off);
+    if (len > remaining) {
+        len = remaining;
+    }
+
+    RESTARTABLE(read(fd, buf, len), n);
+    if (n == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "read");
+    } else {
+        if (n == 0) {
+            n = -1;     // EOF
+        } else {
+            (*env)->SetByteArrayRegion(env, ba, off, (jint)n, (jbyte *)(buf));
+        }
+    }
+    return n;
+}
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    sigquit
+ * Signature: (I)V
+ */
+JNIEXPORT void JNICALL Java_sun_tools_attach_VirtualMachineImpl_sigquit
+  (JNIEnv *env, jclass cls, jint pid)
+{
+    if (kill((pid_t)pid, SIGQUIT) == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "kill");
+    }
+}
+
+/*
+ * A simple table to translate some known errors into reasonable
+ * error messages
+ */
+static struct {
+    jint err;
+    const char* msg;
+} const error_messages[] = {
+    { 100,      "Bad request" },
+    { 101,      "Protocol mismatch" },
+    { 102,      "Resource failure" },
+    { 103,      "Internal error" },
+    { 104,      "Permission denied" },
+};
+
+/*
+ * Lookup the given error code and return the appropriate
+ * message. If not found return NULL.
+ */
+static const char* translate_error(jint err) {
+    int table_size = sizeof(error_messages) / sizeof(error_messages[0]);
+    int i;
+
+    for (i = 0; i < table_size; i++) {
+        if (err == error_messages[i].err) {
+            return error_messages[i].msg;
+        }
+    }
+    return NULL;
+}
+
+/*
+ * Current protocol version
+ */
+static const char* PROTOCOL_VERSION = "1";
+
+/*
+ * Class:     sun_tools_attach_VirtualMachineImpl
+ * Method:    enqueue
+ * Signature: (JILjava/lang/String;[Ljava/lang/Object;)V
+ */
+JNIEXPORT jint JNICALL Java_sun_tools_attach_VirtualMachineImpl_enqueue
+  (JNIEnv *env, jclass cls, jint fd, jstring cmd, jobjectArray args)
+{
+    jint arg_count, i;
+    size_t size;
+    jboolean isCopy;
+    door_arg_t door_args;
+    char res_buffer[128];
+    jint result = -1;
+    int rc;
+    const char* cstr;
+    char* buf;
+
+    /*
+     * First we get the command string and create the start of the
+     * argument string to send to the target VM:
+     * <ver>\0<cmd>\0
+     */
+    cstr = JNU_GetStringPlatformChars(env, cmd, &isCopy);
+    if (cstr == NULL) {
+        return -1;              /* pending exception */
+    }
+    size = strlen(PROTOCOL_VERSION) + strlen(cstr) + 2;
+    buf = (char*)malloc(size);
+    if (buf != NULL) {
+        char* pos = buf;
+        strcpy(buf, PROTOCOL_VERSION);
+        pos += strlen(PROTOCOL_VERSION)+1;
+        strcpy(pos, cstr);
+    }
+    if (isCopy) {
+        JNU_ReleaseStringPlatformChars(env, cmd, cstr);
+    }
+    if (buf == NULL) {
+        JNU_ThrowOutOfMemoryError(env, "malloc failed");
+        return -1;
+    }
+
+    /*
+     * Next we iterate over the arguments and extend the buffer
+     * to include them.
+     */
+    arg_count = (*env)->GetArrayLength(env, args);
+
+    for (i = 0; i < arg_count; i++) {
+        jobject obj = (*env)->GetObjectArrayElement(env, args, i);
+        if (obj != NULL) {
+            cstr = JNU_GetStringPlatformChars(env, obj, &isCopy);
+            if (cstr != NULL) {
+                size_t len = strlen(cstr);
+                char* newbuf = (char*)realloc(buf, size+len+1);
+                if (newbuf != NULL) {
+                    buf = newbuf;
+                    strcpy(buf+size, cstr);
+                    size += len+1;
+                }
+                if (isCopy) {
+                    JNU_ReleaseStringPlatformChars(env, obj, cstr);
+                }
+                if (newbuf == NULL) {
+                    free(buf);
+                    JNU_ThrowOutOfMemoryError(env, "realloc failed");
+                    return -1;
+                }
+            }
+        } else {
+            char* newbuf = (char*)realloc(buf, size + 1);
+            if (newbuf == NULL) {
+                free(buf);
+                JNU_ThrowOutOfMemoryError(env, "realloc failed");
+                return -1;
+            }
+            buf = newbuf;
+            buf[size++] = 0;
+        }
+        if ((*env)->ExceptionOccurred(env)) {
+            free(buf);
+            return -1;
+        }
+    }
+
+    /*
+     * The arguments to the door function are in 'buf' so we now
+     * do the door call
+     */
+    door_args.data_ptr = buf;
+    door_args.data_size = size;
+    door_args.desc_ptr = NULL;
+    door_args.desc_num = 0;
+    door_args.rbuf = (char*)&res_buffer;
+    door_args.rsize = sizeof(res_buffer);
+
+    RESTARTABLE(door_call(fd, &door_args), rc);
+
+    /*
+     * door_call failed
+     */
+    if (rc == -1) {
+        JNU_ThrowIOExceptionWithLastError(env, "door_call");
+    } else {
+        /*
+         * door_call succeeded but the call didn't return the expected jint.
+         */
+        if (door_args.data_size < sizeof(jint)) {
+            JNU_ThrowIOException(env, "Enqueue error - reason unknown as result is truncated!");
+        } else {
+            jint* res = (jint*)(door_args.data_ptr);
+            if (*res != JNI_OK) {
+                const char* msg = translate_error(*res);
+                char buf[255];
+                if (msg == NULL) {
+                    sprintf(buf, "Unable to enqueue command to target VM: %d", *res);
+                } else {
+                    sprintf(buf, "Unable to enqueue command to target VM: %s", msg);
+                }
+                JNU_ThrowIOException(env, buf);
+            } else {
+                /*
+                 * The door call should return a file descriptor to one end of
+                 * a socket pair
+                 */
+                if ((door_args.desc_ptr != NULL) &&
+                    (door_args.desc_num == 1) &&
+                    (door_args.desc_ptr->d_attributes & DOOR_DESCRIPTOR)) {
+                    result = door_args.desc_ptr->d_data.d_desc.d_descriptor;
+                } else {
+                    JNU_ThrowIOException(env, "Reply from enqueue missing descriptor!");
+                }
+            }
+        }
+    }
+
+    free(buf);
+    return result;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java jdk18u-jdk-18.0.2.1-ga/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java	2024-08-17 18:29:44.522857987 +0200
@@ -98,7 +98,7 @@
             (PrivilegedAction<String>) () -> System.getProperty("os.name"));
 
         private static final String SJISName = getSJISName();
-        private static final String EUCJPName = "EUC_JP";
+        private static final String EUCJPName = getEUCJPName();
         private DelegatableDecoder detectedDecoder = null;
 
         public Decoder(Charset cs) {
@@ -226,11 +226,24 @@
          * Returned Shift_JIS Charset name is OS dependent
          */
         private static String getSJISName() {
-            if (osName.startsWith("Windows"))
+            if (osName.equals("Solaris") || osName.equals("SunOS"))
+                return("PCK");
+            else if (osName.startsWith("Windows"))
                 return("windows-31J");
             else
                 return("Shift_JIS");
         }
 
+        /**
+         * Returned EUC-JP Charset name is OS dependent
+         */
+
+        private static String getEUCJPName() {
+            if (osName.equals("Solaris") || osName.equals("SunOS"))
+                return("x-eucjp-open");
+            else
+                return("EUC_JP");
+        }
+
     }
 }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java jdk18u-jdk-18.0.2.1-ga/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java	2024-08-17 18:29:44.523580781 +0200
@@ -711,10 +711,15 @@
         lib = expand(lib);
         int i = lib.indexOf("/$ISA/");
         if (i != -1) {
-            // replace "/$ISA/" with "/"
+            // replace "/$ISA/" with "/amd64/" on Solaris AMD64.
+            // On all other platforms, just turn it into a "/"
             String prefix = lib.substring(0, i);
             String suffix = lib.substring(i + 5);
-            lib = prefix + suffix;
+            if (osName.equals("SunOS") && osArch.equals("amd64")) {
+                lib = prefix + "/amd64" + suffix;
+            } else {
+                lib = prefix + suffix;
+            }
         }
         debug(keyword + ": " + lib);
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg jdk18u-jdk-18.0.2.1-ga/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg	2024-08-17 18:29:44.572066612 +0200
@@ -0,0 +1,23 @@
+#
+# Configuration file to allow the SunPKCS11 provider to utilize
+# the Solaris Cryptographic Framework, if it is available
+#
+
+name = Solaris
+
+description = SunPKCS11 accessing Solaris Cryptographic Framework
+
+library = /usr/lib/$ISA/libpkcs11.so
+
+handleStartupErrors = ignoreAll
+
+# Use the X9.63 encoding for EC points (do not wrap in an ASN.1 OctetString).
+useEcX963Encoding = true
+
+attributes = compatibility
+
+disabledMechanisms = {
+  CKM_DSA_KEY_PAIR_GEN
+  SecureRandom
+}
+
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/debugger/proc/ProcDebuggerLocal.java	2024-08-17 18:29:44.573910358 +0200
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2014, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.debugger.proc;
+
+import java.io.*;
+import java.net.*;
+import java.util.*;
+import java.lang.reflect.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.cdbg.*;
+import sun.jvm.hotspot.debugger.proc.amd64.*;
+import sun.jvm.hotspot.debugger.proc.aarch64.*;
+import sun.jvm.hotspot.debugger.proc.ppc64.*;
+import sun.jvm.hotspot.debugger.proc.x86.*;
+import sun.jvm.hotspot.debugger.ppc64.*;
+import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.debugger.aarch64.*;
+import sun.jvm.hotspot.debugger.x86.*;
+import sun.jvm.hotspot.utilities.*;
+
+/** <P> An implementation of the JVMDebugger interface which sits on
+ * top of proc and relies on the SA's proc import module for
+ * communication with the debugger. </P>
+ *
+ * <P> <B>NOTE</B> that since we have the notion of fetching "Java
+ * primitive types" from the remote process (which might have
+ * different sizes than we expect) we have a bootstrapping
+ * problem. We need to know the sizes of these types before we can
+ * fetch them. The current implementation solves this problem by
+ * requiring that it be configured with these type sizes before they
+ * can be fetched. The readJ(Type) routines here will throw a
+ * RuntimeException if they are called before the debugger is
+ * configured with the Java primitive type sizes. </P>
+ */
+
+public class ProcDebuggerLocal extends DebuggerBase implements ProcDebugger {
+    protected static final int cacheSize = 16 * 1024 * 1024; // 16 MB
+
+    //------------------------------------------------------------------------
+    // Implementation of Debugger interface
+    //
+
+    /** <P> machDesc may be null if it couldn't be determined yet; i.e.,
+     * if we're on SPARC, we need to ask the remote process whether
+     * we're in 32- or 64-bit mode. </P>
+     *
+     * <P> useCache should be set to true if debugging is being done
+     * locally, and to false if the debugger is being created for the
+     * purpose of supporting remote debugging. </P> */
+    public ProcDebuggerLocal(MachineDescription machDesc, boolean useCache) {
+        this.machDesc = machDesc;
+        int cacheNumPages;
+        int cachePageSize;
+
+        final String cpu = PlatformInfo.getCPU();
+        if (cpu.equals("x86")) {
+            threadFactory = new ProcX86ThreadFactory(this);
+            pcRegIndex = X86ThreadContext.EIP;
+            fpRegIndex = X86ThreadContext.EBP;
+            unalignedAccessesOkay = true;
+        } else if (cpu.equals("amd64") || cpu.equals("x86_64")) {
+            threadFactory = new ProcAMD64ThreadFactory(this);
+            pcRegIndex = AMD64ThreadContext.RIP;
+            fpRegIndex = AMD64ThreadContext.RBP;
+        } else if (cpu.equals("aarch64")) {
+            threadFactory = new ProcAARCH64ThreadFactory(this);
+            pcRegIndex = AARCH64ThreadContext.PC;
+            fpRegIndex = AARCH64ThreadContext.FP;
+        } else if (cpu.equals("ppc64")) {
+            threadFactory = new ProcPPC64ThreadFactory(this);
+            pcRegIndex = PPC64ThreadContext.PC;
+            fpRegIndex = PPC64ThreadContext.SP;
+        } else {
+          try {
+            Class tfc = Class.forName("sun.jvm.hotspot.debugger.proc." +
+               cpu.toLowerCase() + ".Proc" + cpu.toUpperCase() +
+               "ThreadFactory");
+            Constructor[] ctfc = tfc.getConstructors();
+            threadFactory = (ProcThreadFactory)ctfc[0].newInstance(this);
+          } catch (Exception e) {
+            throw new RuntimeException("Thread access for CPU architecture " + PlatformInfo.getCPU() + " not yet supported");
+            // Note: pcRegIndex and fpRegIndex do not appear to be referenced
+          }
+        }
+        if (useCache) {
+            // Cache portion of the remote process's address space.
+            // For now, this cache works best if it covers the entire
+            // heap of the remote process. FIXME: at least should make this
+            // tunable from the outside, i.e., via the UI. This is a 16 MB
+            // cache divided on SPARC into 2048 8K pages and on x86 into
+            // 4096 4K pages; the page size must be adjusted to be the OS's
+            // page size.
+
+            cachePageSize = getPageSize();
+            cacheNumPages = parseCacheNumPagesProperty(cacheSize / cachePageSize);
+            initCache(cachePageSize, cacheNumPages);
+        }
+
+        resetNativePointers();
+        clearCacheFields();
+    }
+
+    /** FIXME: implement this with a Runtime.exec() of ps followed by
+     * parsing of its output */
+    public boolean hasProcessList() throws DebuggerException {
+        return false;
+    }
+
+    public List<ProcessInfo> getProcessList() throws DebuggerException {
+        throw new DebuggerException("Not yet supported");
+    }
+
+
+    /** From the Debugger interface via JVMDebugger */
+    public synchronized void attach(int processID) throws DebuggerException {
+        checkAttached();
+        isCore = false;
+        attach0(Integer.toString(processID));
+        attached = true;
+        suspended = true;
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public synchronized void attach
+    (String executableName, String coreFileName) throws DebuggerException {
+        checkAttached();
+        isCore = true;
+        topFrameCache = new HashMap<>();
+        attach0(executableName, coreFileName);
+        attached = true;
+        suspended = true;
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public synchronized boolean detach() {
+        if (! attached) {
+            return false;
+        }
+
+        try {
+            if (p_ps_prochandle == 0L) {
+                return false;
+            }
+            detach0();
+            clearCache();
+            return true;
+        } catch (Exception e) {
+            e.printStackTrace();
+            return false;
+        } finally {
+            resetNativePointers();
+            clearCacheFields();
+            suspended = false;
+            attached = false;
+        }
+    }
+
+    public synchronized void suspend() throws DebuggerException {
+        requireAttach();
+        if (suspended) {
+            throw new DebuggerException("Process already suspended");
+        }
+        suspend0();
+        suspended = true;
+        enableCache();
+    }
+
+    public synchronized void resume() throws DebuggerException {
+        requireAttach();
+        if (!suspended) {
+            throw new DebuggerException("Process not suspended");
+        }
+        resume0();
+        disableCache();
+        suspended = false;
+    }
+
+    public synchronized boolean isSuspended() throws DebuggerException {
+        requireAttach();
+        return suspended;
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public Address parseAddress(String addressString) throws NumberFormatException {
+        long addr = utils.scanAddress(addressString);
+        if (addr == 0) {
+            return null;
+        }
+        return new ProcAddress(this, addr);
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public String getOS() {
+        return PlatformInfo.getOS();
+    }
+
+    /** From the Debugger interface via JVMDebugger */
+    public String getCPU() {
+        return PlatformInfo.getCPU();
+    }
+
+    public boolean hasConsole() throws DebuggerException {
+        return false;
+    }
+
+    public String consoleExecuteCommand(String cmd) throws DebuggerException {
+        throw new DebuggerException("Can't execute console commands");
+    }
+
+    public String getConsolePrompt() throws DebuggerException {
+        return "";
+    }
+
+    public CDebugger getCDebugger() throws DebuggerException {
+        if (cdbg == null) {
+            cdbg = new ProcCDebugger(this);
+        }
+        return cdbg;
+    }
+
+    /** From the SymbolLookup interface via Debugger and JVMDebugger */
+    public synchronized Address lookup(String objectName, String symbol) {
+        requireAttach();
+        long addr = lookupByName0(objectName, symbol);
+        if (addr == 0) {
+            return null;
+        }
+        return new ProcAddress(this, addr);
+    }
+
+    /** From the SymbolLookup interface via Debugger and JVMDebugger */
+    public synchronized OopHandle lookupOop(String objectName, String symbol) {
+        Address addr = lookup(objectName, symbol);
+        if (addr == null) {
+            return null;
+        }
+        return addr.addOffsetToAsOopHandle(0);
+    }
+
+    /** From the ProcDebugger interface */
+    public MachineDescription getMachineDescription() {
+        return machDesc;
+    }
+
+    /** Internal routine supporting lazy setting of MachineDescription,
+     * since on SPARC we will need to query the remote process to ask
+     * it what its data model is (32- or 64-bit).
+     */
+
+    public void setMachineDescription(MachineDescription machDesc) {
+        this.machDesc = machDesc;
+        setBigEndian(machDesc.isBigEndian());
+        utils = new DebuggerUtilities(machDesc.getAddressSize(), machDesc.isBigEndian());
+    }
+
+    public synchronized int getRemoteProcessAddressSize()
+    throws DebuggerException {
+        requireAttach();
+        return getRemoteProcessAddressSize0();
+    }
+
+    //--------------------------------------------------------------------------------
+    // Implementation of ThreadAccess interface
+    //
+
+    /** From the ThreadAccess interface via Debugger and JVMDebugger */
+    public ThreadProxy getThreadForIdentifierAddress(Address addr) {
+        return threadFactory.createThreadWrapper(addr);
+    }
+
+    public ThreadProxy getThreadForThreadId(long id) {
+        return threadFactory.createThreadWrapper(id);
+    }
+
+    //----------------------------------------------------------------------
+    // Overridden from DebuggerBase because we need to relax alignment
+    // constraints on x86
+
+    public long readJLong(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+        checkJavaConfigured();
+        // FIXME: allow this to be configurable. Undesirable to add a
+        // dependency on the runtime package here, though, since this
+        // package should be strictly underneath it.
+        if (unalignedAccessesOkay) {
+            utils.checkAlignment(address, jintSize);
+        } else {
+            utils.checkAlignment(address, jlongSize);
+        }
+        byte[] data = readBytes(address, jlongSize);
+        return utils.dataToJLong(data, jlongSize);
+    }
+
+    //--------------------------------------------------------------------------------
+    // Internal routines (for implementation of ProcAddress).
+    // These must not be called until the MachineDescription has been set up.
+    //
+
+    /** From the ProcDebugger interface */
+    public String addressValueToString(long address) {
+        return utils.addressValueToString(address);
+    }
+
+    /** Need to override this to relax alignment checks on Solaris/x86. */
+    public long readCInteger(long address, long numBytes, boolean isUnsigned)
+    throws UnmappedAddressException, UnalignedAddressException {
+        checkConfigured();
+        if (!unalignedAccessesOkay) {
+            utils.checkAlignment(address, numBytes);
+        } else {
+            // Only slightly relaxed semantics -- this is a hack, but is
+            // necessary on Solaris/x86 where it seems the compiler is
+            // putting some global 64-bit data on 32-bit boundaries
+            if (numBytes == 8) {
+                utils.checkAlignment(address, 4);
+            } else {
+                utils.checkAlignment(address, numBytes);
+            }
+        }
+        byte[] data = readBytes(address, numBytes);
+        return utils.dataToCInteger(data, isUnsigned);
+    }
+
+    /** From the ProcDebugger interface */
+    public ProcAddress readAddress(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+        long value = readAddressValue(address);
+        return (value == 0 ? null : new ProcAddress(this, value));
+    }
+
+    public ProcAddress readCompOopAddress(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+        long value = readCompOopAddressValue(address);
+        return (value == 0 ? null : new ProcAddress(this, value));
+    }
+
+    public ProcAddress readCompKlassAddress(long address)
+    throws UnmappedAddressException, UnalignedAddressException {
+        long value = readCompKlassAddressValue(address);
+        return (value == 0 ? null : new ProcAddress(this, value));
+    }
+
+    /** From the ProcDebugger interface */
+    public ProcOopHandle readOopHandle(long address)
+    throws UnmappedAddressException, UnalignedAddressException, NotInHeapException {
+        long   value = readAddressValue(address);
+        return (value == 0 ? null : new ProcOopHandle(this, value));
+    }
+
+    public ProcOopHandle readCompOopHandle(long address) {
+        long value = readCompOopAddressValue(address);
+        return (value == 0 ? null : new ProcOopHandle(this, value));
+    }
+
+    public void writeBytesToProcess(long address, long numBytes, byte[] data)
+    throws UnmappedAddressException, DebuggerException {
+        if (isCore) {
+            throw new DebuggerException("Attached to a core file!");
+        }
+        writeBytesToProcess0(address, numBytes, data);
+    }
+
+    public synchronized ReadResult readBytesFromProcess(long address, long numBytes)
+    throws DebuggerException {
+        requireAttach();
+        byte[] res = readBytesFromProcess0(address, numBytes);
+        if(res != null)
+            return new ReadResult(res);
+        else
+            return new ReadResult(address);
+    }
+
+    protected int getPageSize() {
+        int pagesize = getPageSize0();
+        if (pagesize == -1) {
+            // return the hard coded default value.
+            if (PlatformInfo.getCPU().equals("sparc") ||
+                PlatformInfo.getCPU().equals("amd64") )
+               pagesize = 8196;
+            else
+               pagesize = 4096;
+        }
+        return pagesize;
+    }
+
+    //--------------------------------------------------------------------------------
+    // Thread context access. Can not be package private, but should
+    // only be accessed by the architecture-specific subpackages.
+
+    /** From the ProcDebugger interface. May have to redefine this later. */
+    public synchronized long[] getThreadIntegerRegisterSet(int tid) {
+        requireAttach();
+        return getThreadIntegerRegisterSet0(tid);
+    }
+
+    //--------------------------------------------------------------------------------
+    // Address access. Can not be package private, but should only be
+    // accessed by the architecture-specific subpackages.
+
+    /** From the ProcDebugger interface */
+    public long getAddressValue(Address addr) {
+        if (addr == null) return 0;
+        return ((ProcAddress) addr).getValue();
+    }
+
+    /** From the ProcDebugger interface */
+    public Address newAddress(long value) {
+        if (value == 0) return null;
+        return new ProcAddress(this, value);
+    }
+
+    /** From the ProcDebugger interface */
+    public synchronized List<ThreadProxy> getThreadList() throws DebuggerException {
+        requireAttach();
+        List<ThreadProxy> res = null;
+        if (isCore && (threadListCache != null)) {
+            res = threadListCache;
+        } else {
+            res = new ArrayList<>();
+            fillThreadList0(res);
+            if (isCore) {
+                threadListCache = res;
+            }
+        }
+        return res;
+    }
+
+    /** From the ProcDebugger interface */
+    public synchronized List<LoadObject> getLoadObjectList() throws DebuggerException {
+        // FIXME-ILLUMOS
+        // unimplemented
+        throw new DebuggerException("Unimplemented");
+    }
+
+    /** From the ProcDebugger interface */
+    public synchronized CFrame topFrameForThread(ThreadProxy thread)
+    throws DebuggerException {
+        requireAttach();
+        CFrame res = null;
+        if (isCore && ((res = (CFrame) topFrameCache.get(thread)) != null)) {
+            return res;
+        } else {
+            ThreadContext context = thread.getContext();
+            int numRegs = context.getNumRegisters();
+            long[] regs = new long[numRegs];
+            for (int i = 0; i < numRegs; i++) {
+                regs[i] = context.getRegister(i);
+            }
+            res = fillCFrameList0(regs);
+            if (isCore) {
+                topFrameCache.put(thread, res);
+            }
+            return res;
+        }
+    }
+
+    /** From the ProcDebugger interface */
+    public synchronized ClosestSymbol lookup(long address) {
+        requireAttach();
+        return lookupByAddress0(address);
+    }
+
+    /** From the ProcDebugger interface */
+    public String demangle(String name) {
+        return demangle0(name);
+    }
+
+    //------------- Internals only below this point --------------------
+    //
+    //
+
+    // sort load objects by base address
+    private static List<LoadObject> sortLoadObjects(List<LoadObject> in) {
+        // sort the list by base address
+        LoadObject[] arr = in.toArray(new LoadObject[0]);
+        Arrays.sort(arr, loadObjectComparator);
+        return Arrays.asList(arr);
+    }
+
+    private SharedObject findDSOByName(String fullPathName) {
+        if (loadObjectCache == null)
+            return null;
+        for (Iterator iter = loadObjectCache.iterator(); iter.hasNext(); ) {
+            SharedObject dso = (SharedObject) iter.next();
+            if (dso.getName().equals(fullPathName)) {
+                return dso;
+            }
+        }
+        return null;
+    }
+
+    private void checkAttached() {
+        if (attached) {
+            if (isCore) {
+                throw new DebuggerException("already attached to a core file!");
+            } else {
+                throw new DebuggerException("already attached to a process!");
+            }
+        }
+    }
+
+    private void requireAttach() {
+        if (! attached) {
+            throw new RuntimeException("not attached to a process or core file!");
+        }
+    }
+
+    private void clearCacheFields() {
+        loadObjectCache = null;
+        nameToDsoMap    = null;
+        threadListCache = null;
+        topFrameCache   = null;
+    }
+
+    private void resetNativePointers() {
+        p_ps_prochandle          = 0L;
+
+        // reset thread_db pointers
+        libthread_db_handle    = 0L;
+        p_td_thragent_t        = 0L;
+        p_td_init              = 0L;
+        p_td_ta_new            = 0L;
+        p_td_ta_delete         = 0L;
+        p_td_ta_thr_iter       = 0L;
+        p_td_thr_get_info      = 0L;
+        p_td_ta_map_id2thr     = 0L;
+        p_td_thr_getgregs      = 0L;
+
+        // part of class sharing workaround
+        classes_jsa_fd         = -1;
+        p_file_map_header      = 0L;
+    }
+
+    // native methods and native helpers
+
+    // attach, detach
+    private native void attach0(String pid) throws DebuggerException;
+    private native void attach0(String executableFile, String coreFileName) throws DebuggerException;
+    private native void detach0() throws DebuggerException;
+
+    // address size, page size
+    private native int getRemoteProcessAddressSize0() throws DebuggerException;
+    private native int getPageSize0() throws DebuggerException;
+
+    // threads, stacks
+    private native long[] getThreadIntegerRegisterSet0(long tid) throws DebuggerException;
+    private native void   fillThreadList0(List<ThreadProxy> l) throws DebuggerException;
+
+    // fills stack frame list given reg set of the top frame and top frame
+    private native ProcCFrame fillCFrameList0(long[] regs) throws DebuggerException;
+
+    // helper called by fillCFrameList0
+    private ProcCFrame createSenderFrame(ProcCFrame f, long pc, long fp) {
+        ProcCFrame sender = new ProcCFrame(this, newAddress(pc), newAddress(fp));
+        if (f != null) {
+            f.setSender(sender);
+        }
+        return sender;
+    }
+
+    // symbol-to-pc
+    private native long lookupByName0(String objectName, String symbolName) throws DebuggerException;
+    private native ClosestSymbol lookupByAddress0(long address) throws DebuggerException;
+
+    // helper called by lookupByAddress0
+    private ClosestSymbol createClosestSymbol(String name, long offset) {
+        return new ClosestSymbol(name, offset);
+    }
+
+    // process read/write
+    private native byte[] readBytesFromProcess0(long address, long numBytes) throws DebuggerException;
+    private native void writeBytesToProcess0(long address, long numBytes, byte[] data) throws DebuggerException;
+
+    // process control
+    private native void suspend0() throws DebuggerException;
+    private native void resume0() throws DebuggerException;
+
+    // demangle a C++ name
+    private native String demangle0(String name);
+
+    // init JNI ids to fields, methods
+    private native static void initIDs() throws DebuggerException;
+    private static LoadObjectComparator loadObjectComparator;
+
+    static {
+        System.loadLibrary("saproc");
+        initIDs();
+        loadObjectComparator = new LoadObjectComparator();
+    }
+
+    private boolean unalignedAccessesOkay;
+    private ProcThreadFactory threadFactory;
+
+    // indices of PC and FP registers in gregset
+    private int pcRegIndex;
+    private int fpRegIndex;
+
+    // Symbol lookup support
+    // This is a map of library names to DSOs
+    private Map<String, SharedObject> nameToDsoMap;
+
+    // C/C++ debugging support
+    private List<LoadObject> loadObjects;
+    private CDebugger cdbg;
+
+    // ProcessControl support
+    private boolean suspended;
+
+    // libproc handle
+    private long p_ps_prochandle;
+
+    // libthread.so's dlopen handle, thread agent
+    // and function pointers
+    private long libthread_db_handle;
+    private long p_td_thragent_t;
+    private long p_td_init;
+    private long p_td_ta_new;
+    private long p_td_ta_delete;
+    private long p_td_ta_thr_iter;
+    private long p_td_thr_get_info;
+    private long p_td_ta_map_id2thr;
+    private long p_td_thr_getgregs;
+
+    // part of class sharing workaround
+    private int classes_jsa_fd;
+    private long p_file_map_header;
+
+    private boolean attached = false;
+    private boolean isCore;
+
+    // for core files, we cache load object list, thread list, top frames etc.
+    // for processes we cache load object list and sync. it during suspend.
+    private List<ThreadProxy> threadListCache;
+    private List<LoadObject> loadObjectCache;
+    private Map<ThreadProxy, CFrame> topFrameCache;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotAgent.java	2024-08-17 18:29:44.524461693 +0200
@@ -40,6 +40,7 @@
 import sun.jvm.hotspot.debugger.NoSuchSymbolException;
 import sun.jvm.hotspot.debugger.bsd.BsdDebuggerLocal;
 import sun.jvm.hotspot.debugger.linux.LinuxDebuggerLocal;
+import sun.jvm.hotspot.debugger.proc.ProcDebuggerLocal;
 import sun.jvm.hotspot.debugger.remote.RemoteDebugger;
 import sun.jvm.hotspot.debugger.remote.RemoteDebuggerClient;
 import sun.jvm.hotspot.debugger.remote.RemoteDebuggerServer;
@@ -361,7 +362,9 @@
                 } catch (UnsupportedPlatformException e) {
                    throw new DebuggerException(e);
                 }
-                if (os.equals("win32")) {
+                if (os.equals("solaris")) {
+                    setupDebuggerSolaris();
+                } else if (os.equals("win32")) {
                     setupDebuggerWin32();
                 } else if (os.equals("linux")) {
                     setupDebuggerLinux();
@@ -413,7 +416,11 @@
         // configure the VM.
 
         try {
-            if (os.equals("win32")) {
+            if (os.equals("solaris")) {
+                db = new HotSpotTypeDataBase(machDesc,
+                new HotSpotSolarisVtblAccess(debugger, jvmLibNames),
+                debugger, jvmLibNames);
+            } else if (os.equals("win32")) {
                 db = new HotSpotTypeDataBase(machDesc,
                 new Win32VtblAccess(debugger, jvmLibNames),
                 debugger, jvmLibNames);
@@ -498,6 +505,29 @@
         System.err.println("Loaded alternate HotSpot SA Debugger: " + alternateName);
     }
 
+    //
+    // Solaris
+    //
+
+    private void setupDebuggerSolaris() {
+        setupJVMLibNamesSolaris();
+        ProcDebuggerLocal dbg = new ProcDebuggerLocal(null, true);
+        debugger = dbg;
+        attachDebugger();
+
+        // Set up CPU-dependent stuff
+        if (cpu.equals("x86")) {
+            machDesc = new MachineDescriptionIntelX86();
+        } else if (cpu.equals("amd64")) {
+            machDesc = new MachineDescriptionAMD64();
+        } else {
+            throw new DebuggerException("Solaris only supported on x86/amd64");
+        }
+
+        dbg.setMachineDescription(machDesc);
+        return;
+    }
+
     private void connectRemoteDebugger() throws DebuggerException {
         RemoteDebugger remote =
         (RemoteDebugger) RMIHelper.lookup(debugServerID);
@@ -509,7 +539,9 @@
     }
 
     private void setupJVMLibNames(String os) {
-        if (os.equals("win32")) {
+        if (os.equals("solaris")) {
+            setupJVMLibNamesSolaris();
+        } else if (os.equals("win32")) {
             setupJVMLibNamesWin32();
         } else if (os.equals("linux")) {
             setupJVMLibNamesLinux();
@@ -522,6 +554,10 @@
         }
     }
 
+    private void setupJVMLibNamesSolaris() {
+        jvmLibNames = new String[] { "libjvm.so" };
+    }
+
     //
     // Win32
     //
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java	2024-08-17 18:29:44.572682434 +0200
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2000, 2005, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot;
+
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.types.basic.*;
+
+/** This class implements the compiler-specific access to the vtbl for
+    a given C++ type. */
+public class HotSpotSolarisVtblAccess extends BasicVtblAccess {
+
+  public HotSpotSolarisVtblAccess(SymbolLookup symbolLookup,
+                                  String[] jvmLibNames) {
+    super(symbolLookup, jvmLibNames);
+  }
+
+  protected String vtblSymbolForType(Type type) {
+    String demangledSymbol = type.getName() + "::__vtbl";
+    return mangle(demangledSymbol);
+  }
+
+  //--------------------------------------------------------------------------------
+  // Internals only below this point
+  //
+
+  private String mangle(String symbol) {
+    String[] parts = symbol.split("::");
+    StringBuffer mangled = new StringBuffer("__1c");
+    for (int i = 0; i < parts.length; i++) {
+      int len = parts[i].length();
+      if (len >= 26) {
+        mangled.append((char)('a' + (len / 26)));
+        len = len % 26;
+      }
+      mangled.append((char)('A' + len));
+      mangled.append(parts[i]);
+    }
+    mangled.append("_");
+    return mangled.toString();
+  }
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java	2024-08-17 18:29:44.574986760 +0200
@@ -0,0 +1,140 @@
+/*
+ * Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.solaris_amd64;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.amd64.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.amd64.*;
+import sun.jvm.hotspot.runtime.x86.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+import sun.jvm.hotspot.utilities.Observable;
+import sun.jvm.hotspot.utilities.Observer;
+
+public class SolarisAMD64JavaThreadPDAccess implements JavaThreadPDAccess {
+    private static AddressField lastJavaFPField;
+    private static AddressField osThreadField;
+    private static AddressField baseOfStackPointerField;
+
+    // Field from OSThread
+    private static CIntegerField osThreadThreadIDField;
+
+    // This is currently unneeded but is being kept in case we change
+    // the currentFrameGuess algorithm
+    private static final long GUESS_SCAN_RANGE = 128 * 1024;
+
+
+    static {
+        VM.registerVMInitializedObserver(new Observer() {
+            public void update(Observable o, Object data) {
+                initialize(VM.getVM().getTypeDataBase());
+            }
+        });
+    }
+
+    private static synchronized void initialize(TypeDataBase db) {
+        Type type = db.lookupType("JavaThread");
+        Type anchorType = db.lookupType("JavaFrameAnchor");
+
+        lastJavaFPField    = anchorType.getAddressField("_last_Java_fp");
+        osThreadField      = type.getAddressField("_osthread");
+
+        type = db.lookupType("OSThread");
+        osThreadThreadIDField   = type.getCIntegerField("_thread_id");
+    }
+
+    public    Address getLastJavaFP(Address addr) {
+        return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset()));
+    }
+
+    public    Address getLastJavaPC(Address addr) {
+        return null;
+    }
+
+    public Address getBaseOfStackPointer(Address addr) {
+        return null;
+    }
+
+    public Frame getLastFramePD(JavaThread thread, Address addr) {
+        Address fp = thread.getLastJavaFP();
+        if (fp == null) {
+            return null; // no information
+        }
+        Address pc =  thread.getLastJavaPC();
+        if ( pc != null ) {
+            return new X86Frame(thread.getLastJavaSP(), fp, pc);
+        } else {
+            return new X86Frame(thread.getLastJavaSP(), fp);
+        }
+    }
+
+    public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+        return new X86RegisterMap(thread, updateMap);
+    }
+
+    public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+        ThreadProxy t = getThreadProxy(addr);
+        AMD64ThreadContext context = (AMD64ThreadContext) t.getContext();
+        AMD64CurrentFrameGuess guesser = new AMD64CurrentFrameGuess(context, thread);
+        if (!guesser.run(GUESS_SCAN_RANGE)) {
+            return null;
+        }
+        if (guesser.getPC() == null) {
+            return new X86Frame(guesser.getSP(), guesser.getFP());
+        } else {
+            return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+        }
+    }
+
+
+    public void printThreadIDOn(Address addr, PrintStream tty) {
+        tty.print(getThreadProxy(addr));
+    }
+
+
+    public void printInfoOn(Address threadAddr, PrintStream tty) {
+    }
+
+    public Address getLastSP(Address addr) {
+        ThreadProxy t = getThreadProxy(addr);
+        AMD64ThreadContext context = (AMD64ThreadContext) t.getContext();
+        return context.getRegisterAsAddress(AMD64ThreadContext.RSP);
+    }
+
+    public ThreadProxy getThreadProxy(Address addr) {
+        // Fetch the OSThread (for now and for simplicity, not making a
+        // separate "OSThread" class in this package)
+        Address osThreadAddr = osThreadField.getValue(addr);
+        // Get the address of the thread ID from the OSThread
+        Address tidAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+
+        JVMDebugger debugger = VM.getVM().getDebugger();
+        return debugger.getThreadForIdentifierAddress(tidAddr);
+    }
+
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_x86/SolarisX86JavaThreadPDAccess.java	2024-08-17 18:29:44.575833484 +0200
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2000, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+package sun.jvm.hotspot.runtime.solaris_x86;
+
+import java.io.*;
+import java.util.*;
+import sun.jvm.hotspot.debugger.*;
+import sun.jvm.hotspot.debugger.x86.*;
+import sun.jvm.hotspot.runtime.*;
+import sun.jvm.hotspot.runtime.x86.*;
+import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.utilities.*;
+import sun.jvm.hotspot.utilities.Observable;
+import sun.jvm.hotspot.utilities.Observer;
+
+/** Placeholder for now to allow us to start the SA without support
+    for stack traces */
+
+public class SolarisX86JavaThreadPDAccess implements JavaThreadPDAccess {
+  private static AddressField lastJavaFPField;
+  private static AddressField osThreadField;
+  private static AddressField baseOfStackPointerField;
+
+  // Field from OSThread
+  private static CIntegerField osThreadThreadIDField;
+
+  // This is currently unneeded but is being kept in case we change
+  // the currentFrameGuess algorithm
+  private static final long GUESS_SCAN_RANGE = 128 * 1024;
+
+
+  static {
+    VM.registerVMInitializedObserver(new Observer() {
+        public void update(Observable o, Object data) {
+          initialize(VM.getVM().getTypeDataBase());
+        }
+      });
+  }
+
+  private static synchronized void initialize(TypeDataBase db) {
+    Type type = db.lookupType("JavaThread");
+    Type anchorType = db.lookupType("JavaFrameAnchor");
+
+    lastJavaFPField    = anchorType.getAddressField("_last_Java_fp");
+    osThreadField      = type.getAddressField("_osthread");
+
+    type = db.lookupType("OSThread");
+    osThreadThreadIDField   = type.getCIntegerField("_thread_id");
+  }
+
+  public    Address getLastJavaFP(Address addr) {
+    return lastJavaFPField.getValue(addr.addOffsetTo(sun.jvm.hotspot.runtime.JavaThread.getAnchorField().getOffset()));
+  }
+
+  public    Address getLastJavaPC(Address addr) {
+    return null;
+  }
+
+  public Address getBaseOfStackPointer(Address addr) {
+    return null;
+  }
+
+  public Frame getLastFramePD(JavaThread thread, Address addr) {
+    Address fp = thread.getLastJavaFP();
+    if (fp == null) {
+      return null; // no information
+    }
+    Address pc =  thread.getLastJavaPC();
+    if ( pc != null ) {
+      return new X86Frame(thread.getLastJavaSP(), fp, pc);
+    } else {
+      return new X86Frame(thread.getLastJavaSP(), fp);
+    }
+  }
+
+  public RegisterMap newRegisterMap(JavaThread thread, boolean updateMap) {
+    return new X86RegisterMap(thread, updateMap);
+  }
+
+  public Frame getCurrentFrameGuess(JavaThread thread, Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    X86ThreadContext context = (X86ThreadContext) t.getContext();
+    X86CurrentFrameGuess guesser = new X86CurrentFrameGuess(context, thread);
+    if (!guesser.run(GUESS_SCAN_RANGE)) {
+      return null;
+    }
+    if (guesser.getPC() == null) {
+      return new X86Frame(guesser.getSP(), guesser.getFP());
+    } else {
+      return new X86Frame(guesser.getSP(), guesser.getFP(), guesser.getPC());
+    }
+  }
+
+
+  public void printThreadIDOn(Address addr, PrintStream tty) {
+    tty.print(getThreadProxy(addr));
+  }
+
+
+  public void printInfoOn(Address threadAddr, PrintStream tty) {
+  }
+
+  public Address getLastSP(Address addr) {
+    ThreadProxy t = getThreadProxy(addr);
+    X86ThreadContext context = (X86ThreadContext) t.getContext();
+    return context.getRegisterAsAddress(X86ThreadContext.ESP);
+  }
+
+  public ThreadProxy getThreadProxy(Address addr) {
+    // Fetch the OSThread (for now and for simplicity, not making a
+    // separate "OSThread" class in this package)
+    Address osThreadAddr = osThreadField.getValue(addr);
+    // Get the address of the thread ID from the OSThread
+    Address tidAddr = osThreadAddr.addOffsetTo(osThreadThreadIDField.getOffset());
+
+    JVMDebugger debugger = VM.getVM().getDebugger();
+    return debugger.getThreadForIdentifierAddress(tidAddr);
+  }
+
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java	2024-08-17 18:29:44.525073600 +0200
@@ -28,6 +28,8 @@
 
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.runtime.solaris_x86.SolarisX86JavaThreadPDAccess;
+import sun.jvm.hotspot.runtime.solaris_amd64.SolarisAMD64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.win32_x86.Win32X86JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.win32_aarch64.Win32AARCH64JavaThreadPDAccess;
@@ -96,7 +98,13 @@
 
         access = null;
         // FIXME: find the platform specific PD class by reflection?
-        if (os.equals("win32")) {
+        if (os.equals("solaris")) {
+            if (cpu.equals("x86")) {
+                access = new SolarisX86JavaThreadPDAccess();
+            } else if (cpu.equals("amd64")) {
+                access = new SolarisAMD64JavaThreadPDAccess();
+            }
+        } else if (os.equals("win32")) {
             if (cpu.equals("x86")) {
                 access =  new Win32X86JavaThreadPDAccess();
             } else if (cpu.equals("amd64")) {
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java	2024-08-17 18:29:44.525573701 +0200
@@ -28,10 +28,14 @@
     system. */
 
 public class PlatformInfo {
-  /* Returns "win32" if Windows; "linux" if Linux. */
+  /* Returns "solaris" if on Solaris; "win32" if Windows; "linux" if
+     Linux. Used to determine location of dbx and import module, or
+     possible debugger agent on win32. */
   public static String getOS() throws UnsupportedPlatformException {
     String os = System.getProperty("os.name");
-    if (os.equals("Linux")) {
+    if (os.equals("SunOS")) {
+      return "solaris";
+    } else if (os.equals("Linux")) {
       return "linux";
     } else if (os.equals("FreeBSD")) {
       return "bsd";
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c	2024-08-17 18:29:44.526093018 +0200
@@ -22,6 +22,8 @@
  *
  */
 
+#include <jni.h> // just include something, or else solaris compiler will complain that this file is empty
+
 #if defined(LINUX) || defined(__APPLE__)
 #include <unistd.h>
 #include <fcntl.h>
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/share/native/libsaproc/sadis.c	2024-08-17 18:29:44.526514569 +0200
@@ -26,7 +26,7 @@
 
 /*
  *  This file implements a binding between Java and the hsdis
- *  disassembler.  It should compile on Linux and Windows.
+ *  disassembler.  It should compile on Linux/Solaris and Windows.
  *  The only platform dependent pieces of the code for doing
  *  dlopen/dlsym to find the entry point in hsdis.  All the rest is
  *  standard JNI code.
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/solaris/native/libsaproc/libproc.h jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/solaris/native/libsaproc/libproc.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/solaris/native/libsaproc/libproc.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/solaris/native/libsaproc/libproc.h	2024-08-17 18:29:44.577143567 +0200
@@ -0,0 +1,471 @@
+/*
+ * Copyright (c) 2002, 2017, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+/*
+ * Interfaces available from the process control library, libproc.
+ *
+ * libproc provides process control functions for the /proc tools
+ * (commands in /usr/proc/bin), /usr/bin/truss, and /usr/bin/gcore.
+ * libproc is a private support library for these commands only.
+ * It is _not_ a public interface, although it might become one
+ * in the fullness of time, when the interfaces settle down.
+ *
+ * In the meantime, be aware that any program linked with libproc in this
+ * release of Solaris is almost guaranteed to break in the next release.
+ *
+ * In short, do not use this header file or libproc for any purpose.
+ */
+
+#ifndef _LIBPROC_H
+#define _LIBPROC_H
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <nlist.h>
+#include <door.h>
+#include <gelf.h>
+#include <proc_service.h>
+#include <rtld_db.h>
+#include <procfs.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/auxv.h>
+#include <sys/resource.h>
+#include <sys/socket.h>
+#include <sys/utsname.h>
+
+#ifdef  __cplusplus
+extern "C" {
+#endif
+
+/*
+ * Opaque structure tag reference to a process control structure.
+ * Clients of libproc cannot look inside the process control structure.
+ * The implementation of struct ps_prochandle can change w/o affecting clients.
+ */
+struct ps_prochandle;
+
+extern  int     _libproc_debug; /* set non-zero to enable debugging fprintfs */
+
+#if defined(sparc) || defined(__sparc)
+#define R_RVAL1 R_O0            /* register holding a function return value */
+#define R_RVAL2 R_O1            /* 32 more bits for a 64-bit return value */
+#define SYSCALL32 0x91d02008    /* 32-bit syscall (ta 8) instruction */
+#define SYSCALL64 0x91d02040    /* 64-bit syscall (ta 64) instruction */
+typedef uint32_t syscall_t;     /* holds a syscall instruction */
+#endif  /* sparc */
+
+#if defined(__i386)
+#define R_PC    EIP
+#define R_SP    UESP
+#define R_RVAL1 EAX             /* register holding a function return value */
+#define R_RVAL2 EDX             /* 32 more bits for a 64-bit return value */
+#define SYSCALL 0x9a            /* syscall (lcall) instruction opcode */
+typedef uchar_t syscall_t[7];   /* holds a syscall instruction */
+#endif  /* __i386 */
+
+#define R_RVAL  R_RVAL1         /* simple function return value register */
+
+/* maximum sizes of things */
+#define PRMAXSIG        (32 * sizeof (sigset_t) / sizeof (uint32_t))
+#define PRMAXFAULT      (32 * sizeof (fltset_t) / sizeof (uint32_t))
+#define PRMAXSYS        (32 * sizeof (sysset_t) / sizeof (uint32_t))
+
+/* State values returned by Pstate() */
+#define PS_RUN          1       /* process is running */
+#define PS_STOP         2       /* process is stopped */
+#define PS_LOST         3       /* process is lost to control (EAGAIN) */
+#define PS_UNDEAD       4       /* process is terminated (zombie) */
+#define PS_DEAD         5       /* process is terminated (core file) */
+
+/* Flags accepted by Pgrab() */
+#define PGRAB_RETAIN    0x01    /* Retain tracing flags, else clear flags */
+#define PGRAB_FORCE     0x02    /* Open the process w/o O_EXCL */
+#define PGRAB_RDONLY    0x04    /* Open the process or core w/ O_RDONLY */
+#define PGRAB_NOSTOP    0x08    /* Open the process but do not stop it */
+
+/* Error codes from Pcreate() */
+#define C_STRANGE       -1      /* Unanticipated error, errno is meaningful */
+#define C_FORK          1       /* Unable to fork */
+#define C_PERM          2       /* No permission (file set-id or unreadable) */
+#define C_NOEXEC        3       /* Cannot find executable file */
+#define C_INTR          4       /* Interrupt received while creating */
+#define C_LP64          5       /* Program is _LP64, self is _ILP32 */
+
+/* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */
+#define G_STRANGE       -1      /* Unanticipated error, errno is meaningful */
+#define G_NOPROC        1       /* No such process */
+#define G_NOCORE        2       /* No such core file */
+#define G_NOPROCORCORE  3       /* No such proc or core (for proc_arg_grab) */
+#define G_NOEXEC        4       /* Cannot locate executable file */
+#define G_ZOMB          5       /* Zombie process */
+#define G_PERM          6       /* No permission */
+#define G_BUSY          7       /* Another process has control */
+#define G_SYS           8       /* System process */
+#define G_SELF          9       /* Process is self */
+#define G_INTR          10      /* Interrupt received while grabbing */
+#define G_LP64          11      /* Process is _LP64, self is ILP32 */
+#define G_FORMAT        12      /* File is not an ELF format core file */
+#define G_ELF           13      /* Libelf error, elf_errno() is meaningful */
+#define G_NOTE          14      /* Required PT_NOTE Phdr not present in core */
+
+/* Flags accepted by Prelease */
+#define PRELEASE_CLEAR  0x10    /* Clear all tracing flags */
+#define PRELEASE_RETAIN 0x20    /* Retain final tracing flags */
+#define PRELEASE_HANG   0x40    /* Leave the process stopped */
+#define PRELEASE_KILL   0x80    /* Terminate the process */
+
+typedef struct {        /* argument descriptor for system call (Psyscall) */
+        long    arg_value;      /* value of argument given to system call */
+        void    *arg_object;    /* pointer to object in controlling process */
+        char    arg_type;       /* AT_BYVAL, AT_BYREF */
+        char    arg_inout;      /* AI_INPUT, AI_OUTPUT, AI_INOUT */
+        ushort_t arg_size;      /* if AT_BYREF, size of object in bytes */
+} argdes_t;
+
+typedef struct {        /* return values from system call (Psyscall) */
+        int     sys_errno;      /* syscall error number */
+        long    sys_rval1;      /* primary return value from system call */
+        long    sys_rval2;      /* second return value from system call */
+} sysret_t;
+
+/* values for type */
+#define AT_BYVAL        1
+#define AT_BYREF        2
+
+/* values for inout */
+#define AI_INPUT        1
+#define AI_OUTPUT       2
+#define AI_INOUT        3
+
+/* maximum number of syscall arguments */
+#define MAXARGS         8
+
+/* maximum size in bytes of a BYREF argument */
+#define MAXARGL         (4*1024)
+
+/* Kludges to make things work on Solaris 2.6 */
+#if !defined(_LP64) && !defined(PR_MODEL_UNKNOWN)
+#define PR_MODEL_UNKNOWN 0
+#define PR_MODEL_ILP32  0       /* process data model is ILP32 */
+#define PR_MODEL_LP64   2       /* process data model is LP64 */
+#define PR_MODEL_NATIVE PR_MODEL_ILP32
+#define pr_dmodel       pr_filler[0]
+#define STACK_BIAS      0
+#endif
+
+/*
+ * Function prototypes for routines in the process control package.
+ */
+extern struct ps_prochandle *Pcreate(const char *, char *const *,
+    int *, char *, size_t);
+
+extern const char *Pcreate_error(int);
+
+extern struct ps_prochandle *Pgrab(pid_t, int, int *);
+extern struct ps_prochandle *Pgrab_core(const char *, const char *, int, int *);
+extern struct ps_prochandle *Pfgrab_core(int, const char *, int *);
+
+extern const char *Pgrab_error(int);
+
+extern  int     Preopen(struct ps_prochandle *);
+extern  void    Prelease(struct ps_prochandle *, int);
+extern  void    Pfree(struct ps_prochandle *);
+
+extern  int     Pasfd(struct ps_prochandle *);
+extern  int     Pctlfd(struct ps_prochandle *);
+extern  int     Pcreate_agent(struct ps_prochandle *);
+extern  void    Pdestroy_agent(struct ps_prochandle *);
+extern  int     Pwait(struct ps_prochandle *, uint_t);
+extern  int     Pstop(struct ps_prochandle *, uint_t);
+extern  int     Pstate(struct ps_prochandle *);
+extern  const psinfo_t *Ppsinfo(struct ps_prochandle *);
+extern  const pstatus_t *Pstatus(struct ps_prochandle *);
+extern  int     Pcred(struct ps_prochandle *, prcred_t *, int);
+extern  int     Pgetareg(struct ps_prochandle *, int, prgreg_t *);
+extern  int     Pputareg(struct ps_prochandle *, int, prgreg_t);
+extern  int     Psetrun(struct ps_prochandle *, int, int);
+extern  ssize_t Pread(struct ps_prochandle *, void *, size_t, uintptr_t);
+extern  ssize_t Pread_string(struct ps_prochandle *, char *, size_t, uintptr_t);
+extern  ssize_t Pwrite(struct ps_prochandle *, const void *, size_t, uintptr_t);
+extern  int     Pclearsig(struct ps_prochandle *);
+extern  int     Pclearfault(struct ps_prochandle *);
+extern  int     Psetbkpt(struct ps_prochandle *, uintptr_t, ulong_t *);
+extern  int     Pdelbkpt(struct ps_prochandle *, uintptr_t, ulong_t);
+extern  int     Pxecbkpt(struct ps_prochandle *, ulong_t);
+extern  int     Psetflags(struct ps_prochandle *, long);
+extern  int     Punsetflags(struct ps_prochandle *, long);
+extern  int     Psignal(struct ps_prochandle *, int, int);
+extern  int     Pfault(struct ps_prochandle *, int, int);
+extern  int     Psysentry(struct ps_prochandle *, int, int);
+extern  int     Psysexit(struct ps_prochandle *, int, int);
+extern  void    Psetsignal(struct ps_prochandle *, const sigset_t *);
+extern  void    Psetfault(struct ps_prochandle *, const fltset_t *);
+extern  void    Psetsysentry(struct ps_prochandle *, const sysset_t *);
+extern  void    Psetsysexit(struct ps_prochandle *, const sysset_t *);
+extern  void    Psync(struct ps_prochandle *);
+extern  sysret_t Psyscall(struct ps_prochandle *, int, uint_t, argdes_t *);
+extern  int     Pisprocdir(struct ps_prochandle *, const char *);
+
+/*
+ * Function prototypes for system calls forced on the victim process.
+ */
+extern  int     pr_open(struct ps_prochandle *, const char *, int, mode_t);
+extern  int     pr_creat(struct ps_prochandle *, const char *, mode_t);
+extern  int     pr_close(struct ps_prochandle *, int);
+extern  int     pr_door_info(struct ps_prochandle *, int, struct door_info *);
+extern  void    *pr_mmap(struct ps_prochandle *,
+                        void *, size_t, int, int, int, off_t);
+extern  void    *pr_zmap(struct ps_prochandle *,
+                        void *, size_t, int, int);
+extern  int     pr_munmap(struct ps_prochandle *, void *, size_t);
+extern  int     pr_memcntl(struct ps_prochandle *,
+                        caddr_t, size_t, int, caddr_t, int, int);
+extern  int     pr_sigaction(struct ps_prochandle *,
+                        int, const struct sigaction *, struct sigaction *);
+extern  int     pr_getitimer(struct ps_prochandle *,
+                        int, struct itimerval *);
+extern  int     pr_setitimer(struct ps_prochandle *,
+                        int, const struct itimerval *, struct itimerval *);
+extern  int     pr_ioctl(struct ps_prochandle *, int, int, void *, size_t);
+extern  int     pr_fcntl(struct ps_prochandle *, int, int, void *);
+extern  int     pr_stat(struct ps_prochandle *, const char *, struct stat *);
+extern  int     pr_lstat(struct ps_prochandle *, const char *, struct stat *);
+extern  int     pr_fstat(struct ps_prochandle *, int, struct stat *);
+extern  int     pr_statvfs(struct ps_prochandle *, const char *, statvfs_t *);
+extern  int     pr_fstatvfs(struct ps_prochandle *, int, statvfs_t *);
+extern  int     pr_getrlimit(struct ps_prochandle *,
+                        int, struct rlimit *);
+extern  int     pr_setrlimit(struct ps_prochandle *,
+                        int, const struct rlimit *);
+#if defined(_LARGEFILE64_SOURCE)
+extern  int     pr_getrlimit64(struct ps_prochandle *,
+                        int, struct rlimit64 *);
+extern  int     pr_setrlimit64(struct ps_prochandle *,
+                        int, const struct rlimit64 *);
+#endif  /* _LARGEFILE64_SOURCE */
+extern  int     pr_lwp_exit(struct ps_prochandle *);
+extern  int     pr_exit(struct ps_prochandle *, int);
+extern  int     pr_waitid(struct ps_prochandle *,
+                        idtype_t, id_t, siginfo_t *, int);
+extern  off_t   pr_lseek(struct ps_prochandle *, int, off_t, int);
+extern  offset_t pr_llseek(struct ps_prochandle *, int, offset_t, int);
+extern  int     pr_rename(struct ps_prochandle *, const char *, const char *);
+extern  int     pr_link(struct ps_prochandle *, const char *, const char *);
+extern  int     pr_unlink(struct ps_prochandle *, const char *);
+extern  int     pr_getpeername(struct ps_prochandle *,
+                        int, struct sockaddr *, socklen_t *);
+extern  int     pr_getsockname(struct ps_prochandle *,
+                        int, struct sockaddr *, socklen_t *);
+
+/*
+ * Function prototypes for accessing per-LWP register information.
+ */
+extern int Plwp_getregs(struct ps_prochandle *, lwpid_t, prgregset_t);
+extern int Plwp_setregs(struct ps_prochandle *, lwpid_t, const prgregset_t);
+
+extern int Plwp_getfpregs(struct ps_prochandle *, lwpid_t, prfpregset_t *);
+extern int Plwp_setfpregs(struct ps_prochandle *, lwpid_t,
+    const prfpregset_t *);
+
+extern int Plwp_getpsinfo(struct ps_prochandle *, lwpid_t, lwpsinfo_t *);
+
+/*
+ * LWP iteration interface.
+ */
+typedef int proc_lwp_f(void *, const lwpstatus_t *);
+extern int Plwp_iter(struct ps_prochandle *, proc_lwp_f *, void *);
+
+/*
+ * Symbol table interfaces.
+ */
+
+/*
+ * Pseudo-names passed to Plookup_by_name() for well-known load objects.
+ * NOTE: It is required that PR_OBJ_EXEC and PR_OBJ_LDSO exactly match
+ * the definitions of PS_OBJ_EXEC and PS_OBJ_LDSO from <proc_service.h>.
+ */
+#define PR_OBJ_EXEC     ((const char *)0)       /* search the executable file */
+#define PR_OBJ_LDSO     ((const char *)1)       /* search ld.so.1 */
+#define PR_OBJ_EVERY    ((const char *)-1)      /* search every load object */
+
+/*
+ * 'object_name' is the name of a load object obtained from an
+ * iteration over the process's address space mappings (Pmapping_iter),
+ * or an iteration over the process's mapped objects (Pobject_iter),
+ * or else it is one of the special PR_OBJ_* values above.
+ */
+extern int Plookup_by_name(struct ps_prochandle *,
+    const char *, const char *, GElf_Sym *);
+
+extern int Plookup_by_addr(struct ps_prochandle *,
+    uintptr_t, char *, size_t, GElf_Sym *);
+
+typedef int proc_map_f(void *, const prmap_t *, const char *);
+
+extern int Pmapping_iter(struct ps_prochandle *, proc_map_f *, void *);
+extern int Pobject_iter(struct ps_prochandle *, proc_map_f *, void *);
+
+extern const prmap_t *Paddr_to_map(struct ps_prochandle *, uintptr_t);
+extern const prmap_t *Paddr_to_text_map(struct ps_prochandle *, uintptr_t);
+extern const prmap_t *Pname_to_map(struct ps_prochandle *, const char *);
+
+extern char *Pplatform(struct ps_prochandle *, char *, size_t);
+extern int Puname(struct ps_prochandle *, struct utsname *);
+
+extern char *Pexecname(struct ps_prochandle *, char *, size_t);
+extern char *Pobjname(struct ps_prochandle *, uintptr_t, char *, size_t);
+
+extern char *Pgetenv(struct ps_prochandle *, const char *, char *, size_t);
+extern long Pgetauxval(struct ps_prochandle *, int);
+
+/*
+ * Symbol table iteration interface.
+ */
+typedef int proc_sym_f(void *, const GElf_Sym *, const char *);
+
+extern int Psymbol_iter(struct ps_prochandle *,
+    const char *, int, int, proc_sym_f *, void *);
+
+/*
+ * 'which' selects which symbol table and can be one of the following.
+ */
+#define PR_SYMTAB       1
+#define PR_DYNSYM       2
+/*
+ * 'type' selects the symbols of interest by binding and type.  It is a bit-
+ * mask of one or more of the following flags, whose order MUST match the
+ * order of STB and STT constants in <sys/elf.h>.
+ */
+#define BIND_LOCAL      0x0001
+#define BIND_GLOBAL     0x0002
+#define BIND_WEAK       0x0004
+#define BIND_ANY (BIND_LOCAL|BIND_GLOBAL|BIND_WEAK)
+#define TYPE_NOTYPE     0x0100
+#define TYPE_OBJECT     0x0200
+#define TYPE_FUNC       0x0400
+#define TYPE_SECTION    0x0800
+#define TYPE_FILE       0x1000
+#define TYPE_ANY (TYPE_NOTYPE|TYPE_OBJECT|TYPE_FUNC|TYPE_SECTION|TYPE_FILE)
+
+/*
+ * This returns the rtld_db agent handle for the process.
+ * The handle will become invalid at the next successful exec() and
+ * must not be used beyond that point (see Preset_maps(), below).
+ */
+extern rd_agent_t *Prd_agent(struct ps_prochandle *);
+
+/*
+ * This should be called when an RD_DLACTIVITY event with the
+ * RD_CONSISTENT state occurs via librtld_db's event mechanism.
+ * This makes libproc's address space mappings and symbol tables current.
+ */
+extern void Pupdate_maps(struct ps_prochandle *);
+
+/*
+ * This must be called after the victim process performs a successful
+ * exec() if any of the symbol table interface functions have been called
+ * prior to that point.  This is essential because an exec() invalidates
+ * all previous symbol table and address space mapping information.
+ * It is always safe to call, but if it is called other than after an
+ * exec() by the victim process it just causes unnecessary overhead.
+ *
+ * The rtld_db agent handle obtained from a previous call to Prd_agent() is
+ * made invalid by Preset_maps() and Prd_agent() must be called again to get
+ * the new handle.
+ */
+extern void Preset_maps(struct ps_prochandle *);
+
+/*
+ * Given an address, Ppltdest() determines if this is part of a PLT, and if
+ * so returns the target address of this PLT entry and a flag indicating
+ * whether or not this PLT entry has been bound by the run-time linker.
+ */
+extern uintptr_t Ppltdest(struct ps_prochandle *, uintptr_t, int *);
+
+/*
+ * Stack frame iteration interface.
+ */
+typedef int proc_stack_f(
+    void *,             /* the cookie given to Pstack_iter() */
+    const prgregset_t,  /* the frame's registers */
+    uint_t,             /* argc for the frame's function */
+    const long *,       /* argv for the frame's function */
+    int,                /* bitwise flags describing the frame (see below) */
+    int);               /* a signal number */
+
+#define PR_SIGNAL_FRAME    1    /* called by a signal handler */
+#define PR_FOUND_SIGNAL    2    /* we found the corresponding signal number */
+
+extern int Pstack_iter(struct ps_prochandle *,
+    const prgregset_t, proc_stack_f *, void *);
+
+/*
+ * Compute the full pathname of a named directory without using chdir().
+ * This is useful for dealing with /proc/<pid>/cwd.
+ */
+extern char *proc_dirname(const char *, char *, size_t);
+
+/*
+ * Remove unprintable characters from psinfo.pr_psargs and replace with
+ * whitespace characters so it is safe for printing.
+ */
+extern void proc_unctrl_psinfo(psinfo_t *);
+
+/*
+ * Utility functions for processing arguments which should be /proc files,
+ * pids, and/or core files.  The returned error code can be passed to
+ * Pgrab_error() in order to convert it to an error string.
+ */
+#define PR_ARG_PIDS     0x1     /* Allow pid and /proc file arguments */
+#define PR_ARG_CORES    0x2     /* Allow core file arguments */
+
+#define PR_ARG_ANY      (PR_ARG_PIDS | PR_ARG_CORES)
+
+extern struct ps_prochandle *proc_arg_grab(const char *, int, int, int *);
+extern pid_t proc_arg_psinfo(const char *, int, psinfo_t *, int *);
+
+/*
+ * Utility functions for obtaining information via /proc without actually
+ * performing a Pcreate() or Pgrab():
+ */
+extern int proc_get_auxv(pid_t, auxv_t *, int);
+extern int proc_get_cred(pid_t, prcred_t *, int);
+extern int proc_get_psinfo(pid_t, psinfo_t *);
+extern int proc_get_status(pid_t, pstatus_t *);
+
+/*
+ * Utility functions for debugging tools to convert numeric fault,
+ * signal, and system call numbers to symbolic names:
+ */
+extern char *proc_fltname(int, char *, size_t);
+extern char *proc_signame(int, char *, size_t);
+extern char *proc_sysname(int, char *, size_t);
+
+#ifdef  __cplusplus
+}
+#endif
+
+#endif  /* _LIBPROC_H */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/solaris/native/libsaproc/salibproc.h jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/solaris/native/libsaproc/salibproc.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/solaris/native/libsaproc/salibproc.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/solaris/native/libsaproc/salibproc.h	2024-08-17 18:29:44.577711269 +0200
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2003, 2016, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+#ifndef _SALIBPROC_H_
+#define _SALIBPROC_H_
+
+/*
+ * The following definitions, prototypes are from Solaris libproc.h.
+ * We used to use the copy of it from Solaris 8.0. But there are
+ * problems with that approach in building this library across Solaris
+ * versions.  Solaris 10 has libproc.h in /usr/include. And libproc.h
+ * varies slightly across Solaris versions. On Solaris 9, we get
+ * 'sysret_t multiply defined' error. This is common minimum subset we
+ * really need from libproc.h. The libproc.h in the current dir has
+ * been left for reference and not used in build.
+ */
+
+#include <dlfcn.h>
+#include <gelf.h>
+#include <procfs.h>
+#include <proc_service.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/* extended symbol table information */
+typedef struct {
+        const char      *prs_object;            /* object name */
+        const char      *prs_name;              /* symbol name */
+        Lmid_t          prs_lmid;               /* link map id */
+        uint_t          prs_id;                 /* symbol id */
+        uint_t          prs_table;              /* symbol table id */
+} prsyminfo_t;
+
+typedef struct ps_prochandle ps_prochandle_t;
+
+/*
+ * 'object_name' is the name of a load object obtained from an
+ * iteration over the process's address space mappings (Pmapping_iter),
+ * or an iteration over the process's mapped objects (Pobject_iter),
+ * or else it is one of the special PR_OBJ_* values above.
+ */
+
+extern int Plookup_by_addr(ps_prochandle_t *, uintptr_t, char *,
+                           size_t, GElf_Sym *, prsyminfo_t *);
+extern ps_prochandle_t *proc_arg_grab(const char *, int, int,
+                                      int *, const char **);
+
+typedef int proc_map_f(void *, const prmap_t *, const char *);
+extern int Pobject_iter(struct ps_prochandle *, proc_map_f *, void *);
+
+/*
+ * Utility functions for processing arguments which should be /proc files,
+ * pids, and/or core files.  The returned error code can be passed to
+ * Pgrab_error() in order to convert it to an error string.
+ */
+#define PR_ARG_PIDS     0x1     /* Allow pid and /proc file arguments */
+#define PR_ARG_CORES    0x2     /* Allow core file arguments */
+#define PR_ARG_ANY      (PR_ARG_PIDS | PR_ARG_CORES)
+
+/* Flags accepted by Pgrab() (partial) */
+#define PGRAB_FORCE     0x02    /* Open the process w/o O_EXCL */
+
+/* Error codes from Pgrab(), Pfgrab_core(), and Pgrab_core() */
+#define G_STRANGE       -1      /* Unanticipated error, errno is meaningful */
+#define G_NOPROC        1       /* No such process */
+#define G_NOCORE        2       /* No such core file */
+#define G_NOPROCORCORE  3       /* No such proc or core (for proc_arg_grab) */
+#define G_NOEXEC        4       /* Cannot locate executable file */
+#define G_ZOMB          5       /* Zombie process */
+#define G_PERM          6       /* No permission */
+#define G_BUSY          7       /* Another process has control */
+#define G_SYS           8       /* System process */
+#define G_SELF          9       /* Process is self */
+#define G_INTR          10      /* Interrupt received while grabbing */
+#define G_LP64          11      /* Process is _LP64, self is ILP32 */
+#define G_FORMAT        12      /* File is not an ELF format core file */
+#define G_ELF           13      /* Libelf error, elf_errno() is meaningful */
+#define G_NOTE          14      /* Required PT_NOTE Phdr not present in core */
+
+extern  const pstatus_t *Pstatus(struct ps_prochandle *);
+
+/* Flags accepted by Prelease (partial) */
+#define PRELEASE_CLEAR  0x10    /* Clear all tracing flags */
+
+extern  void    Prelease(struct ps_prochandle *, int);
+extern  int     Psetrun(struct ps_prochandle *, int, int);
+extern  int     Pstop(struct ps_prochandle *, uint_t);
+
+/*
+ * Stack frame iteration interface.
+ */
+typedef int proc_stack_f(
+    void *,             /* the cookie given to Pstack_iter() */
+    const prgregset_t,  /* the frame's registers */
+    uint_t,             /* argc for the frame's function */
+    const long *,       /* argv for the frame's function */
+    int,                /* bitwise flags describing the frame (see below) */
+    int);               /* a signal number */
+
+#define PR_SIGNAL_FRAME    1    /* called by a signal handler */
+#define PR_FOUND_SIGNAL    2    /* we found the corresponding signal number */
+
+extern int Pstack_iter(struct ps_prochandle *,
+    const prgregset_t, proc_stack_f *, void *);
+
+#define PR_OBJ_EVERY    ((const char *)-1)      /* search every load object */
+
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* _SALIBPROC_H_ */
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/solaris/native/libsaproc/saproc.cpp	2024-08-17 18:29:44.579327412 +0200
@@ -0,0 +1,1292 @@
+/*
+ * Copyright (c) 2002, 2020, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ *
+ */
+
+#include "salibproc.h"
+#include "sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal.h"
+#include <thread_db.h>
+#include <strings.h>
+#include <limits.h>
+#include <demangle.h>
+#include <stdarg.h>
+#include <stdlib.h>
+#include <errno.h>
+#include "cds.h"
+
+#define CHECK_EXCEPTION_(value) if(env->ExceptionOccurred()) { return value; }
+#define CHECK_EXCEPTION if(env->ExceptionOccurred()) { return;}
+#define THROW_NEW_DEBUGGER_EXCEPTION_(str, value) { throwNewDebuggerException(env, str); return value; }
+#define THROW_NEW_DEBUGGER_EXCEPTION(str) { throwNewDebuggerException(env, str); return;}
+
+#define SYMBOL_BUF_SIZE  256
+#define ERR_MSG_SIZE     (PATH_MAX + 256)
+
+// debug modes
+static int _libsaproc_debug = 0;
+
+static void print_debug(const char* format,...) {
+  if (_libsaproc_debug) {
+    va_list alist;
+
+    va_start(alist, format);
+    fputs("libsaproc DEBUG: ", stderr);
+    vfprintf(stderr, format, alist);
+    va_end(alist);
+  }
+}
+
+struct Debugger {
+    JNIEnv* env;
+    jobject this_obj;
+};
+
+struct DebuggerWithObject : Debugger {
+    jobject obj;
+};
+
+struct DebuggerWith2Objects : DebuggerWithObject {
+    jobject obj2;
+};
+
+/*
+* Portions of user thread level detail gathering code is from pstack source
+* code. See pstack.c in Solaris 2.8 user commands source code.
+*/
+
+static void throwNewDebuggerException(JNIEnv* env, const char* errMsg) {
+  jclass clazz = env->FindClass("sun/jvm/hotspot/debugger/DebuggerException");
+  CHECK_EXCEPTION;
+  env->ThrowNew(clazz, errMsg);
+}
+
+// JNI ids for some fields, methods
+
+// libproc handler pointer
+static jfieldID p_ps_prochandle_ID = 0;
+
+// libthread.so dlopen handle, thread agent ptr and function pointers
+static jfieldID libthread_db_handle_ID   = 0;
+static jfieldID p_td_thragent_t_ID       = 0;
+static jfieldID p_td_init_ID             = 0;
+static jfieldID p_td_ta_new_ID           = 0;
+static jfieldID p_td_ta_delete_ID        = 0;
+static jfieldID p_td_ta_thr_iter_ID      = 0;
+static jfieldID p_td_thr_get_info_ID     = 0;
+static jfieldID p_td_ta_map_id2thr_ID    = 0;
+static jfieldID p_td_thr_getgregs_ID     = 0;
+
+// reg index fields
+static jfieldID pcRegIndex_ID            = 0;
+static jfieldID fpRegIndex_ID            = 0;
+
+// part of the class sharing workaround
+static jfieldID classes_jsa_fd_ID        = 0;
+static jfieldID p_file_map_header_ID     = 0;
+
+// method ids
+
+static jmethodID getThreadForThreadId_ID = 0;
+static jmethodID createSenderFrame_ID    = 0;
+static jmethodID createClosestSymbol_ID  = 0;
+static jmethodID listAdd_ID              = 0;
+
+/*
+ * Functions we need from libthread_db
+ */
+typedef td_err_e
+        (*p_td_init_t)(void);
+typedef td_err_e
+        (*p_td_ta_new_t)(void *, td_thragent_t **);
+typedef td_err_e
+        (*p_td_ta_delete_t)(td_thragent_t *);
+typedef td_err_e
+        (*p_td_ta_thr_iter_t)(const td_thragent_t *, td_thr_iter_f *, void *,
+                td_thr_state_e, int, sigset_t *, unsigned);
+typedef td_err_e
+        (*p_td_thr_get_info_t)(const td_thrhandle_t *, td_thrinfo_t *);
+typedef td_err_e
+        (*p_td_ta_map_id2thr_t)(const td_thragent_t *, thread_t,  td_thrhandle_t *);
+typedef td_err_e
+        (*p_td_thr_getgregs_t)(const td_thrhandle_t *, prgregset_t);
+
+static void
+clear_libthread_db_ptrs(JNIEnv* env, jobject this_obj) {
+  // release libthread_db agent, if we had created
+  p_td_ta_delete_t p_td_ta_delete = 0;
+  p_td_ta_delete = (p_td_ta_delete_t) env->GetLongField(this_obj, p_td_ta_delete_ID);
+
+  td_thragent_t *p_td_thragent_t = 0;
+  p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
+  if (p_td_thragent_t != 0 && p_td_ta_delete != 0) {
+     p_td_ta_delete(p_td_thragent_t);
+  }
+
+  // dlclose libthread_db.so
+  void* libthread_db_handle = (void*) env->GetLongField(this_obj, libthread_db_handle_ID);
+  if (libthread_db_handle != 0) {
+    dlclose(libthread_db_handle);
+  }
+
+  env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_init_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)0);
+  env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)0);
+}
+
+
+static void detach_internal(JNIEnv* env, jobject this_obj) {
+  // clear libthread_db stuff
+  clear_libthread_db_ptrs(env, this_obj);
+
+  // release ptr to ps_prochandle
+  jlong p_ps_prochandle;
+  p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+  if (p_ps_prochandle != 0L) {
+    Prelease((struct ps_prochandle*) p_ps_prochandle, PRELEASE_CLEAR);
+  }
+
+  // part of the class sharing workaround
+  int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
+  if (classes_jsa_fd != -1) {
+    close(classes_jsa_fd);
+    CDSFileMapHeaderBase* pheader = (CDSFileMapHeaderBase*) env->GetLongField(this_obj, p_file_map_header_ID);
+    if (pheader != NULL) {
+      free(pheader);
+    }
+  }
+}
+
+// Is it okay to ignore libthread_db failure? Set env var to ignore
+// libthread_db failure. You can still debug, but will miss threads
+// related functionality.
+static bool sa_ignore_threaddb = (getenv("SA_IGNORE_THREADDB") != 0);
+
+#define HANDLE_THREADDB_FAILURE(msg)          \
+  if (sa_ignore_threaddb) {                   \
+     printf("libsaproc WARNING: %s\n", msg);  \
+     return;                                  \
+  } else {                                    \
+     THROW_NEW_DEBUGGER_EXCEPTION(msg);       \
+  }
+
+#define HANDLE_THREADDB_FAILURE_(msg, ret)    \
+  if (sa_ignore_threaddb) {                   \
+     printf("libsaproc WARNING: %s\n", msg);  \
+     return ret;                              \
+  } else {                                    \
+     THROW_NEW_DEBUGGER_EXCEPTION_(msg, ret); \
+  }
+
+static const char * alt_root = NULL;
+static int alt_root_len = -1;
+
+#define SA_ALTROOT "SA_ALTROOT"
+
+static void init_alt_root() {
+  if (alt_root_len == -1) {
+    alt_root = getenv(SA_ALTROOT);
+    if (alt_root)
+      alt_root_len = strlen(alt_root);
+    else
+      alt_root_len = 0;
+  }
+}
+
+// This function is a complete substitute for the open system call
+// since it's also used to override open calls from libproc to
+// implement as a pathmap style facility for the SA.  If libproc
+// starts using other interfaces then this might have to extended to
+// cover other calls.
+extern "C" JNIEXPORT int JNICALL
+libsaproc_open(const char * name, int oflag, ...) {
+  if (oflag == O_RDONLY) {
+    init_alt_root();
+
+    if (_libsaproc_debug) {
+      printf("libsaproc DEBUG: libsaproc_open %s\n", name);
+    }
+
+    if (alt_root_len > 0) {
+      int fd = -1;
+      char alt_path[PATH_MAX+1];
+
+      strcpy(alt_path, alt_root);
+      strcat(alt_path, name);
+      fd = open(alt_path, O_RDONLY);
+      if (fd >= 0) {
+        if (_libsaproc_debug) {
+          printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);
+        }
+        return fd;
+      }
+
+      if (strrchr(name, '/')) {
+        strcpy(alt_path, alt_root);
+        strcat(alt_path, strrchr(name, '/'));
+        fd = open(alt_path, O_RDONLY);
+        if (fd >= 0) {
+          if (_libsaproc_debug) {
+            printf("libsaproc DEBUG: libsaproc_open substituted %s\n", alt_path);
+          }
+          return fd;
+        }
+      }
+    }
+  }
+
+  {
+    mode_t mode;
+    va_list ap;
+    va_start(ap, oflag);
+    mode = va_arg(ap, mode_t);
+    va_end(ap);
+
+    return open(name, oflag, mode);
+  }
+}
+
+
+static void * pathmap_dlopen(const char * name, int mode) {
+  init_alt_root();
+
+  if (_libsaproc_debug) {
+    printf("libsaproc DEBUG: pathmap_dlopen %s\n", name);
+  }
+
+  void * handle = NULL;
+  if (alt_root_len > 0) {
+    char alt_path[PATH_MAX+1];
+    strcpy(alt_path, alt_root);
+    strcat(alt_path, name);
+    handle = dlopen(alt_path, mode);
+    if (_libsaproc_debug && handle) {
+      printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
+    }
+
+    if (handle == NULL && strrchr(name, '/')) {
+      strcpy(alt_path, alt_root);
+      strcat(alt_path, strrchr(name, '/'));
+      handle = dlopen(alt_path, mode);
+      if (_libsaproc_debug && handle) {
+        printf("libsaproc DEBUG: pathmap_dlopen substituted %s\n", alt_path);
+      }
+    }
+  }
+  if (handle == NULL) {
+    handle = dlopen(name, mode);
+  }
+  if (_libsaproc_debug) {
+    printf("libsaproc DEBUG: pathmap_dlopen %s return 0x%lx\n", name, (unsigned long) handle);
+  }
+  return handle;
+}
+
+// libproc and libthread_db callback functions
+
+extern "C" {
+
+static int
+init_libthread_db_ptrs(void *cd, const prmap_t *pmp, const char *object_name) {
+  Debugger* dbg = (Debugger*) cd;
+  JNIEnv* env = dbg->env;
+  jobject this_obj = dbg->this_obj;
+  struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
+
+  char *s1 = 0, *s2 = 0;
+  char libthread_db[PATH_MAX];
+
+  if (strstr(object_name, "/libthread.so.") == NULL)
+     return (0);
+
+  /*
+   * We found a libthread.
+   * dlopen() the matching libthread_db and get the thread agent handle.
+   */
+  if (Pstatus(ph)->pr_dmodel == PR_MODEL_NATIVE) {
+     (void) strcpy(libthread_db, object_name);
+     s1 = (char*) strstr(object_name, ".so.");
+     s2 = (char*) strstr(libthread_db, ".so.");
+     (void) strcpy(s2, "_db");
+     s2 += 3;
+     (void) strcpy(s2, s1);
+  } else {
+#ifdef _LP64
+     /*
+      * The victim process is 32-bit, we are 64-bit.
+      * We have to find the 64-bit version of libthread_db
+      * that matches the victim's 32-bit version of libthread.
+      */
+     (void) strcpy(libthread_db, object_name);
+     s1 = (char*) strstr(object_name, "/libthread.so.");
+     s2 = (char*) strstr(libthread_db, "/libthread.so.");
+     (void) strcpy(s2, "/64");
+     s2 += 3;
+     (void) strcpy(s2, s1);
+     s1 = (char*) strstr(s1, ".so.");
+     s2 = (char*) strstr(s2, ".so.");
+     (void) strcpy(s2, "_db");
+     s2 += 3;
+     (void) strcpy(s2, s1);
+#else
+     return (0);
+#endif  /* _LP64 */
+  }
+
+  void* libthread_db_handle = 0;
+  if ((libthread_db_handle = pathmap_dlopen(libthread_db, RTLD_LAZY|RTLD_LOCAL)) == NULL) {
+     char errMsg[PATH_MAX + 256];
+     sprintf(errMsg, "Can't load %s!", libthread_db);
+     HANDLE_THREADDB_FAILURE_(errMsg, 0);
+  }
+  env->SetLongField(this_obj, libthread_db_handle_ID, (jlong)(uintptr_t)libthread_db_handle);
+
+  void* tmpPtr = 0;
+  tmpPtr = dlsym(libthread_db_handle, "td_init");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_init!", 0);
+  }
+  env->SetLongField(this_obj, p_td_init_ID, (jlong)(uintptr_t) tmpPtr);
+
+  tmpPtr =dlsym(libthread_db_handle, "td_ta_new");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_new!", 0);
+  }
+  env->SetLongField(this_obj, p_td_ta_new_ID, (jlong)(uintptr_t) tmpPtr);
+
+  tmpPtr = dlsym(libthread_db_handle, "td_ta_delete");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_delete!", 0);
+  }
+  env->SetLongField(this_obj, p_td_ta_delete_ID, (jlong)(uintptr_t) tmpPtr);
+
+  tmpPtr = dlsym(libthread_db_handle, "td_ta_thr_iter");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_thr_iter!", 0);
+  }
+  env->SetLongField(this_obj, p_td_ta_thr_iter_ID, (jlong)(uintptr_t) tmpPtr);
+
+  tmpPtr = dlsym(libthread_db_handle, "td_thr_get_info");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_get_info!", 0);
+  }
+  env->SetLongField(this_obj, p_td_thr_get_info_ID, (jlong)(uintptr_t) tmpPtr);
+
+  tmpPtr = dlsym(libthread_db_handle, "td_ta_map_id2thr");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_ta_map_id2thr!", 0);
+  }
+  env->SetLongField(this_obj, p_td_ta_map_id2thr_ID, (jlong)(uintptr_t) tmpPtr);
+
+  tmpPtr = dlsym(libthread_db_handle, "td_thr_getgregs");
+  if (tmpPtr == 0) {
+     HANDLE_THREADDB_FAILURE_("dlsym failed on td_thr_getgregs!", 0);
+  }
+  env->SetLongField(this_obj, p_td_thr_getgregs_ID, (jlong)(uintptr_t) tmpPtr);
+
+  return 1;
+}
+
+static int
+fill_thread_list(const td_thrhandle_t *p_td_thragent_t, void* cd) {
+  DebuggerWithObject* dbgo = (DebuggerWithObject*) cd;
+  JNIEnv* env = dbgo->env;
+  jobject this_obj = dbgo->this_obj;
+  jobject list = dbgo->obj;
+
+  td_thrinfo_t thrinfo;
+  p_td_thr_get_info_t p_td_thr_get_info = (p_td_thr_get_info_t) env->GetLongField(this_obj, p_td_thr_get_info_ID);
+
+  if (p_td_thr_get_info(p_td_thragent_t, &thrinfo) != TD_OK)
+    return (0);
+
+  jobject threadProxy = env->CallObjectMethod(this_obj, getThreadForThreadId_ID, (jlong)(uintptr_t) thrinfo.ti_tid);
+  CHECK_EXCEPTION_(1);
+  env->CallBooleanMethod(list, listAdd_ID, threadProxy);
+  CHECK_EXCEPTION_(1);
+  return 0;
+}
+
+// Pstack_iter() proc_stack_f callback prior to Nevada-B159
+static int
+fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc, const long *argv) {
+  DebuggerWith2Objects* dbgo2 = (DebuggerWith2Objects*) cd;
+  JNIEnv* env = dbgo2->env;
+  jobject this_obj = dbgo2->this_obj;
+  jobject curFrame = dbgo2->obj2;
+
+  jint pcRegIndex = env->GetIntField(this_obj, pcRegIndex_ID);
+  jint fpRegIndex = env->GetIntField(this_obj, fpRegIndex_ID);
+
+  jlong pc = (jlong) (uintptr_t) regs[pcRegIndex];
+  jlong fp = (jlong) (uintptr_t) regs[fpRegIndex];
+
+  dbgo2->obj2 = env->CallObjectMethod(this_obj, createSenderFrame_ID,
+                                    curFrame, pc, fp);
+  CHECK_EXCEPTION_(1);
+  if (dbgo2->obj == 0) {
+     dbgo2->obj = dbgo2->obj2;
+  }
+  return 0;
+}
+
+// Pstack_iter() proc_stack_f callback in Nevada-B159 or later
+/*ARGSUSED*/
+static int
+wrapper_fill_cframe_list(void *cd, const prgregset_t regs, uint_t argc,
+                         const long *argv, int frame_flags, int sig) {
+  return(fill_cframe_list(cd, regs, argc, argv));
+}
+
+//---------------------------------------------------------------
+// Part of the class sharing workaround:
+//
+// With class sharing, pages are mapped from classes.jsa file.
+// The read-only class sharing pages are mapped as MAP_SHARED,
+// PROT_READ pages. These pages are not dumped into core dump.
+// With this workaround, these pages are read from classes.jsa.
+
+static bool
+read_jboolean(struct ps_prochandle* ph, psaddr_t addr, jboolean* pvalue) {
+  jboolean i;
+  if (ps_pread(ph, addr, &i, sizeof(i)) == PS_OK) {
+    *pvalue = i;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static bool
+read_pointer(struct ps_prochandle* ph, psaddr_t addr, uintptr_t* pvalue) {
+  uintptr_t uip;
+  if (ps_pread(ph, addr, &uip, sizeof(uip)) == PS_OK) {
+    *pvalue = uip;
+    return true;
+  } else {
+    return false;
+  }
+}
+
+static bool
+read_string(struct ps_prochandle* ph, psaddr_t addr, char* buf, size_t size) {
+  char ch = ' ';
+  size_t i = 0;
+
+  while (ch != '\0') {
+    if (ps_pread(ph, addr, &ch, sizeof(ch)) != PS_OK)
+      return false;
+
+    if (i < size - 1) {
+      buf[i] = ch;
+    } else { // smaller buffer
+      return false;
+    }
+
+    i++; addr++;
+  }
+
+  buf[i] = '\0';
+  return true;
+}
+
+#define USE_SHARED_SPACES_SYM   "UseSharedSpaces"
+#define SHARED_BASE_ADDRESS_SYM "SharedBaseAddress"
+// mangled symbol name for Arguments::SharedArchivePath
+#define SHARED_ARCHIVE_PATH_SYM "__1cJArgumentsRSharedArchivePath_"
+
+static uintptr_t sharedBaseAddress = 0;
+static int
+init_classsharing_workaround(void *cd, const prmap_t* pmap, const char* obj_name) {
+  Debugger* dbg = (Debugger*) cd;
+  JNIEnv*   env = dbg->env;
+  jobject this_obj = dbg->this_obj;
+  const char* jvm_name = 0;
+  if ((jvm_name = strstr(obj_name, "libjvm.so")) != NULL) {
+    jvm_name = obj_name;
+  } else {
+    return 0;
+  }
+
+  struct ps_prochandle* ph = (struct ps_prochandle*) env->GetLongField(this_obj, p_ps_prochandle_ID);
+
+  // initialize classes.jsa file descriptor field.
+  dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, -1);
+
+  // check whether class sharing is on by reading variable "UseSharedSpaces"
+  psaddr_t useSharedSpacesAddr = 0;
+  ps_pglobal_lookup(ph, jvm_name, USE_SHARED_SPACES_SYM, &useSharedSpacesAddr);
+  if (useSharedSpacesAddr == 0) {
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'UseSharedSpaces' flag\n", 1);
+  }
+
+  // read the value of the flag "UseSharedSpaces"
+  // Since hotspot types are not available to build this library. So
+  // equivalent type "jboolean" is used to read the value of "UseSharedSpaces"
+  // which is same as hotspot type "bool".
+  jboolean value = 0;
+  if (read_jboolean(ph, useSharedSpacesAddr, &value) != true) {
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't read 'UseSharedSpaces' flag", 1);
+  } else if ((int)value == 0) {
+    print_debug("UseSharedSpaces is false, assuming -Xshare:off!\n");
+    return 1;
+  }
+
+  psaddr_t sharedBaseAddressAddr = 0;
+  ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedBaseAddressAddr);
+  if (sharedBaseAddressAddr == 0) {
+    print_debug("can't find symbol 'SharedBaseAddress'\n");
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't find 'SharedBaseAddress' flag\n", 1);
+  }
+
+  sharedBaseAddress = 0;
+  if (read_pointer(ph, sharedBaseAddressAddr, &sharedBaseAddress) != true) {
+    print_debug("can't read the value of 'SharedBaseAddress' flag\n");
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't get SharedBaseAddress from debuggee", 1);
+  }
+
+  char classes_jsa[PATH_MAX];
+  psaddr_t sharedArchivePathAddrAddr = 0;
+  ps_pglobal_lookup(ph, jvm_name, SHARED_ARCHIVE_PATH_SYM, &sharedArchivePathAddrAddr);
+  if (sharedArchivePathAddrAddr == 0) {
+    print_debug("can't find symbol 'Arguments::SharedArchivePath'\n");
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
+  }
+
+  uintptr_t sharedArchivePathAddr = 0;
+  if (read_pointer(ph, sharedArchivePathAddrAddr, &sharedArchivePathAddr) != true) {
+    print_debug("can't find read pointer 'Arguments::SharedArchivePath'\n");
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
+  }
+
+  if (read_string(ph, (psaddr_t)sharedArchivePathAddr, classes_jsa, sizeof(classes_jsa)) != true) {
+    print_debug("can't find read 'Arguments::SharedArchivePath' value\n");
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't get shared archive path from debuggee", 1);
+  }
+
+  print_debug("looking for %s\n", classes_jsa);
+
+  // open the classes.jsa
+  int fd = libsaproc_open(classes_jsa, O_RDONLY);
+  if (fd < 0) {
+    char errMsg[ERR_MSG_SIZE];
+    sprintf(errMsg, "can't open shared archive file %s", classes_jsa);
+    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
+  } else {
+    print_debug("opened shared archive file %s\n", classes_jsa);
+  }
+
+  // parse classes.jsa
+  CDSFileMapHeaderBase* pheader = (CDSFileMapHeaderBase*) malloc(sizeof(CDSFileMapHeaderBase));
+  if (pheader == NULL) {
+    close(fd);
+    THROW_NEW_DEBUGGER_EXCEPTION_("can't allocate memory for shared file map header", 1);
+  }
+
+  memset(pheader, 0, sizeof(CDSFileMapHeaderBase));
+  // read CDSFileMapHeaderBase
+  size_t n = read(fd, pheader, sizeof(CDSFileMapHeaderBase));
+  if (n != sizeof(CDSFileMapHeaderBase)) {
+    char errMsg[ERR_MSG_SIZE];
+    sprintf(errMsg, "unable to read shared archive file map header from %s", classes_jsa);
+    close(fd);
+    free(pheader);
+    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
+  }
+
+  // check file magic
+  if (pheader->_generic_header._magic != CDS_ARCHIVE_MAGIC) {
+    char errMsg[ERR_MSG_SIZE];
+    sprintf(errMsg, "%s has bad shared archive magic 0x%x, expecting 0x%x",
+            classes_jsa, pheader->_generic_header._magic, CDS_ARCHIVE_MAGIC);
+    close(fd);
+    free(pheader);
+    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
+  }
+
+  // check version
+  if (pheader->_generic_header._version != CURRENT_CDS_ARCHIVE_VERSION) {
+    char errMsg[ERR_MSG_SIZE];
+    sprintf(errMsg, "%s has wrong shared archive version %d, expecting %d",
+                   classes_jsa, pheader->_generic_header._version, CURRENT_CDS_ARCHIVE_VERSION);
+    close(fd);
+    free(pheader);
+    THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 1);
+  }
+
+  if (_libsaproc_debug) {
+    for (int m = 0; m < NUM_CDS_REGIONS; m++) {
+      if (!pheader->_space[m]._is_heap_region &&
+          !pheader->_space[m]._is_bitmap_region) {
+        jlong mapping_offset = pheader->_space[m]._mapping_offset;
+        jlong baseAddress = mapping_offset + (jlong)sharedBaseAddress;
+        print_debug("shared file offset %d mapped at 0x%lx, size = %ld, read only? = %d\n",
+                    pheader->_space[m]._file_offset, baseAddress,
+                    pheader->_space[m]._used, pheader->_space[m]._read_only);
+      }
+    }
+  }
+
+  // FIXME: For now, omitting other checks such as VM version etc.
+
+  // store class archive file fd and map header in debugger object fields
+  dbg->env->SetIntField(this_obj, classes_jsa_fd_ID, fd);
+  dbg->env->SetLongField(this_obj, p_file_map_header_ID, (jlong)(uintptr_t) pheader);
+  return 1;
+}
+
+} // extern "C"
+
+// error messages for proc_arg_grab failure codes. The messages are
+// modified versions of comments against corresponding #defines in
+// libproc.h.
+static const char* proc_arg_grab_errmsgs[] = {
+                      "",
+ /* G_NOPROC */       "No such process",
+ /* G_NOCORE */       "No such core file",
+ /* G_NOPROCORCORE */ "No such process or core",
+ /* G_NOEXEC */       "Cannot locate executable file",
+ /* G_ZOMB   */       "Zombie processs",
+ /* G_PERM   */       "No permission to attach",
+ /* G_BUSY   */       "Another process has already attached",
+ /* G_SYS    */       "System process - can not attach",
+ /* G_SELF   */       "Process is self - can't debug myself!",
+ /* G_INTR   */       "Interrupt received while grabbing",
+ /* G_LP64   */       "debuggee is 64 bit, use java -d64 for debugger",
+ /* G_FORMAT */       "File is not an ELF format core file - corrupted core?",
+ /* G_ELF    */       "Libelf error while parsing an ELF file",
+ /* G_NOTE   */       "Required PT_NOTE Phdr not present - corrupted core?",
+};
+
+static void attach_internal(JNIEnv* env, jobject this_obj, jstring cmdLine, jboolean isProcess) {
+  jboolean isCopy;
+  int gcode;
+  const char* cmdLine_cstr = env->GetStringUTFChars(cmdLine, &isCopy);
+  char errMsg[ERR_MSG_SIZE];
+  td_err_e te;
+  CHECK_EXCEPTION;
+  if (cmdLine_cstr == NULL) {
+    return;
+  }
+
+  // some older versions of libproc.so crash when trying to attach 32 bit
+  // debugger to 64 bit core file. check and throw error.
+#ifndef _LP64
+  errno = 0;
+  strtol(cmdLine_cstr, NULL, 10);
+  if (errno) {
+     // core file
+     int core_fd;
+     if ((core_fd = open64(cmdLine_cstr, O_RDONLY)) >= 0) {
+        Elf32_Ehdr e32;
+        if (pread64(core_fd, &e32, sizeof (e32), 0) == sizeof (e32) &&
+            memcmp(&e32.e_ident[EI_MAG0], ELFMAG, SELFMAG) == 0 &&
+            e32.e_type == ET_CORE && e32.e_ident[EI_CLASS] == ELFCLASS64) {
+              close(core_fd);
+              env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
+              THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 64 bit, use java -d64 for debugger");
+        }
+        close(core_fd);
+     }
+     // all other conditions are handled by libproc.so.
+  }
+#endif
+
+  // connect to process/core
+  ps_prochandle_t* ph = proc_arg_grab(cmdLine_cstr, (isProcess? PR_ARG_PIDS : PR_ARG_CORES), PGRAB_FORCE, &gcode, NULL);
+
+  env->ReleaseStringUTFChars(cmdLine, cmdLine_cstr);
+
+  if (! ph) {
+     if (gcode > 0 && gcode < sizeof(proc_arg_grab_errmsgs)/sizeof(const char*)) {
+        snprintf(errMsg, ERR_MSG_SIZE, "Attach failed : %s", proc_arg_grab_errmsgs[gcode]);
+        THROW_NEW_DEBUGGER_EXCEPTION(errMsg);
+    } else {
+        if (_libsaproc_debug && gcode == G_STRANGE) {
+           perror("libsaproc DEBUG: ");
+        }
+        if (isProcess) {
+           THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to process!");
+        } else {
+           THROW_NEW_DEBUGGER_EXCEPTION("Not able to attach to core file!");
+        }
+     }
+  }
+
+  // even though libproc.so supports 64 bit debugger and 32 bit debuggee, we don't
+  // support such cross-bit-debugging. check for that combination and throw error.
+#ifdef _LP64
+  int data_model;
+  if (ps_pdmodel(ph, &data_model) != PS_OK) {
+     Prelease(ph, PRELEASE_CLEAR);
+     THROW_NEW_DEBUGGER_EXCEPTION("can't determine debuggee data model (ILP32? or LP64?)");
+  }
+  if (data_model == PR_MODEL_ILP32) {
+     Prelease(ph, PRELEASE_CLEAR);
+     THROW_NEW_DEBUGGER_EXCEPTION("debuggee is 32 bit, use 32 bit java for debugger");
+  }
+#endif
+
+  env->SetLongField(this_obj, p_ps_prochandle_ID, (jlong)(uintptr_t)ph);
+
+  Debugger dbg;
+  dbg.env = env;
+  dbg.this_obj = this_obj;
+  jthrowable exception = 0;
+  if (! isProcess) {
+    /*
+     * With class sharing, shared perm. gen heap is allocated in with MAP_SHARED|PROT_READ.
+     * These pages are mapped from the file "classes.jsa". MAP_SHARED pages are not dumped
+     * in Solaris core.To read shared heap pages, we have to read classes.jsa file.
+     */
+    Pobject_iter(ph, init_classsharing_workaround, &dbg);
+    exception = env->ExceptionOccurred();
+    if (exception) {
+      env->ExceptionClear();
+      detach_internal(env, this_obj);
+      env->Throw(exception);
+      return;
+    }
+  }
+
+  /*
+   * Iterate over the process mappings looking
+   * for libthread and then dlopen the appropriate
+   * libthread_db and get function pointers.
+   */
+  Pobject_iter(ph, init_libthread_db_ptrs, &dbg);
+  exception = env->ExceptionOccurred();
+  if (exception) {
+    env->ExceptionClear();
+    if (!sa_ignore_threaddb) {
+      detach_internal(env, this_obj);
+      env->Throw(exception);
+    }
+    return;
+  }
+
+  // init libthread_db and create thread_db agent
+  p_td_init_t p_td_init = (p_td_init_t) env->GetLongField(this_obj, p_td_init_ID);
+  if (p_td_init == 0) {
+    if (!sa_ignore_threaddb) {
+      detach_internal(env, this_obj);
+    }
+    HANDLE_THREADDB_FAILURE("Did not find libthread in target process/core!");
+  }
+
+  te = p_td_init();
+  if (te != TD_OK) {
+    if (!sa_ignore_threaddb) {
+      detach_internal(env, this_obj);
+    }
+    snprintf(errMsg, ERR_MSG_SIZE, "Can't initialize thread_db! td_init failed: %d", te);
+    HANDLE_THREADDB_FAILURE(errMsg);
+  }
+
+  p_td_ta_new_t p_td_ta_new = (p_td_ta_new_t) env->GetLongField(this_obj, p_td_ta_new_ID);
+
+  td_thragent_t *p_td_thragent_t = 0;
+  te = p_td_ta_new(ph, &p_td_thragent_t);
+  if (te != TD_OK) {
+    if (!sa_ignore_threaddb) {
+      detach_internal(env, this_obj);
+    }
+    snprintf(errMsg, ERR_MSG_SIZE, "Can't create thread_db agent! td_ta_new failed: %d", te);
+    HANDLE_THREADDB_FAILURE(errMsg);
+  }
+  env->SetLongField(this_obj, p_td_thragent_t_ID, (jlong)(uintptr_t) p_td_thragent_t);
+
+}
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:    attach0
+ * Signature: (Ljava/lang/String;)V
+ * Description: process detach
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2
+  (JNIEnv *env, jobject this_obj, jstring pid) {
+  attach_internal(env, this_obj, pid, JNI_TRUE);
+}
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:    attach0
+ * Signature: (Ljava/lang/String;Ljava/lang/String;)V
+ * Description: core file detach
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_attach0__Ljava_lang_String_2Ljava_lang_String_2
+  (JNIEnv *env, jobject this_obj, jstring executable, jstring corefile) {
+  // ignore executable file name, libproc.so can detect a.out name anyway.
+  attach_internal(env, this_obj, corefile, JNI_FALSE);
+}
+
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      detach0
+ * Signature:   ()V
+ * Description: process/core file detach
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_detach0
+  (JNIEnv *env, jobject this_obj) {
+  detach_internal(env, this_obj);
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      getRemoteProcessAddressSize0
+ * Signature:   ()I
+ * Description: get process/core address size
+ */
+JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getRemoteProcessAddressSize0
+  (JNIEnv *env, jobject this_obj) {
+  jlong p_ps_prochandle;
+  p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+  int data_model = PR_MODEL_ILP32;
+  ps_pdmodel((struct ps_prochandle*) p_ps_prochandle, &data_model);
+  print_debug("debuggee is %d bit\n", data_model == PR_MODEL_ILP32? 32 : 64);
+  return (jint) data_model == PR_MODEL_ILP32? 32 : 64;
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      getPageSize0
+ * Signature:   ()I
+ * Description: get process/core page size
+ */
+JNIEXPORT jint JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getPageSize0
+  (JNIEnv *env, jobject this_obj) {
+
+/*
+  We are not yet attached to a java process or core file. getPageSize is called from
+  the constructor of ProcDebuggerLocal. The following won't work!
+
+    jlong p_ps_prochandle;
+    p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+    CHECK_EXCEPTION_(-1);
+    struct ps_prochandle* prochandle = (struct ps_prochandle*) p_ps_prochandle;
+    return (Pstate(prochandle) == PS_DEAD) ? Pgetauxval(prochandle, AT_PAGESZ)
+                                           : getpagesize();
+
+  So even though core may have been generated with a different page size settings, for now
+  call getpagesize.
+*/
+
+  return getpagesize();
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      getThreadIntegerRegisterSet0
+ * Signature:   (J)[J
+ * Description: get gregset for a given thread specified by thread id
+ */
+JNIEXPORT jlongArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_getThreadIntegerRegisterSet0
+  (JNIEnv *env, jobject this_obj, jlong tid) {
+  char errMsg[ERR_MSG_SIZE];
+  td_err_e te;
+  // map the thread id to thread handle
+  p_td_ta_map_id2thr_t p_td_ta_map_id2thr = (p_td_ta_map_id2thr_t) env->GetLongField(this_obj, p_td_ta_map_id2thr_ID);
+
+  td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
+  if (p_td_thragent_t == 0) {
+     return 0;
+  }
+
+  td_thrhandle_t thr_handle;
+  te = p_td_ta_map_id2thr(p_td_thragent_t, (thread_t) tid, &thr_handle);
+  if (te != TD_OK) {
+     snprintf(errMsg, ERR_MSG_SIZE, "can't map thread id to thread handle! td_ta_map_id2thr failed: %d", te);
+     THROW_NEW_DEBUGGER_EXCEPTION_(errMsg, 0);
+  }
+
+  p_td_thr_getgregs_t p_td_thr_getgregs = (p_td_thr_getgregs_t) env->GetLongField(this_obj, p_td_thr_getgregs_ID);
+  prgregset_t gregs;
+  p_td_thr_getgregs(&thr_handle, gregs);
+
+  jlongArray res = env->NewLongArray(NPRGREG);
+  CHECK_EXCEPTION_(0);
+  jboolean isCopy;
+  jlong* ptr = env->GetLongArrayElements(res, &isCopy);
+  CHECK_EXCEPTION_(NULL);
+  for (int i = 0; i < NPRGREG; i++) {
+    ptr[i] = (jlong) (uintptr_t) gregs[i];
+  }
+  env->ReleaseLongArrayElements(res, ptr, JNI_COMMIT);
+  return res;
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      fillThreadList0
+ * Signature:   (Ljava/util/List;)V
+ * Description: fills thread list of the debuggee process/core
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillThreadList0
+  (JNIEnv *env, jobject this_obj, jobject list) {
+
+  td_thragent_t* p_td_thragent_t = (td_thragent_t*) env->GetLongField(this_obj, p_td_thragent_t_ID);
+  if (p_td_thragent_t == 0) {
+     return;
+  }
+
+  p_td_ta_thr_iter_t p_td_ta_thr_iter = (p_td_ta_thr_iter_t) env->GetLongField(this_obj, p_td_ta_thr_iter_ID);
+
+  DebuggerWithObject dbgo;
+  dbgo.env = env;
+  dbgo.this_obj = this_obj;
+  dbgo.obj = list;
+
+  p_td_ta_thr_iter(p_td_thragent_t, fill_thread_list, &dbgo,
+                   TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      fillCFrameList0
+ * Signature:   ([J)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;
+ * Description: fills CFrame list for a given thread
+ */
+JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_fillCFrameList0
+  (JNIEnv *env, jobject this_obj, jlongArray regsArray) {
+  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+
+  DebuggerWith2Objects dbgo2;
+  dbgo2.env  = env;
+  dbgo2.this_obj = this_obj;
+  dbgo2.obj  = NULL;
+  dbgo2.obj2 = NULL;
+
+  jboolean isCopy;
+  jlong* ptr = env->GetLongArrayElements(regsArray, &isCopy);
+  CHECK_EXCEPTION_(0);
+
+  prgregset_t gregs;
+  for (int i = 0; i < NPRGREG; i++) {
+     gregs[i] = (uintptr_t) ptr[i];
+  }
+
+  env->ReleaseLongArrayElements(regsArray, ptr, JNI_ABORT);
+  CHECK_EXCEPTION_(0);
+
+  Pstack_iter((struct ps_prochandle*) p_ps_prochandle, gregs,
+              wrapper_fill_cframe_list, &dbgo2);
+  return dbgo2.obj;
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      readBytesFromProcess0
+ * Signature:   (JJ)[B
+ * Description: read bytes from debuggee process/core
+ */
+JNIEXPORT jbyteArray JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_readBytesFromProcess0
+  (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes) {
+
+  jbyteArray array = env->NewByteArray(numBytes);
+  CHECK_EXCEPTION_(0);
+  jboolean isCopy;
+  jbyte* bufPtr = env->GetByteArrayElements(array, &isCopy);
+  CHECK_EXCEPTION_(0);
+
+  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+  ps_err_e ret = ps_pread((struct ps_prochandle*) p_ps_prochandle,
+                       (psaddr_t)address, bufPtr, (size_t)numBytes);
+
+  if (ret != PS_OK) {
+    // part of the class sharing workaround. try shared heap area
+    int classes_jsa_fd = env->GetIntField(this_obj, classes_jsa_fd_ID);
+    if (classes_jsa_fd != -1 && address != (jlong)0) {
+      print_debug("read failed at 0x%lx, attempting shared heap area\n", (long) address);
+
+      CDSFileMapHeaderBase* pheader = (CDSFileMapHeaderBase*) env->GetLongField(this_obj, p_file_map_header_ID);
+      // walk through the shared mappings -- we just have 9 of them.
+      // so, linear walking is okay.
+      for (int m = 0; m < NUM_CDS_REGIONS; m++) {
+
+        // We can skip the non-read-only maps. These are mapped as MAP_PRIVATE
+        // and hence will be read by libproc. Besides, the file copy may be
+        // stale because the process might have modified those pages.
+        if (pheader->_space[m]._read_only &&
+            !pheader->_space[m]._is_heap_region &&
+            !pheader->_space[m]._is_bitmap_region) {
+         jlong mapping_offset = (jlong) (uintptr_t) pheader->_space[m]._mapping_offset;
+         jlong baseAddress = mapping_offset + (jlong)sharedBaseAddress;
+         size_t usedSize = pheader->_space[m]._used;
+         if (address >= baseAddress && address < (baseAddress + usedSize)) {
+            // the given address falls in this shared metadata area
+            print_debug("found shared map at 0x%lx\n", (long) baseAddress);
+
+
+            // If more data is asked than actually mapped from file, we need to zero fill
+            // till the end-of-page boundary. But, java array new does that for us. we just
+            // need to read as much as data available.
+
+#define MIN2(x, y) (((x) < (y))? (x) : (y))
+
+            jlong diff = address - baseAddress;
+            jlong bytesToRead = MIN2(numBytes, usedSize - diff);
+            off_t offset = pheader->_space[m]._file_offset  + off_t(diff);
+            ssize_t bytesRead = pread(classes_jsa_fd, bufPtr, bytesToRead, offset);
+            if (bytesRead != bytesToRead) {
+              env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
+              print_debug("shared map read failed\n");
+              return jbyteArray(0);
+            } else {
+              print_debug("shared map read succeeded\n");
+              env->ReleaseByteArrayElements(array, bufPtr, 0);
+              return array;
+            }
+          } // is in current map
+        } // is read only map
+      } // for shared maps
+    } // classes_jsa_fd != -1
+    env->ReleaseByteArrayElements(array, bufPtr, JNI_ABORT);
+    return jbyteArray(0);
+  } else {
+    env->ReleaseByteArrayElements(array, bufPtr, 0);
+    return array;
+  }
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      writeBytesToProcess0
+ * Signature:   (JJ[B)V
+ * Description: write bytes into debugger process
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_writeBytesToProcess0
+  (JNIEnv *env, jobject this_obj, jlong address, jlong numBytes, jbyteArray data) {
+  char errMsg[ERR_MSG_SIZE];
+  ps_err_e pe;
+  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+  jboolean isCopy;
+  jbyte* ptr = env->GetByteArrayElements(data, &isCopy);
+  CHECK_EXCEPTION;
+
+  pe = ps_pwrite((struct ps_prochandle*) p_ps_prochandle, address, ptr, numBytes);
+  if (pe != PS_OK) {
+     snprintf(errMsg, ERR_MSG_SIZE, "Process write failed! ps_pwrite failed: %d", pe);
+     env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+     THROW_NEW_DEBUGGER_EXCEPTION(errMsg);
+  }
+
+  env->ReleaseByteArrayElements(data, ptr, JNI_ABORT);
+}
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:    suspend0
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_suspend0
+  (JNIEnv *env, jobject this_obj) {
+  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+  // for now don't check return value. revisit this again.
+  Pstop((struct ps_prochandle*) p_ps_prochandle, 1000);
+}
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:    resume0
+ * Signature: ()V
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_resume0
+  (JNIEnv *env, jobject this_obj) {
+  jlong p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+  // for now don't check return value. revisit this again.
+  Psetrun((struct ps_prochandle*) p_ps_prochandle, 0, PRCFAULT|PRSTOP);
+}
+
+/*
+  * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+  * Method:      lookupByName0
+  * Signature:   (Ljava/lang/String;Ljava/lang/String;)J
+  * Description: symbol lookup by name
+*/
+JNIEXPORT jlong JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByName0
+   (JNIEnv *env, jobject this_obj, jstring objectName, jstring symbolName) {
+   jlong p_ps_prochandle;
+   p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+
+   jboolean isCopy;
+   const char* objectName_cstr = NULL;
+   if (objectName != NULL) {
+     objectName_cstr = env->GetStringUTFChars(objectName, &isCopy);
+     CHECK_EXCEPTION_(0);
+   } else {
+     objectName_cstr = PR_OBJ_EVERY;
+   }
+
+   const char* symbolName_cstr = env->GetStringUTFChars(symbolName, &isCopy);
+   if (env->ExceptionOccurred()) {
+     if (objectName_cstr != PR_OBJ_EVERY) {
+       env->ReleaseStringUTFChars(objectName, objectName_cstr);
+     }
+     return 0;
+   }
+
+   psaddr_t symbol_addr = (psaddr_t) 0;
+   ps_pglobal_lookup((struct ps_prochandle*) p_ps_prochandle,  objectName_cstr,
+                    symbolName_cstr, &symbol_addr);
+
+   if (symbol_addr == 0) {
+      print_debug("lookup for %s in %s failed\n", symbolName_cstr, objectName_cstr);
+   }
+
+   if (objectName_cstr != PR_OBJ_EVERY) {
+     env->ReleaseStringUTFChars(objectName, objectName_cstr);
+   }
+   env->ReleaseStringUTFChars(symbolName, symbolName_cstr);
+   return (jlong) (uintptr_t) symbol_addr;
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      lookupByAddress0
+ * Signature:   (J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;
+ * Description: lookup symbol name for a given address
+ */
+JNIEXPORT jobject JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_lookupByAddress0
+   (JNIEnv *env, jobject this_obj, jlong address) {
+   jlong p_ps_prochandle;
+   p_ps_prochandle = env->GetLongField(this_obj, p_ps_prochandle_ID);
+
+   char nameBuf[SYMBOL_BUF_SIZE + 1];
+   GElf_Sym sym;
+   int res = Plookup_by_addr((struct ps_prochandle*) p_ps_prochandle, (uintptr_t) address,
+                             nameBuf, sizeof(nameBuf), &sym, NULL);
+
+   if (res != 0) { // failed
+      return 0;
+   }
+
+   jstring resSym = env->NewStringUTF(nameBuf);
+   CHECK_EXCEPTION_(0);
+
+   return env->CallObjectMethod(this_obj, createClosestSymbol_ID, resSym, (address - sym.st_value));
+}
+
+/*
+ * Class:     sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:    demangle0
+ * Signature: (Ljava/lang/String;)Ljava/lang/String;
+ */
+JNIEXPORT jstring JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_demangle0
+  (JNIEnv *env, jobject this_object, jstring name) {
+  jboolean isCopy;
+  const char* ptr = env->GetStringUTFChars(name, &isCopy);
+  CHECK_EXCEPTION_(NULL);
+  char  buf[2*SYMBOL_BUF_SIZE + 1];
+  jstring res = 0;
+  if (cplus_demangle((char*) ptr, buf, sizeof(buf)) != DEMANGLE_ESPACE) {
+    res = env->NewStringUTF(buf);
+  } else {
+    res = name;
+  }
+  env->ReleaseStringUTFChars(name, ptr);
+  return res;
+}
+
+/*
+ * Class:       sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal
+ * Method:      initIDs
+ * Signature:   ()V
+ * Description: get JNI ids for fields and methods of ProcDebuggerLocal class
+ */
+JNIEXPORT void JNICALL Java_sun_jvm_hotspot_debugger_proc_ProcDebuggerLocal_initIDs
+  (JNIEnv *env, jclass clazz) {
+  _libsaproc_debug = getenv("LIBSAPROC_DEBUG") != NULL;
+  if (_libsaproc_debug) {
+     // propagate debug mode to libproc.so
+     static const char* var = "LIBPROC_DEBUG=1";
+     putenv((char*)var);
+  }
+
+  void* libproc_handle = dlopen("libproc.so", RTLD_LAZY | RTLD_GLOBAL);
+  if (libproc_handle == 0)
+     THROW_NEW_DEBUGGER_EXCEPTION("can't load libproc.so, if you are using Solaris 5.7 or below, copy libproc.so from 5.8!");
+
+  p_ps_prochandle_ID = env->GetFieldID(clazz, "p_ps_prochandle", "J");
+  CHECK_EXCEPTION;
+
+  libthread_db_handle_ID = env->GetFieldID(clazz, "libthread_db_handle", "J");
+  CHECK_EXCEPTION;
+
+  p_td_thragent_t_ID = env->GetFieldID(clazz, "p_td_thragent_t", "J");
+  CHECK_EXCEPTION;
+
+  p_td_init_ID = env->GetFieldID(clazz, "p_td_init", "J");
+  CHECK_EXCEPTION;
+
+  p_td_ta_new_ID = env->GetFieldID(clazz, "p_td_ta_new", "J");
+  CHECK_EXCEPTION;
+
+  p_td_ta_delete_ID = env->GetFieldID(clazz, "p_td_ta_delete", "J");
+  CHECK_EXCEPTION;
+
+  p_td_ta_thr_iter_ID = env->GetFieldID(clazz, "p_td_ta_thr_iter", "J");
+  CHECK_EXCEPTION;
+
+  p_td_thr_get_info_ID = env->GetFieldID(clazz, "p_td_thr_get_info", "J");
+  CHECK_EXCEPTION;
+
+  p_td_ta_map_id2thr_ID = env->GetFieldID(clazz, "p_td_ta_map_id2thr", "J");
+  CHECK_EXCEPTION;
+
+  p_td_thr_getgregs_ID = env->GetFieldID(clazz, "p_td_thr_getgregs", "J");
+  CHECK_EXCEPTION;
+
+  getThreadForThreadId_ID = env->GetMethodID(clazz,
+                            "getThreadForThreadId", "(J)Lsun/jvm/hotspot/debugger/ThreadProxy;");
+  CHECK_EXCEPTION;
+
+  pcRegIndex_ID = env->GetFieldID(clazz, "pcRegIndex", "I");
+  CHECK_EXCEPTION;
+
+  fpRegIndex_ID = env->GetFieldID(clazz, "fpRegIndex", "I");
+  CHECK_EXCEPTION;
+
+  createSenderFrame_ID = env->GetMethodID(clazz,
+                            "createSenderFrame", "(Lsun/jvm/hotspot/debugger/proc/ProcCFrame;JJ)Lsun/jvm/hotspot/debugger/proc/ProcCFrame;");
+  CHECK_EXCEPTION;
+
+  createClosestSymbol_ID = env->GetMethodID(clazz,
+                            "createClosestSymbol", "(Ljava/lang/String;J)Lsun/jvm/hotspot/debugger/cdbg/ClosestSymbol;");
+  CHECK_EXCEPTION;
+
+  jclass list_clazz = env->FindClass("java/util/List");
+  CHECK_EXCEPTION;
+  listAdd_ID = env->GetMethodID(list_clazz, "add", "(Ljava/lang/Object;)Z");
+  CHECK_EXCEPTION;
+
+  // part of the class sharing workaround
+  classes_jsa_fd_ID = env->GetFieldID(clazz, "classes_jsa_fd", "I");
+  CHECK_EXCEPTION;
+  p_file_map_header_ID = env->GetFieldID(clazz, "p_file_map_header", "J");
+  CHECK_EXCEPTION;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/test/libproc/libproctest.sh jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/test/libproc/libproctest.sh
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.hotspot.agent/test/libproc/libproctest.sh	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.hotspot.agent/test/libproc/libproctest.sh	2024-08-17 18:29:44.526952468 +0200
@@ -59,8 +59,10 @@
 kill -9 $pid
 
 
+OPTIONS="-Djava.library.path=$STARTDIR/../src/os/solaris/proc/`uname -p`:$STARTDIR/../solaris/`uname -p`"
+
 # run libproc client
-$SA_JAVA -showversion -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid
+$SA_JAVA -showversion ${OPTIONS} -cp $STARTDIR/../../build/classes::$STARTDIR/../sa.jar:$STARTDIR LibprocClient x core.$pid
 
 # delete core
 rm -f core.$pid
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c jdk18u-jdk-18.0.2.1-ga/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c	2024-08-17 18:29:44.527588574 +0200
@@ -33,8 +33,12 @@
 #include <errno.h>
 #include <string.h>
 #include <sys/time.h>
+#ifdef __solaris__
+#include <thread.h>
+#else
 #include <pthread.h>
 #include <poll.h>
+#endif
 
 #include "socket_md.h"
 #include "sysSocket.h"
@@ -273,6 +277,35 @@
     return 0;
 }
 
+#ifdef __solaris__
+int
+dbgsysTlsAlloc() {
+    thread_key_t tk;
+    if (thr_keycreate(&tk, NULL)) {
+        perror("thr_keycreate");
+        exit(-1);
+    }
+    return (int)tk;
+}
+
+void
+dbgsysTlsFree(int index) {
+   /* no-op */
+}
+
+void
+dbgsysTlsPut(int index, void *value) {
+    thr_setspecific((thread_key_t)index, value) ;
+}
+
+void *
+dbgsysTlsGet(int index) {
+    void* r = NULL;
+    thr_getspecific((thread_key_t)index, &r);
+    return r;
+}
+
+#else
 int
 dbgsysTlsAlloc() {
     pthread_key_t key;
@@ -298,6 +331,8 @@
     return pthread_getspecific((pthread_key_t)index);
 }
 
+#endif
+
 long
 dbgsysCurrentTimeMillis() {
     struct timeval t;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.jdwp.agent/unix/native/libjdwp/exec_md.c jdk18u-jdk-18.0.2.1-ga/src/jdk.jdwp.agent/unix/native/libjdwp/exec_md.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.jdwp.agent/unix/native/libjdwp/exec_md.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.jdwp.agent/unix/native/libjdwp/exec_md.c	2024-08-17 18:29:44.528047433 +0200
@@ -30,6 +30,14 @@
 #include "sys.h"
 #include "util.h"
 
+#if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(AIX)
+  /* Linux, BSD, AIX */
+  #define FORK() fork()
+#else
+  /* Solaris (make sure we always get the POSIX-specified behavior) */
+  #define FORK() fork1()
+#endif
+
 static char *skipWhitespace(char *p) {
     while ((*p != '\0') && isspace(*p)) {
         p++;
@@ -92,7 +100,7 @@
     }
     argv[i] = NULL;  /* NULL terminate */
 
-    if ((pid = fork()) == 0) {
+    if ((pid = FORK()) == 0) {
         /* Child process */
         int i;
         long max_fd;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java jdk18u-jdk-18.0.2.1-ga/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.jlink/share/classes/jdk/tools/jlink/internal/Platform.java	2024-08-17 18:29:44.528628168 +0200
@@ -34,6 +34,7 @@
     public enum OperatingSystem {
         WINDOWS,
         LINUX,
+        SOLARIS,
         MACOS,
         AIX,
         UNKNOWN;
@@ -104,6 +105,7 @@
         OperatingSystem os = switch (osName) {
             case "win" -> OperatingSystem.WINDOWS;
             case "lin" -> OperatingSystem.LINUX;
+            case "sun" -> OperatingSystem.SOLARIS;
             case "mac" -> OperatingSystem.MACOS;
             case "aix" -> OperatingSystem.AIX;
             default    -> OperatingSystem.UNKNOWN;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c jdk18u-jdk-18.0.2.1-ga/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c	2024-08-17 18:29:44.579984070 +0200
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2011, 2019, Oracle and/or its affiliates. All rights reserved.
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
+ *
+ * This code is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License version 2 only, as
+ * published by the Free Software Foundation.  Oracle designates this
+ * particular file as subject to the "Classpath" exception as provided
+ * by Oracle in the LICENSE file that accompanied this code.
+ *
+ * This code is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
+ * version 2 for more details (a copy is included in the LICENSE file that
+ * accompanied this code).
+ *
+ * You should have received a copy of the GNU General Public License version
+ * 2 along with this work; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
+ * or visit www.oracle.com if you need additional information or have any
+ * questions.
+ */
+
+#include <fcntl.h>
+#include <kstat.h>
+#include <procfs.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/sysinfo.h>
+#include <sys/lwp.h>
+#include <pthread.h>
+#include <utmpx.h>
+#include <dlfcn.h>
+#include <sys/loadavg.h>
+#include <jni.h>
+#include "jvm.h"
+#include "com_sun_management_internal_OperatingSystemImpl.h"
+
+typedef struct {
+    kstat_t *kstat;
+    uint64_t  last_idle;
+    uint64_t  last_total;
+    double  last_ratio;
+} cpuload_t;
+
+static cpuload_t   *cpu_loads = NULL;
+static unsigned int num_cpus;
+static kstat_ctl_t *kstat_ctrl = NULL;
+
+static void map_cpu_kstat_counters() {
+    kstat_t     *kstat;
+    int          i;
+
+    // Get number of CPU(s)
+    if ((num_cpus = sysconf(_SC_NPROCESSORS_ONLN)) == -1) {
+        num_cpus = 1;
+    }
+
+    // Data structure for saving CPU load
+    if ((cpu_loads = calloc(num_cpus,sizeof(cpuload_t))) == NULL) {
+        return;
+    }
+
+    // Get kstat cpu_stat counters for every CPU
+    // (loop over kstat to find our cpu_stat(s)
+    i = 0;
+    for (kstat = kstat_ctrl->kc_chain; kstat != NULL; kstat = kstat->ks_next) {
+        if (strncmp(kstat->ks_module, "cpu_stat", 8) == 0) {
+
+            if (kstat_read(kstat_ctrl, kstat, NULL) == -1) {
+            // Failed to initialize kstat for this CPU so ignore it
+            continue;
+            }
+
+            if (i == num_cpus) {
+            // Found more cpu_stats than reported CPUs
+            break;
+            }
+
+            cpu_loads[i++].kstat = kstat;
+        }
+    }
+}
+
+static int init_cpu_kstat_counters() {
+    static int initialized = 0;
+
+    // Concurrence in this method is prevented by the lock in
+    // the calling method get_cpu_load();
+    if(!initialized) {
+        if ((kstat_ctrl = kstat_open()) != NULL) {
+            map_cpu_kstat_counters();
+            initialized = 1;
+        }
+    }
+    return initialized ? 0 : -1;
+}
+
+static void update_cpu_kstat_counters() {
+    if(kstat_chain_update(kstat_ctrl) != 0) {
+        free(cpu_loads);
+        map_cpu_kstat_counters();
+    }
+}
+
+int read_cpustat(cpuload_t *load, cpu_stat_t *cpu_stat) {
+    if (load->kstat == NULL) {
+        // no handle.
+        return -1;
+    }
+    if (kstat_read(kstat_ctrl, load->kstat, cpu_stat) == -1) {
+        //  disabling for now, a kstat chain update is likely to happen next time
+        load->kstat = NULL;
+        return -1;
+    }
+    return 0;
+}
+
+double get_single_cpu_load(unsigned int n) {
+    cpuload_t  *load;
+    cpu_stat_t  cpu_stat;
+    uint_t     *usage;
+    uint64_t          c_idle;
+    uint64_t          c_total;
+    uint64_t          d_idle;
+    uint64_t          d_total;
+    int           i;
+
+    if (n >= num_cpus) {
+        return -1.0;
+    }
+
+    load = &cpu_loads[n];
+    if (read_cpustat(load, &cpu_stat) < 0) {
+        return -1.0;
+    }
+
+    usage   = cpu_stat.cpu_sysinfo.cpu;
+    c_idle  = usage[CPU_IDLE];
+
+    for (c_total = 0, i = 0; i < CPU_STATES; i++) {
+        c_total += usage[i];
+    }
+
+    // Calculate diff against previous snapshot
+    d_idle  = c_idle - load->last_idle;
+    d_total = c_total - load->last_total;
+
+    /** update if weve moved */
+    if (d_total > 0) {
+        // Save current values for next time around
+        load->last_idle  = c_idle;
+        load->last_total = c_total;
+        load->last_ratio = (double) (d_total - d_idle) / d_total;
+    }
+
+    return load->last_ratio;
+}
+
+int get_info(const char *path, void *info, size_t s, off_t o) {
+    int fd;
+    int ret = 0;
+    if ((fd = open(path, O_RDONLY)) < 0) {
+        return -1;
+    }
+    if (pread(fd, info, s, o) != s) {
+        ret = -1;
+    }
+    close(fd);
+    return ret;
+}
+
+#define MIN(a, b)           ((a < b) ? a : b)
+
+static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER;
+
+/**
+ * Return the cpu load (0-1) for proc number 'which' (or average all if which == -1)
+ */
+double  get_cpu_load(int which) {
+    double load =.0;
+
+    pthread_mutex_lock(&lock);
+    if(init_cpu_kstat_counters()==0) {
+
+        update_cpu_kstat_counters();
+
+        if (which == -1) {
+            unsigned int i;
+            double       t;
+
+            for (t = .0, i = 0; i < num_cpus; i++) {
+                t += get_single_cpu_load(i);
+            }
+
+            // Cap total systemload to 1.0
+            load = MIN((t / num_cpus), 1.0);
+        } else {
+            load = MIN(get_single_cpu_load(which), 1.0);
+        }
+    } else {
+        load = -1.0;
+    }
+    pthread_mutex_unlock(&lock);
+
+    return load;
+}
+
+/**
+ * Return the cpu load (0-1) for the current process (i.e the JVM)
+ * or -1.0 if the get_info() call failed
+ */
+double get_process_load(void) {
+    psinfo_t info;
+
+    // Get the percentage of "recent cpu usage" from all the lwp:s in the JVM:s
+    // process. This is returned as a value between 0.0 and 1.0 multiplied by 0x8000.
+    if (get_info("/proc/self/psinfo",&info.pr_pctcpu, sizeof(info.pr_pctcpu), offsetof(psinfo_t, pr_pctcpu)) == 0) {
+        return (double) info.pr_pctcpu / 0x8000;
+    }
+    return -1.0;
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_sun_management_internal_OperatingSystemImpl_getCpuLoad0
+(JNIEnv *env, jobject dummy)
+{
+    return get_cpu_load(-1);
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_sun_management_internal_OperatingSystemImpl_getProcessCpuLoad0
+(JNIEnv *env, jobject dummy)
+{
+    return get_process_load();
+}
+
+JNIEXPORT jdouble JNICALL
+Java_com_sun_management_internal_OperatingSystemImpl_getSingleCpuLoad0
+(JNIEnv *env, jobject mbean, jint cpu_number)
+{
+    return -1.0;
+}
+
+JNIEXPORT jint JNICALL
+Java_com_sun_management_internal_OperatingSystemImpl_getHostConfiguredCpuCount0
+(JNIEnv *env, jobject mbean)
+{
+    return -1;
+}
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c jdk18u-jdk-18.0.2.1-ga/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c	2024-08-17 18:29:44.529306503 +0200
@@ -85,7 +85,63 @@
 // true = get available swap in bytes
 // false = get total swap in bytes
 static jlong get_total_or_available_swap_space_size(JNIEnv* env, jboolean available) {
-#if defined(__linux__)
+#ifdef __solaris__
+    long total, avail;
+    int nswap, i, count;
+    swaptbl_t *stbl;
+    char *strtab;
+
+    // First get the number of swap resource entries
+    if ((nswap = swapctl(SC_GETNSWP, NULL)) == -1) {
+        throw_internal_error(env, "swapctl failed to get nswap");
+        return -1;
+    }
+    if (nswap == 0) {
+        return 0;
+    }
+
+    // Allocate storage for resource entries
+    stbl = (swaptbl_t*) malloc(nswap * sizeof(swapent_t) +
+                               sizeof(struct swaptable));
+    if (stbl == NULL) {
+        JNU_ThrowOutOfMemoryError(env, 0);
+        return -1;
+    }
+
+    // Allocate storage for the table
+    strtab = (char*) malloc((nswap + 1) * MAXPATHLEN);
+    if (strtab == NULL) {
+        free(stbl);
+        JNU_ThrowOutOfMemoryError(env, 0);
+        return -1;
+    }
+
+    for (i = 0; i < (nswap + 1); i++) {
+      stbl->swt_ent[i].ste_path = strtab + (i * MAXPATHLEN);
+    }
+    stbl->swt_n = nswap + 1;
+
+    // Get the entries
+    if ((count = swapctl(SC_LIST, stbl)) < 0) {
+        free(stbl);
+        free(strtab);
+        throw_internal_error(env, "swapctl failed to get swap list");
+        return -1;
+    }
+
+    // Sum the entries to get total and free swap
+    total = 0;
+    avail = 0;
+    for (i = 0; i < count; i++) {
+      total += stbl->swt_ent[i].ste_pages;
+      avail += stbl->swt_ent[i].ste_free;
+    }
+
+    free(stbl);
+    free(strtab);
+    return available ? ((jlong)avail * page_size) :
+                       ((jlong)total * page_size);
+#elif defined(__linux__)
     int ret;
     FILE *fp;
     jlong total = 0, avail = 0;
@@ -127,7 +183,37 @@
 Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0
   (JNIEnv *env, jobject mbean)
 {
-#if defined(__linux__)
+#ifdef __solaris__
+    psinfo_t psinfo;
+    ssize_t result;
+    size_t remaining;
+    char* addr;
+    int fd;
+
+    fd = open64("/proc/self/psinfo", O_RDONLY, 0);
+    if (fd < 0) {
+        throw_internal_error(env, "Unable to open /proc/self/psinfo");
+        return -1;
+    }
+
+    addr = (char *)&psinfo;
+    for (remaining = sizeof(psinfo_t); remaining > 0;) {
+        result = read(fd, addr, remaining);
+        if (result < 0) {
+            if (errno != EINTR) {
+                close(fd);
+                throw_internal_error(env, "Unable to read /proc/self/psinfo");
+                return -1;
+            }
+        } else {
+            remaining -= result;
+            addr += result;
+        }
+    }
+
+    close(fd);
+    return (jlong) psinfo.pr_size * 1024;
+#elif defined(__linux__)
     FILE *fp;
     unsigned long vsize = 0;
 
@@ -200,7 +286,7 @@
      * BSDNOTE: FreeBSD implements _SC_CLK_TCK since FreeBSD 5, so
      *          add a magic to handle it
      */
-#if defined(_SC_CLK_TCK)
+#if defined(__solaris__) || defined(_SC_CLK_TCK)
     clk_tck = (jlong) sysconf(_SC_CLK_TCK);
 #elif defined(__linux__) || defined(_ALLBSD_SOURCE)
     clk_tck = 100;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java	2024-08-17 18:29:44.529941703 +0200
@@ -48,6 +48,11 @@
     /* -- Miscellaneous SCTP utilities -- */
 
     private static boolean IPv4MappedAddresses() {
+        if ("SunOS".equals(osName)) {
+            /* Solaris supports IPv4Mapped Addresses with bindx */
+            return true;
+        } /* else {  //other OS/implementations  */
+
         /* lksctp/linux requires Ipv4 addresses */
         return false;
     }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/native/libsctp/Sctp.h jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/native/libsctp/Sctp.h
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/native/libsctp/Sctp.h	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/native/libsctp/Sctp.h	2024-08-17 18:29:44.530507393 +0200
@@ -26,6 +26,48 @@
 #ifndef SUN_NIO_CH_SCTP_H
 #define SUN_NIO_CH_SCTP_H
 
+#ifdef __solaris__
+
+#define _XPG4_2
+#define __EXTENSIONS__
+#include <sys/socket.h>
+#include <netinet/sctp.h>
+#include "jni.h"
+
+/* Current Solaris headers don't comply with draft rfc */
+#ifndef SCTP_EOF
+#define SCTP_EOF MSG_EOF
+#endif
+
+#ifndef SCTP_UNORDERED
+#define SCTP_UNORDERED MSG_UNORDERED
+#endif
+
+/* The current version of the socket API extension shipped with Solaris does
+ * not define the following options that the Java API (optionally) supports */
+#ifndef SCTP_EXPLICIT_EOR
+#define SCTP_EXPLICIT_EOR -1
+#endif
+#ifndef SCTP_FRAGMENT_INTERLEAVE
+#define SCTP_FRAGMENT_INTERLEAVE -1
+#endif
+#ifndef SCTP_SET_PEER_PRIMARY_ADDR
+#define SCTP_SET_PEER_PRIMARY_ADDR -1
+#endif
+
+/* Function types to support dynamic linking of socket API extension functions
+ * for SCTP. This is so that there is no linkage depandancy during build or
+ * runtime for libsctp.*/
+typedef int sctp_getladdrs_func(int sock, sctp_assoc_t id, void **addrs);
+typedef int sctp_freeladdrs_func(void* addrs);
+typedef int sctp_getpaddrs_func(int sock, sctp_assoc_t id, void **addrs);
+typedef int sctp_freepaddrs_func(void *addrs);
+typedef int sctp_bindx_func(int sock, void *addrs, int addrcnt, int flags);
+typedef int sctp_peeloff_func(int sock, sctp_assoc_t id);
+
+
+
+#else /* __linux__ */
 #include <stdint.h>
 #include <linux/types.h>
 #include <sys/socket.h>
@@ -278,6 +320,8 @@
 typedef int sctp_peeloff_func(int sock, sctp_assoc_t id);
 
 
+#endif /* __linux__ */
+
 extern sctp_getladdrs_func* nio_sctp_getladdrs;
 extern sctp_freeladdrs_func* nio_sctp_freeladdrs;
 extern sctp_getpaddrs_func* nio_sctp_getpaddrs;
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c	2024-08-17 18:29:44.531036830 +0200
@@ -334,11 +334,10 @@
             break;
         case SCTP_ADDR_MADE_PRIM :
             event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_MADE_PRIM;
+#ifdef __linux__  /* Solaris currently doesn't support SCTP_ADDR_CONFIRMED */
             break;
-#ifdef __linux__
         case SCTP_ADDR_CONFIRMED :
             event = sun_nio_ch_sctp_PeerAddrChange_SCTP_ADDR_CONFIRMED;
-            break;
 #endif  /* __linux__ */
     }
 
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpNet.c jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/native/libsctp/SctpNet.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.sctp/unix/native/libsctp/SctpNet.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.sctp/unix/native/libsctp/SctpNet.c	2024-08-17 18:29:44.531617705 +0200
@@ -364,7 +364,11 @@
     int i, addrCount;
     jobjectArray isaa;
 
+#ifdef __solaris__
+    if ((addrCount = nio_sctp_getladdrs(fd, 0, (void **)&addr_buf)) == -1) {
+#else /* __linux__ */
     if ((addrCount = nio_sctp_getladdrs(fd, 0, (struct sockaddr **)&addr_buf)) == -1) {
+#endif
         handleSocketError(env, errno);
         return NULL;
     }
@@ -409,7 +413,11 @@
     int i, addrCount;
     jobjectArray isaa;
 
+#if defined(__solaris__)
+    if ((addrCount = nio_sctp_getpaddrs(fd, id, (void **)&addr_buf)) == -1) {
+#else /* __linux__ */
     if ((addrCount = nio_sctp_getpaddrs(fd, id, (struct sockaddr **)&addr_buf)) == -1) {
+#endif
         handleSocketError(env, errno);
         return NULL;
     }
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java jdk18u-jdk-18.0.2.1-ga/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.security.auth/share/classes/com/sun/security/auth/module/Krb5LoginModule.java	2024-08-17 18:29:44.532435688 +0200
@@ -104,7 +104,7 @@
  * to false if you do not want this module to use the ticket cache.
  * (Default is False).
  * This module will search for the ticket
- * cache in the following locations: On Linux
+ * cache in the following locations: On Solaris and Linux
  * it will look for the ticket cache in /tmp/krb5cc_{@code uid}
  * where the uid is numeric user identifier. If the ticket cache is
  * not available in the above location, or if we are on a
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.security.auth/unix/native/libjaas/Unix.c jdk18u-jdk-18.0.2.1-ga/src/jdk.security.auth/unix/native/libjaas/Unix.c
--- jdk18u-jdk-18.0.2.1-ga.orig/src/jdk.security.auth/unix/native/libjaas/Unix.c	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/jdk.security.auth/unix/native/libjaas/Unix.c	2024-08-17 18:29:44.532923400 +0200
@@ -32,6 +32,10 @@
 #include <stdlib.h>
 #include <string.h>
 
+/* For POSIX-compliant getpwuid_r on Solaris */
+#if defined(__solaris__)
+#define _POSIX_PTHREAD_SEMANTICS
+#endif
 #include <pwd.h>
 
 /*
diff -Nru jdk18u-jdk-18.0.2.1-ga.orig/src/utils/hsdis/Makefile jdk18u-jdk-18.0.2.1-ga/src/utils/hsdis/Makefile
--- jdk18u-jdk-18.0.2.1-ga.orig/src/utils/hsdis/Makefile	2022-08-16 01:13:26.000000000 +0200
+++ jdk18u-jdk-18.0.2.1-ga/src/utils/hsdis/Makefile	2024-08-17 18:29:44.533479278 +0200
@@ -45,13 +45,33 @@
 #
 #
 
-# Single gnu makefile for linux and windows (windows requires cygwin and mingw)
+# Single gnu makefile for solaris, linux and windows (windows requires cygwin and mingw)
 
 # Default arch; it is changed below as needed.
 ARCH		= i386
 OS		= $(shell uname)
 AR		= ar
 
+## OS = SunOS ##
+ifeq		($(OS),SunOS)
+CPU             = $(shell uname -p)
+ARCH1=$(CPU:i586=i386)
+ARCH=$(ARCH1:i686=i386)
+OS		= solaris
+CC 		= cc
+CFLAGS		+= -KPIC
+ifdef LP64
+ifeq ($(ARCH),i386)
+ARCH            = amd64
+endif
+endif
+CFLAGS/amd64	+= -m64
+CFLAGS		+= $(CFLAGS/$(ARCH))
+DLDFLAGS	+= -G
+LDFLAGS         += -ldl
+OUTFLAGS	+= -o $@
+LIB_EXT		= .so
+else
 ## OS = Linux ##
 ifeq		($(OS),Linux)
 ifneq           ($(MINGW),)
@@ -145,6 +165,7 @@
 endif   # Darwin
 endif   # AIX
 endif	# Linux
+endif	# SunOS
 
 LIBARCH		= $(ARCH)
 ifdef		LP64
