diff -Nru jdk24u-jdk-24-29.orig/bin/unshuffle_list.txt jdk24u-jdk-24-29/bin/unshuffle_list.txt
--- jdk24u-jdk-24-29.orig/bin/unshuffle_list.txt	2024-12-29 15:19:41.076403399 +0100
+++ jdk24u-jdk-24-29/bin/unshuffle_list.txt	2024-12-29 15:20:25.047019940 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/autoconf/basic_tools.m4 jdk24u-jdk-24-29/make/autoconf/basic_tools.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/basic_tools.m4	2024-12-29 15:19:41.040717954 +0100
+++ jdk24u-jdk-24-29/make/autoconf/basic_tools.m4	2024-12-29 15:20:25.048607639 +0100
@@ -291,6 +291,8 @@
     TAR_TYPE="bsd"
   elif test "x$($TAR --version | $GREP "busybox")" != "x"; then
     TAR_TYPE="busybox"
+  elif test "x$OPENJDK_BUILD_OS" = "xsolaris"; then
+    TAR_TYPE="solaris"
   elif test "x$OPENJDK_BUILD_OS" = "xaix"; then
     TAR_TYPE="aix"
   fi
diff -Nru jdk24u-jdk-24-29.orig/make/autoconf/build-aux/config.guess jdk24u-jdk-24-29/make/autoconf/build-aux/config.guess
--- jdk24u-jdk-24-29.orig/make/autoconf/build-aux/config.guess	2024-12-29 15:19:41.044566791 +0100
+++ jdk24u-jdk-24-29/make/autoconf/build-aux/config.guess	2024-12-29 15:20:25.048987320 +0100
@@ -53,6 +53,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 jdk24u-jdk-24-29.orig/make/autoconf/build-performance.m4 jdk24u-jdk-24-29/make/autoconf/build-performance.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/build-performance.m4	2024-12-29 15:19:41.041131762 +0100
+++ jdk24u-jdk-24-29/make/autoconf/build-performance.m4	2024-12-29 15:20:25.049450916 +0100
@@ -33,6 +33,9 @@
     if test "$NUM_CORES" -eq "0"; then
       NUM_CORES=`cat /proc/cpuinfo  | grep -c ^CPU`
     fi
+  elif test -x /usr/sbin/psrinfo; then
+    # Looks like a Solaris system
+    NUM_CORES=`/usr/sbin/psrinfo -v | grep -c on-line`
   elif test -x /usr/sbin/sysctl; then
     # Looks like a MacOSX system
     NUM_CORES=`/usr/sbin/sysctl -n hw.ncpu`
@@ -65,7 +68,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 jdk24u-jdk-24-29.orig/make/autoconf/flags-cflags.m4 jdk24u-jdk-24-29/make/autoconf/flags-cflags.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/flags-cflags.m4	2024-12-29 15:19:41.045782859 +0100
+++ jdk24u-jdk-24-29/make/autoconf/flags-cflags.m4	2024-12-29 15:20:25.049992802 +0100
@@ -459,6 +459,9 @@
   if test "x$OPENJDK_TARGET_OS" = xlinux; then
     CFLAGS_OS_DEF_JVM="-DLINUX -D_FILE_OFFSET_BITS=64"
     CFLAGS_OS_DEF_JDK="-D_GNU_SOURCE -D_REENTRANT -D_FILE_OFFSET_BITS=64"
+  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 jdk24u-jdk-24-29.orig/make/autoconf/jdk-options.m4 jdk24u-jdk-24-29/make/autoconf/jdk-options.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/jdk-options.m4	2024-12-29 15:19:41.046187773 +0100
+++ jdk24u-jdk-24-29/make/autoconf/jdk-options.m4	2024-12-29 15:20:25.050527202 +0100
@@ -280,7 +280,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
@@ -293,7 +293,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 jdk24u-jdk-24-29.orig/make/autoconf/libraries.m4 jdk24u-jdk-24-29/make/autoconf/libraries.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/libraries.m4	2024-12-29 15:19:41.043836607 +0100
+++ jdk24u-jdk-24-29/make/autoconf/libraries.m4	2024-12-29 15:20:25.050972546 +0100
@@ -133,13 +133,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
@@ -156,6 +158,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 powrprof.lib uuid.lib \
diff -Nru jdk24u-jdk-24-29.orig/make/autoconf/platform.m4 jdk24u-jdk-24-29/make/autoconf/platform.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/platform.m4	2024-12-29 15:19:41.041696476 +0100
+++ jdk24u-jdk-24-29/make/autoconf/platform.m4	2024-12-29 15:20:25.051524163 +0100
@@ -202,6 +202,10 @@
       VAR_OS=linux
       VAR_OS_TYPE=unix
       ;;
+    *solaris*)
+      VAR_OS=solaris
+      VAR_OS_TYPE=unix
+      ;;
     *darwin*)
       VAR_OS=macosx
       VAR_OS_TYPE=unix
@@ -472,6 +476,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
@@ -603,6 +618,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
diff -Nru jdk24u-jdk-24-29.orig/make/autoconf/toolchain.m4 jdk24u-jdk-24-29/make/autoconf/toolchain.m4
--- jdk24u-jdk-24-29.orig/make/autoconf/toolchain.m4	2024-12-29 15:19:41.043116614 +0100
+++ jdk24u-jdk-24-29/make/autoconf/toolchain.m4	2024-12-29 15:20:25.052038752 +0100
@@ -39,6 +39,7 @@
 
 # These toolchains are valid on different platforms
 VALID_TOOLCHAINS_linux="gcc clang"
+VALID_TOOLCHAINS_solaris="gcc"
 VALID_TOOLCHAINS_macosx="clang"
 VALID_TOOLCHAINS_aix="clang"
 VALID_TOOLCHAINS_windows="microsoft"
diff -Nru jdk24u-jdk-24-29.orig/make/common/FileUtils.gmk jdk24u-jdk-24-29/make/common/FileUtils.gmk
--- jdk24u-jdk-24-29.orig/make/common/FileUtils.gmk	2024-12-29 15:19:40.996796014 +0100
+++ jdk24u-jdk-24-29/make/common/FileUtils.gmk	2024-12-29 15:20:25.052495522 +0100
@@ -114,7 +114,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 jdk24u-jdk-24-29.orig/make/common/modules/LauncherCommon.gmk jdk24u-jdk-24-29/make/common/modules/LauncherCommon.gmk
--- jdk24u-jdk-24-29.orig/make/common/modules/LauncherCommon.gmk	2024-12-29 15:19:40.993653222 +0100
+++ jdk24u-jdk-24-29/make/common/modules/LauncherCommon.gmk	2024-12-29 15:20:25.052964745 +0100
@@ -143,6 +143,7 @@
           -DLAUNCHER_NAME='"$$(LAUNCHER_NAME)"' \
           -DPROGNAME='"$1"' \
           $$($1_CFLAGS), \
+      CFLAGS_solaris := -fPIC, \
       CFLAGS_windows := $$($1_CFLAGS_windows), \
       EXTRA_HEADER_DIRS := java.base:libjvm, \
       DISABLED_WARNINGS_gcc := unused-function unused-variable, \
@@ -150,12 +151,14 @@
       LDFLAGS := $$($1_LDFLAGS), \
       LDFLAGS_linux := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
       LDFLAGS_macosx := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
+      LDFLAGS_solaris := $$(call SET_EXECUTABLE_ORIGIN,/../lib), \
       LDFLAGS_FILTER_OUT := $$($1_LDFLAGS_FILTER_OUT), \
       JDK_LIBS := $$($1_JDK_LIBS), \
       JDK_LIBS_windows := $$($1_JDK_LIBS_windows), \
       LIBS := $$($1_LIBS), \
       LIBS_unix := $(LIBZ_LIBS), \
       LIBS_linux := $(LIBDL) -lpthread, \
+      LIBS_solaris := $(LIBDL) -lthread, \
       LIBS_macosx := \
           -framework ApplicationServices \
           -framework Cocoa \
diff -Nru jdk24u-jdk-24-29.orig/make/hotspot/gensrc/GensrcAdlc.gmk jdk24u-jdk-24-29/make/hotspot/gensrc/GensrcAdlc.gmk
--- jdk24u-jdk-24-29.orig/make/hotspot/gensrc/GensrcAdlc.gmk	2024-12-29 15:19:41.052346251 +0100
+++ jdk24u-jdk-24-29/make/hotspot/gensrc/GensrcAdlc.gmk	2024-12-29 15:20:25.053429759 +0100
@@ -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)
     ifeq ($(TOOLCHAIN_TYPE), clang)
       ADLC_LDFLAGS += -m64
@@ -101,6 +104,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 jdk24u-jdk-24-29.orig/make/hotspot/gensrc/GensrcDtrace.gmk jdk24u-jdk-24-29/make/hotspot/gensrc/GensrcDtrace.gmk
--- jdk24u-jdk-24-29.orig/make/hotspot/gensrc/GensrcDtrace.gmk	2024-12-29 15:19:41.052187375 +0100
+++ jdk24u-jdk-24-29/make/hotspot/gensrc/GensrcDtrace.gmk	2024-12-29 15:20:25.053868654 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/hotspot/lib/CompileDtraceLibraries.gmk jdk24u-jdk-24-29/make/hotspot/lib/CompileDtraceLibraries.gmk
--- jdk24u-jdk-24-29.orig/make/hotspot/lib/CompileDtraceLibraries.gmk	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/hotspot/lib/CompileDtraceLibraries.gmk	2024-12-29 15:20:25.106492623 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/hotspot/lib/CompileJvm.gmk jdk24u-jdk-24-29/make/hotspot/lib/CompileJvm.gmk
--- jdk24u-jdk-24-29.orig/make/hotspot/lib/CompileJvm.gmk	2024-12-29 15:19:41.051115056 +0100
+++ jdk24u-jdk-24-29/make/hotspot/lib/CompileJvm.gmk	2024-12-29 15:20:25.054350436 +0100
@@ -31,6 +31,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).
 
@@ -173,6 +176,7 @@
     EXCLUDES := $(JVM_EXCLUDES), \
     EXCLUDE_FILES := $(JVM_EXCLUDE_FILES), \
     EXCLUDE_PATTERNS := $(JVM_EXCLUDE_PATTERNS), \
+    EXTRA_OBJECT_FILES := $(DTRACE_EXTRA_OBJECT_FILES), \
     DEFAULT_CFLAGS := false, \
     CFLAGS := $(JVM_CFLAGS), \
     abstract_vm_version.cpp_CXXFLAGS := $(CFLAGS_VM_VERSION), \
diff -Nru jdk24u-jdk-24-29.orig/make/hotspot/lib/CompileLibraries.gmk jdk24u-jdk-24-29/make/hotspot/lib/CompileLibraries.gmk
--- jdk24u-jdk-24-29.orig/make/hotspot/lib/CompileLibraries.gmk	2024-12-29 15:19:41.051718945 +0100
+++ jdk24u-jdk-24-29/make/hotspot/lib/CompileLibraries.gmk	2024-12-29 15:20:25.054691054 +0100
@@ -32,6 +32,7 @@
 include HotspotCommon.gmk
 
 include lib/CompileJvm.gmk
+include lib/CompileDtraceLibraries.gmk
 
 ifneq ($(GTEST_FRAMEWORK_SRC), )
   ifneq ($(CREATING_BUILDJDK), true)
diff -Nru jdk24u-jdk-24-29.orig/make/hotspot/lib/JvmDtraceObjects.gmk jdk24u-jdk-24-29/make/hotspot/lib/JvmDtraceObjects.gmk
--- jdk24u-jdk-24-29.orig/make/hotspot/lib/JvmDtraceObjects.gmk	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/hotspot/lib/JvmDtraceObjects.gmk	2024-12-29 15:20:25.106783253 +0100
@@ -0,0 +1,122 @@
+#
+# 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
+
+    # 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 jdk24u-jdk-24-29.orig/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp jdk24u-jdk-24-29/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp
--- jdk24u-jdk-24-29.orig/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/hotspot/src/native/dtrace/generateJvmOffsets.cpp	2024-12-29 15:20:25.107269598 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/hotspot/symbols/symbols-solaris jdk24u-jdk-24-29/make/hotspot/symbols/symbols-solaris
--- jdk24u-jdk-24-29.orig/make/hotspot/symbols/symbols-solaris	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/hotspot/symbols/symbols-solaris	2024-12-29 15:20:25.107563620 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler1 jdk24u-jdk-24-29/make/hotspot/symbols/symbols-solaris-dtrace-compiler1
--- jdk24u-jdk-24-29.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler1	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/hotspot/symbols/symbols-solaris-dtrace-compiler1	2024-12-29 15:20:25.107801381 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler2 jdk24u-jdk-24-29/make/hotspot/symbols/symbols-solaris-dtrace-compiler2
--- jdk24u-jdk-24-29.orig/make/hotspot/symbols/symbols-solaris-dtrace-compiler2	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/hotspot/symbols/symbols-solaris-dtrace-compiler2	2024-12-29 15:20:25.108039628 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/ide/visualstudio/hotspot/CreateVSProject.gmk jdk24u-jdk-24-29/make/ide/visualstudio/hotspot/CreateVSProject.gmk
--- jdk24u-jdk-24-29.orig/make/ide/visualstudio/hotspot/CreateVSProject.gmk	2024-12-29 15:19:40.989281916 +0100
+++ jdk24u-jdk-24-29/make/ide/visualstudio/hotspot/CreateVSProject.gmk	2024-12-29 15:20:25.055136902 +0100
@@ -76,6 +76,7 @@
     -ignorePath linux \
     -ignorePath posix \
     -ignorePath ppc \
+    -ignorePath solaris \
     -ignorePath x86_32 \
     -ignorePath zero \
       #
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.base/Copy.gmk jdk24u-jdk-24-29/make/modules/java.base/Copy.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.base/Copy.gmk	2024-12-29 15:19:40.941628254 +0100
+++ jdk24u-jdk-24-29/make/modules/java.base/Copy.gmk	2024-12-29 15:20:25.055545714 +0100
@@ -148,7 +148,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 jdk24u-jdk-24-29.orig/make/modules/java.base/gensrc/GensrcMisc.gmk jdk24u-jdk-24-29/make/modules/java.base/gensrc/GensrcMisc.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.base/gensrc/GensrcMisc.gmk	2024-12-29 15:19:40.942589672 +0100
+++ jdk24u-jdk-24-29/make/modules/java.base/gensrc/GensrcMisc.gmk	2024-12-29 15:20:25.056346896 +0100
@@ -136,6 +136,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 jdk24u-jdk-24-29.orig/make/modules/java.base/lib/CoreLibraries.gmk jdk24u-jdk-24-29/make/modules/java.base/lib/CoreLibraries.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.base/lib/CoreLibraries.gmk	2024-12-29 15:19:40.943721691 +0100
+++ jdk24u-jdk-24-29/make/modules/java.base/lib/CoreLibraries.gmk	2024-12-29 15:20:25.056869920 +0100
@@ -28,7 +28,7 @@
 ################################################################################
 
 LIBVERIFY_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, linux)+$(COMPILE_WITH_DEBUG_SYMBOLS), true+true)
+ifeq ($(call isTargetOs, solaris linux)+$(COMPILE_WITH_DEBUG_SYMBOLS), true+true)
   LIBVERIFY_OPTIMIZATION := LOW
 endif
 
@@ -63,6 +63,7 @@
     DISABLED_WARNINGS_clang_TimeZone_md.c := unused-variable, \
     JDK_LIBS := libjvm, \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := -lsocket -lnsl -lscf $(LIBDL), \
     LIBS_aix := $(LIBDL) $(LIBM), \
     LIBS_macosx := \
         -framework CoreFoundation \
@@ -183,6 +184,7 @@
     DISABLED_WARNINGS_clang_java_md_macosx.m := unused-variable, \
     LIBS_unix := $(LIBZ_LIBS), \
     LIBS_linux := $(LIBDL) -lpthread, \
+    LIBS_solaris := $(LIBDL), \
     LIBS_macosx := \
         -framework ApplicationServices \
         -framework Cocoa \
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.base/Lib.gmk jdk24u-jdk-24-29/make/modules/java.base/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.base/Lib.gmk	2024-12-29 15:19:40.944753774 +0100
+++ jdk24u-jdk-24-29/make/modules/java.base/Lib.gmk	2024-12-29 15:20:25.055981968 +0100
@@ -58,6 +58,7 @@
         -delayload:winhttp.dll, \
     JDK_LIBS := libjava libjvm, \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := -lnsl -lsocket $(LIBDL), \
     LIBS_aix := $(LIBDL), \
     LIBS_windows := advapi32.lib delayimp.lib iphlpapi.lib secur32.lib \
         winhttp.lib ws2_32.lib, \
@@ -81,8 +82,9 @@
         libjvm, \
     DISABLED_WARNINGS_clang_Net.c := unused-function unused-variable, \
     DISABLED_WARNINGS_clang_UnixNativeDispatcher.c := unused-variable, \
-    JDK_LIBS := libjava libnet, \
+    JDK_LIBS := libjava libjvm libnet, \
     LIBS_linux := $(LIBDL) -lpthread, \
+    LIBS_solaris := -lsocket -lposix4 $(LIBDL) -lsendfile, \
     LIBS_aix := $(LIBDL), \
     LIBS_macosx := \
         -framework CoreFoundation \
@@ -124,6 +126,7 @@
       DISABLED_WARNINGS_gcc_jsig.c := unused-but-set-variable, \
       DISABLED_WARNINGS_clang_jsig.c := unused-but-set-variable, \
       LIBS_linux := $(LIBDL), \
+      LIBS_solaris := $(LIBDL), \
       LIBS_aix := $(LIBDL), \
   ))
 
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.desktop/Gensrc.gmk jdk24u-jdk-24-29/make/modules/java.desktop/Gensrc.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.desktop/Gensrc.gmk	2024-12-29 15:19:40.967927385 +0100
+++ jdk24u-jdk-24-29/make/modules/java.desktop/Gensrc.gmk	2024-12-29 15:20:25.057303377 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/modules/java.desktop/lib/AwtLibraries.gmk jdk24u-jdk-24-29/make/modules/java.desktop/lib/AwtLibraries.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.desktop/lib/AwtLibraries.gmk	2024-12-29 15:19:40.968409202 +0100
+++ jdk24u-jdk-24-29/make/modules/java.desktop/lib/AwtLibraries.gmk	2024-12-29 15:20:25.058308807 +0100
@@ -57,7 +57,7 @@
       #
 endif
 
-ifeq ($(call isTargetOs, linux macosx aix), true)
+ifeq ($(call isTargetOs, solaris linux macosx aix), true)
   LIBAWT_EXCLUDE_FILES += awt_Font.c CUPSfuncs.c fontpath.c X11Color.c
 endif
 
@@ -123,6 +123,7 @@
     JDK_LIBS := java.base:libjava java.base:libjvm, \
     LIBS_unix := $(LIBM), \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := $(LIBDL), \
     LIBS_aix := $(LIBDL), \
     LIBS_macosx := \
         -framework ApplicationServices \
@@ -188,8 +189,9 @@
       DISABLED_WARNINGS_gcc_X11SurfaceData.c := unused-function, \
       DISABLED_WARNINGS_clang_X11Renderer.c := unused-function, \
       DISABLED_WARNINGS_clang_X11SurfaceData.c := unused-function, \
-      JDK_LIBS := libawt java.base:libjava, \
+      JDK_LIBS := libawt java.base:libjava java.base:libjvm, \
       LIBS_linux := $(LIBDL) $(LIBM), \
+      LIBS_solaris := $(LIBDL) $(LIBM) $(LIBCXX), \
       STATIC_LIB_EXCLUDE_OBJS := $(LIBAWT_HEADLESS_STATIC_EXCLUDE_OBJS), \
   ))
 
@@ -278,7 +280,7 @@
       DISABLED_WARNINGS_clang_aix_sun_awt_X11_GtkFileDialogPeer.c := \
           parentheses, \
       DISABLED_WARNINGS_clang_aix_awt_InputMethod.c := unused-function sign-compare, \
-      JDK_LIBS := libawt java.base:libjava, \
+      JDK_LIBS := libawt java.base:libjava java.base:libjvm, \
       LIBS_unix := $(LIBDL) $(LIBM) $(X_LIBS) -lX11 -lXext -lXi -lXrender \
           -lXtst, \
       LIBS_linux := -lpthread, \
@@ -399,7 +401,7 @@
 endif
 
 ifeq ($(call isTargetOsType, unix)+$(call isTargetOs, macosx), true+false)
-  LIBJAWT_JDK_LIBS_unix := libawt
+  LIBJAWT_JDK_LIBS_unix := libawt java.base:libjava java.base:libjvm
   ifeq ($(ENABLE_HEADLESS_ONLY), false)
     LIBJAWT_JDK_LIBS_unix += libawt_xawt
   else
@@ -419,6 +421,7 @@
     LDFLAGS_windows := $(LDFLAGS_CXX_JDK), \
     LDFLAGS_macosx := -Wl$(COMMA)-rpath$(COMMA)@loader_path, \
     JDK_LIBS_unix := $(LIBJAWT_JDK_LIBS_unix), \
+    LIBS_solaris := $(X_LIBS) -lXrender, \
     JDK_LIBS_windows := libawt, \
     JDK_LIBS_macosx := libawt_lwawt, \
     LIBS_macosx := -framework Cocoa, \
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.desktop/lib/ClientLibraries.gmk jdk24u-jdk-24-29/make/modules/java.desktop/lib/ClientLibraries.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.desktop/lib/ClientLibraries.gmk	2024-12-29 15:19:40.968231334 +0100
+++ jdk24u-jdk-24-29/make/modules/java.desktop/lib/ClientLibraries.gmk	2024-12-29 15:20:25.058848583 +0100
@@ -88,7 +88,7 @@
     DISABLED_WARNINGS_gcc := format-nonliteral stringop-truncation type-limits \
         unused-variable, \
     DISABLED_WARNINGS_clang := format-nonliteral, \
-    JDK_LIBS := libawt java.base:libjava, \
+    JDK_LIBS := libawt java.base:libjava java.base:libjvm, \
     LIBS_unix := $(LCMS_LIBS) $(LIBM), \
 ))
 
@@ -125,7 +125,7 @@
     DISABLED_WARNINGS_gcc_jcmaster.c := implicit-fallthrough, \
     DISABLED_WARNINGS_gcc_jdphuff.c := shift-negative-value, \
     DISABLED_WARNINGS_clang_imageioJPEG.c := unused-but-set-variable, \
-    JDK_LIBS := java.base:libjava, \
+    JDK_LIBS := java.base:libjava java.base:libjvm, \
     LIBS := $(LIBJPEG_LIBS), \
 ))
 
@@ -258,6 +258,7 @@
       LIBS := $(GIFLIB_LIBS) $(LIBJPEG_LIBS) $(LIBZ_LIBS) $(PNG_LIBS), \
       LIBS_unix := $(LIBM) -lpthread, \
       LIBS_linux := $(LIBDL) $(X_LIBS) -lX11 -lXext, \
+      LIBS_solaris := $(LIBDL) $(X_LIBS) -lX11 -lXext, \
       LIBS_macosx := -liconv \
           -framework ApplicationServices \
           -framework Cocoa \
@@ -307,7 +308,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 -DHB_NO_VISIBILITY
   endif
 
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.desktop/Lib.gmk jdk24u-jdk-24-29/make/modules/java.desktop/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.desktop/Lib.gmk	2024-12-29 15:19:40.966758458 +0100
+++ jdk24u-jdk-24-29/make/modules/java.desktop/Lib.gmk	2024-12-29 15:20:25.057641020 +0100
@@ -48,10 +48,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
+
   LIBJSOUND_LINK_TYPE := C
   ifeq ($(call isTargetOs, macosx), true)
     LIBJSOUND_LINK_TYPE := C++
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.instrument/Lib.gmk jdk24u-jdk-24-29/make/modules/java.instrument/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.instrument/Lib.gmk	2024-12-29 15:19:40.960757682 +0100
+++ jdk24u-jdk-24-29/make/modules/java.instrument/Lib.gmk	2024-12-29 15:20:25.059240721 +0100
@@ -39,6 +39,7 @@
     JDK_LIBS := java.base:libjava java.base:libjli java.base:libjvm, \
     LIBS_unix := $(LIBZ_LIBS), \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := $(LIBDL), \
     LIBS_aix := $(LIBDL) -liconv, \
     LIBS_macosx := -liconv \
         -framework ApplicationServices \
diff -Nru jdk24u-jdk-24-29.orig/make/modules/java.management/Lib.gmk jdk24u-jdk-24-29/make/modules/java.management/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/java.management/Lib.gmk	2024-12-29 15:19:40.969810894 +0100
+++ jdk24u-jdk-24-29/make/modules/java.management/Lib.gmk	2024-12-29 15:20:25.059651103 +0100
@@ -30,7 +30,7 @@
 ################################################################################
 
 LIBMANAGEMENT_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, linux)+$(COMPILE_WITH_DEBUG_SYMBOLS), true+true)
+ifeq ($(call isTargetOs, solaris linux)+$(COMPILE_WITH_DEBUG_SYMBOLS), true+true)
   LIBMANAGEMENT_OPTIMIZATION := LOW
 endif
 
@@ -40,6 +40,7 @@
     DISABLED_WARNINGS_gcc_VMManagementImpl.c := unused-variable, \
     DISABLED_WARNINGS_clang_VMManagementImpl.c := unused-variable, \
     JDK_LIBS := java.base:libjava java.base:libjvm, \
+    LIBS_solaris := -lkstat, \
     LIBS_aix := -lperfstat, \
     LIBS_windows := advapi32.lib psapi.lib, \
 ))
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.attach/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.attach/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.attach/Lib.gmk	2024-12-29 15:19:40.955644587 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.attach/Lib.gmk	2024-12-29 15:20:25.060027203 +0100
@@ -41,7 +41,8 @@
     OPTIMIZATION := LOW, \
     CFLAGS := $(LIBATTACH_CFLAGS), \
     CFLAGS_windows := -Gy, \
-    JDK_LIBS := java.base:libjava, \
+    JDK_LIBS := java.base:libjava java.base:libjvm, \
+    LIBS_solaris := -ldoor, \
     LIBS_windows := advapi32.lib psapi.lib, \
 ))
 
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.crypto.cryptoki/Copy.gmk jdk24u-jdk-24-29/make/modules/jdk.crypto.cryptoki/Copy.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.crypto.cryptoki/Copy.gmk	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.crypto.cryptoki/Copy.gmk	2024-12-29 15:20:25.108324877 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/modules/jdk.hotspot.agent/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.hotspot.agent/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.hotspot.agent/Lib.gmk	2024-12-29 15:19:40.962661958 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.hotspot.agent/Lib.gmk	2024-12-29 15:20:25.060416388 +0100
@@ -68,8 +68,9 @@
     CFLAGS := $(LIBSAPROC_CFLAGS), \
     CXXFLAGS := $(LIBSAPROC_CFLAGS) $(LIBSAPROC_CXXFLAGS), \
     EXTRA_SRC := $(LIBSAPROC_EXTRA_SRC), \
-    JDK_LIBS := java.base:libjava, \
+    JDK_LIBS := java.base:libjava java.base:libjvm, \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := -ldl -lstdc++ -lthread -lproc, \
     LIBS_macosx := \
         -framework CoreFoundation \
         -framework Foundation \
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.jdwp.agent/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.jdwp.agent/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.jdwp.agent/Lib.gmk	2024-12-29 15:19:40.961157832 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.jdwp.agent/Lib.gmk	2024-12-29 15:20:25.060832362 +0100
@@ -37,6 +37,7 @@
         include \
         libjdwp/export, \
     LIBS_linux := -lpthread, \
+    LIBS_solaris := -lnsl -lsocket, \
     LIBS_windows := iphlpapi.lib ws2_32.lib, \
 ))
 
@@ -72,6 +73,7 @@
         java.base:libjava, \
     JDK_LIBS := java.base:libjvm, \
     LIBS_linux := $(LIBDL), \
+    LIBS_solaris := $(LIBDL), \
     LIBS_macosx := -liconv, \
     LIBS_aix := -liconv, \
 ))
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.management/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.management/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.management/Lib.gmk	2024-12-29 15:19:40.958221433 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.management/Lib.gmk	2024-12-29 15:20:25.061284036 +0100
@@ -37,7 +37,7 @@
 endif
 
 LIBMANAGEMENT_EXT_OPTIMIZATION := HIGH
-ifeq ($(call isTargetOs, linux)+$(COMPILE_WITH_DEBUG_SYMBOLS), true+true)
+ifeq ($(call isTargetOs, solaris linux)+$(COMPILE_WITH_DEBUG_SYMBOLS), true+true)
   LIBMANAGEMENT_EXT_OPTIMIZATION := LOW
 endif
 
@@ -49,6 +49,7 @@
     DISABLED_WARNINGS_clang_UnixOperatingSystem.c := format-nonliteral, \
     CFLAGS := $(LIBMANAGEMENT_EXT_CFLAGS), \
     JDK_LIBS := java.base:libjava java.base:libjvm, \
+    LIBS_solaris := -lkstat, \
     LIBS_aix := -lperfstat, \
     LIBS_windows := advapi32.lib psapi.lib, \
 ))
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.management.agent/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.management.agent/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.management.agent/Lib.gmk	2024-12-29 15:19:40.965748005 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.management.agent/Lib.gmk	2024-12-29 15:20:25.061653179 +0100
@@ -32,7 +32,7 @@
 $(eval $(call SetupJdkLibrary, BUILD_LIBMANAGEMENT_AGENT, \
     NAME := management_agent, \
     OPTIMIZATION := LOW, \
-    JDK_LIBS := java.base:libjava, \
+    JDK_LIBS := java.base:libjava java.base:libjvm, \
     LIBS_windows := advapi32.lib, \
 ))
 
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.net/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.net/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.net/Lib.gmk	2024-12-29 15:19:40.969538777 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.net/Lib.gmk	2024-12-29 15:20:25.062061531 +0100
@@ -29,6 +29,8 @@
 ## Build libextnet
 ################################################################################
 
+ifeq ($(call isTargetOs, solaris), false)
+
 $(eval $(call SetupJdkLibrary, BUILD_LIBEXTNET, \
     NAME := extnet, \
     OPTIMIZATION := LOW, \
@@ -38,3 +40,5 @@
 ))
 
 TARGETS += $(BUILD_LIBEXTNET)
+
+endif
diff -Nru jdk24u-jdk-24-29.orig/make/modules/jdk.sctp/Lib.gmk jdk24u-jdk-24-29/make/modules/jdk.sctp/Lib.gmk
--- jdk24u-jdk-24-29.orig/make/modules/jdk.sctp/Lib.gmk	2024-12-29 15:19:40.963373042 +0100
+++ jdk24u-jdk-24-29/make/modules/jdk.sctp/Lib.gmk	2024-12-29 15:20:25.062432619 +0100
@@ -40,6 +40,7 @@
           java.base:libnio/ch, \
       JDK_LIBS := java.base:libjava java.base:libnet, \
       LIBS_linux := $(LIBDL) -lpthread, \
+      LIBS_solaris := -lsocket, \
   ))
 
   TARGETS += $(BUILD_LIBSCTP)
diff -Nru jdk24u-jdk-24-29.orig/make/RunTestsPrebuilt.gmk jdk24u-jdk-24-29/make/RunTestsPrebuilt.gmk
--- jdk24u-jdk-24-29.orig/make/RunTestsPrebuilt.gmk	2024-12-29 15:19:40.972763429 +0100
+++ jdk24u-jdk-24-29/make/RunTestsPrebuilt.gmk	2024-12-29 15:20:25.047687299 +0100
@@ -168,6 +168,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
@@ -180,15 +182,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)
@@ -213,6 +228,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 jdk24u-jdk-24-29.orig/make/RunTestsPrebuiltSpec.gmk jdk24u-jdk-24-29/make/RunTestsPrebuiltSpec.gmk
--- jdk24u-jdk-24-29.orig/make/RunTestsPrebuiltSpec.gmk	2024-12-29 15:19:40.502513991 +0100
+++ jdk24u-jdk-24-29/make/RunTestsPrebuiltSpec.gmk	2024-12-29 15:20:25.048055505 +0100
@@ -173,6 +173,16 @@
 FILE := file
 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 jdk24u-jdk-24-29.orig/make/scripts/compare.sh jdk24u-jdk-24-29/make/scripts/compare.sh
--- jdk24u-jdk-24-29.orig/make/scripts/compare.sh	2024-12-29 15:19:40.999058715 +0100
+++ jdk24u-jdk-24-29/make/scripts/compare.sh	2024-12-29 15:20:25.063307605 +0100
@@ -75,7 +75,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
   DIS_DIFF_FILTER="$SED -r \
       -e 's/^  [0-9A-F]{16}: //' \
       -e 's/\[[0-9A-F]{4,16}h\]/[<HEXSTR>]/' \
@@ -385,7 +392,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)
@@ -407,8 +421,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=
@@ -756,6 +776,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 jdk24u-jdk-24-29.orig/make/scripts/hide_important_warnings_from_javac.sh jdk24u-jdk-24-29/make/scripts/hide_important_warnings_from_javac.sh
--- jdk24u-jdk-24-29.orig/make/scripts/hide_important_warnings_from_javac.sh	2024-12-29 15:19:40.998265976 +0100
+++ jdk24u-jdk-24-29/make/scripts/hide_important_warnings_from_javac.sh	2024-12-29 15:20:25.063631963 +0100
@@ -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 jdk24u-jdk-24-29.orig/make/test/JtregNativeHotspot.gmk jdk24u-jdk-24-29/make/test/JtregNativeHotspot.gmk
--- jdk24u-jdk-24-29.orig/make/test/JtregNativeHotspot.gmk	2024-12-29 15:19:40.972190461 +0100
+++ jdk24u-jdk-24-29/make/test/JtregNativeHotspot.gmk	2024-12-29 15:20:25.064365661 +0100
@@ -883,6 +883,10 @@
 BUILD_HOTSPOT_JTREG_LIBRARIES_JDK_LIBS_libatExit := java.base:libjvm
 BUILD_HOTSPOT_JTREG_EXECUTABLES_JDK_LIBS_exedaemonDestroy := java.base:libjvm
 
+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 libCompleteExit.c libMonitorWithDeadObjectTest.c libTestPsig.c exeGetCreatedJavaVMs.c libTestUnloadedClass.cpp
diff -Nru jdk24u-jdk-24-29.orig/make/test/JtregNativeJdk.gmk jdk24u-jdk-24-29/make/test/JtregNativeJdk.gmk
--- jdk24u-jdk-24-29.orig/make/test/JtregNativeJdk.gmk	2024-12-29 15:19:40.972486023 +0100
+++ jdk24u-jdk-24-29/make/test/JtregNativeJdk.gmk	2024-12-29 15:20:25.064883320 +0100
@@ -60,10 +60,10 @@
 BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeCallerAccessTest := java.base:libjvm
 BUILD_JDK_JTREG_EXECUTABLES_JDK_LIBS_exeNullCallerTest := java.base:libjvm
 
-BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libstringPlatformChars := java.base:libjava
+BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libstringPlatformChars := java.base:libjava java.base:libjvm
 BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libTracePinnedThreads := java.base:libjvm
-BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libNewDirectByteBuffer := java.base:libjava
-BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libGetXSpace := java.base:libjava
+BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libNewDirectByteBuffer := java.base:libjava java.base:libjvm
+BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libGetXSpace := java.base:libjava java.base:libjvm
 
 # Platform specific setup
 ifeq ($(call isTargetOs, windows), true)
@@ -75,7 +75,7 @@
   BUILD_JDK_JTREG_EXECUTABLES_LIBS_exerevokeall := advapi32.lib
   BUILD_JDK_JTREG_EXECUTABLES_CFLAGS_exeNullCallerTest := /EHsc
 else
-  BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libDirectIO := java.base:libjava
+  BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libDirectIO := java.base:libjava java.base:libjvm
   BUILD_JDK_JTREG_LIBRARIES_LDFLAGS_libNativeThread := -pthread
 
   # java.lang.foreign tests
@@ -92,6 +92,9 @@
   ifeq ($(call isTargetOs, linux), true)
     BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libInheritedChannel := java.base:libjava
     BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -ldl
+  else ifeq ($(call isTargetOs, solaris), true)
+    BUILD_JDK_JTREG_LIBRARIES_JDK_LIBS_libInheritedChannel := java.base:libjava java.base:libjvm
+    BUILD_JDK_JTREG_EXECUTABLES_LIBS_exelauncher := -lsocket -lnsl -lthread -ldl
   endif
   BUILD_JDK_JTREG_EXECUTABLES_LIBS_exeNullCallerTest := $(LIBCXX)
 endif
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/cpu/x86/globalDefinitions_x86.hpp jdk24u-jdk-24-29/src/hotspot/cpu/x86/globalDefinitions_x86.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/cpu/x86/globalDefinitions_x86.hpp	2024-12-29 15:19:43.881468590 +0100
+++ jdk24u-jdk-24-29/src/hotspot/cpu/x86/globalDefinitions_x86.hpp	2024-12-29 15:20:25.065428060 +0100
@@ -54,7 +54,7 @@
 #define DEFAULT_PADDING_SIZE DEFAULT_CACHE_LINE_SIZE
 #endif
 
-#if defined(LINUX) || defined(__APPLE__)
+#if defined(LINUX) || defined(SOLARIS) || defined(__APPLE__)
 #define SUPPORT_RESERVED_STACK_AREA
 #endif
 
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/os/posix/include/jvm_md.h jdk24u-jdk-24-29/src/hotspot/os/posix/include/jvm_md.h
--- jdk24u-jdk-24-29.orig/src/hotspot/os/posix/include/jvm_md.h	2024-12-29 15:19:43.850726619 +0100
+++ jdk24u-jdk-24-29/src/hotspot/os/posix/include/jvm_md.h	2024-12-29 15:20:25.065874413 +0100
@@ -47,7 +47,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
@@ -80,6 +80,9 @@
 #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
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/os/posix/os_posix.cpp jdk24u-jdk-24-29/src/hotspot/os/posix/os_posix.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/os/posix/os_posix.cpp	2024-12-29 15:19:43.851756327 +0100
+++ jdk24u-jdk-24-29/src/hotspot/os/posix/os_posix.cpp	2024-12-29 15:20:25.066524583 +0100
@@ -596,7 +596,7 @@
   st->print("%ld", sysconf(_SC_CHILD_MAX));
 
   print_rlimit(st, ", THREADS", RLIMIT_THREADS);
-#else
+#elif !defined(SOLARIS)
   print_rlimit(st, ", NPROC", RLIMIT_NPROC);
 #endif
 
@@ -614,6 +614,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);
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/os/posix/os_posix.inline.hpp jdk24u-jdk-24-29/src/hotspot/os/posix/os_posix.inline.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/os/posix/os_posix.inline.hpp	2024-12-29 15:19:43.853207918 +0100
+++ jdk24u-jdk-24-29/src/hotspot/os/posix/os_posix.inline.hpp	2024-12-29 15:20:25.066856941 +0100
@@ -34,8 +34,10 @@
 #include <sys/socket.h>
 #include <netdb.h>
 
+#ifndef SOLARIS
 // Aix does not have NUMA support but need these for compilation.
 inline bool os::numa_has_group_homing()     { AIX_ONLY(ShouldNotReachHere();) return false;  }
+#endif // !SOLARIS
 
 // Platform Mutex/Monitor implementation
 
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/os/posix/vmError_posix.cpp jdk24u-jdk-24-29/src/hotspot/os/posix/vmError_posix.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/os/posix/vmError_posix.cpp	2024-12-29 15:19:43.852643683 +0100
+++ jdk24u-jdk-24-29/src/hotspot/os/posix/vmError_posix.cpp	2024-12-29 15:20:25.067184764 +0100
@@ -41,6 +41,9 @@
 #include <sys/syscall.h>
 #include <unistd.h>
 #endif
+#ifdef SOLARIS
+#include <thread.h>
+#endif
 #ifdef AIX
 #include <unistd.h>
 #endif
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/c1/c1_LIR.cpp jdk24u-jdk-24-29/src/hotspot/share/c1/c1_LIR.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/c1/c1_LIR.cpp	2024-12-29 15:19:44.561293086 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/c1/c1_LIR.cpp	2024-12-29 15:20:25.067897390 +0100
@@ -452,6 +452,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() != nullptr, "must be");
       LIR_Op1* op1 = (LIR_Op1*)op;
@@ -1736,6 +1738,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 jdk24u-jdk-24-29.orig/src/hotspot/share/c1/c1_LIR.hpp jdk24u-jdk-24-29/src/hotspot/share/c1/c1_LIR.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/c1/c1_LIR.hpp	2024-12-29 15:19:44.562078817 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/c1/c1_LIR.hpp	2024-12-29 15:20:25.068700119 +0100
@@ -940,6 +940,8 @@
       , lir_monaddr
       , lir_roundfp
       , lir_safepoint
+      , lir_pack64
+      , lir_unpack64
       , lir_unwind
       , lir_load_klass
   , end_op1
@@ -2239,6 +2241,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 jdk24u-jdk-24-29.orig/src/hotspot/share/cds/classListParser.cpp jdk24u-jdk-24-29/src/hotspot/share/cds/classListParser.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/cds/classListParser.cpp	2024-12-29 15:19:44.325037907 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/cds/classListParser.cpp	2024-12-29 15:20:25.069282551 +0100
@@ -493,7 +493,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 jdk24u-jdk-24-29.orig/src/hotspot/share/nmt/memTracker.cpp jdk24u-jdk-24-29/src/hotspot/share/nmt/memTracker.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/nmt/memTracker.cpp	2024-12-29 15:19:44.514278783 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/nmt/memTracker.cpp	2024-12-29 15:20:25.070636942 +0100
@@ -48,6 +48,12 @@
 #include <windows.h>
 #endif
 
+#ifdef SOLARIS
+  volatile bool NMT_stack_walkable = false;
+#else
+  volatile bool NMT_stack_walkable = true;
+#endif
+
 NMT_TrackingLevel MemTracker::_tracking_level = NMT_unknown;
 
 MemBaseline MemTracker::_baseline;
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/nmt/memTracker.hpp jdk24u-jdk-24-29/src/hotspot/share/nmt/memTracker.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/nmt/memTracker.hpp	2024-12-29 15:19:44.515838269 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/nmt/memTracker.hpp	2024-12-29 15:20:25.070989421 +0100
@@ -35,9 +35,11 @@
 #include "utilities/debug.hpp"
 #include "utilities/nativeCallStack.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) : FAKE_CALLSTACK)
-#define CALLER_PC  ((MemTracker::tracking_level() == NMT_detail) ?  \
+#define CALLER_PC  ((MemTracker::tracking_level() == NMT_detail && NMT_stack_walkable) ?  \
                     NativeCallStack(1) : FAKE_CALLSTACK)
 
 class MemBaseline;
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/runtime/abstract_vm_version.cpp jdk24u-jdk-24-29/src/hotspot/share/runtime/abstract_vm_version.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/runtime/abstract_vm_version.cpp	2024-12-29 15:19:44.432849856 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/runtime/abstract_vm_version.cpp	2024-12-29 15:20:25.069877513 +0100
@@ -171,6 +171,7 @@
 
 #define OS       LINUX_ONLY("linux")             \
                  WINDOWS_ONLY("windows")         \
+                 SOLARIS_ONLY("solaris")         \
                  AIX_ONLY("aix")                 \
                  BSD_ONLY("bsd")
 
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/runtime/semaphore.hpp jdk24u-jdk-24-29/src/hotspot/share/runtime/semaphore.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/runtime/semaphore.hpp	2024-12-29 15:19:44.435349254 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/runtime/semaphore.hpp	2024-12-29 15:20:25.070209400 +0100
@@ -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"
 #else
 # include OS_HEADER(semaphore)
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/services/dtraceAttacher.cpp jdk24u-jdk-24-29/src/hotspot/share/services/dtraceAttacher.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/services/dtraceAttacher.cpp	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/services/dtraceAttacher.cpp	2024-12-29 15:20:25.108656505 +0100
@@ -0,0 +1,99 @@
+/*
+ * 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 the "fine grained" flags.
+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
+    DeoptimizationScope deopt_scope;
+    CodeCache::mark_all_nmethods_for_deoptimization(&deopt_scope);
+    deopt_scope.deoptimize_marked();
+  }
+}
+
+// Disable the "fine grained" flags.
+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
+    DeoptimizationScope deopt_scope;
+    CodeCache::mark_all_nmethods_for_deoptimization(&deopt_scope);
+    deopt_scope.deoptimize_marked();
+  }
+}
+
+// Do clean-up on "all door clients detached" event.
+void DTrace::detach_all_clients() {
+  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 jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/debug.cpp jdk24u-jdk-24-29/src/hotspot/share/utilities/debug.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/debug.cpp	2024-12-29 15:19:44.107612010 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/utilities/debug.cpp	2024-12-29 15:20:25.071553653 +0100
@@ -620,11 +620,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()");
   tty->print_cr("class metadata.");
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/globalDefinitions_gcc.hpp jdk24u-jdk-24-29/src/hotspot/share/utilities/globalDefinitions_gcc.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	2024-12-29 15:19:44.097041012 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/utilities/globalDefinitions_gcc.hpp	2024-12-29 15:20:25.072004166 +0100
@@ -50,15 +50,32 @@
 #endif
 #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
+
 #if defined(LINUX) || defined(_ALLBSD_SOURCE) || defined(_AIX)
 #include <signal.h>
 #ifndef __OpenBSD__
@@ -71,8 +88,73 @@
 #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
+  #undef NULL
+  #define NULL 0L
+#endif
+
+#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) || defined(_AIX)
 inline int g_isnan(float  f) { return isnan(f); }
diff -Nru jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/macros.hpp jdk24u-jdk-24-29/src/hotspot/share/utilities/macros.hpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/macros.hpp	2024-12-29 15:19:44.105856555 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/utilities/macros.hpp	2024-12-29 15:20:25.072407199 +0100
@@ -403,6 +403,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 jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/ostream.cpp jdk24u-jdk-24-29/src/hotspot/share/utilities/ostream.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/ostream.cpp	2024-12-29 15:19:44.101737493 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/utilities/ostream.cpp	2024-12-29 15:20:25.072857953 +0100
@@ -1074,7 +1074,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 jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/vmError.cpp jdk24u-jdk-24-29/src/hotspot/share/utilities/vmError.cpp
--- jdk24u-jdk-24-29.orig/src/hotspot/share/utilities/vmError.cpp	2024-12-29 15:19:44.095861158 +0100
+++ jdk24u-jdk-24-29/src/hotspot/share/utilities/vmError.cpp	2024-12-29 15:20:25.073637466 +0100
@@ -1915,6 +1915,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
@@ -1979,6 +1981,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 jdk24u-jdk-24-29.orig/src/java.base/share/classes/sun/net/sdp/SdpSupport.java jdk24u-jdk-24-29/src/java.base/share/classes/sun/net/sdp/SdpSupport.java
--- jdk24u-jdk-24-29.orig/src/java.base/share/classes/sun/net/sdp/SdpSupport.java	2024-12-29 15:19:43.498352670 +0100
+++ jdk24u-jdk-24-29/src/java.base/share/classes/sun/net/sdp/SdpSupport.java	2024-12-29 15:20:25.074112180 +0100
@@ -39,7 +39,7 @@
  */
 
 public final class SdpSupport {
-    private static final boolean isSupported = OperatingSystem.isLinux();
+    private static final boolean isSupported = (OperatingSystem.isSolaris() || OperatingSystem.isLinux());
     private static final JavaIOFileDescriptorAccess fdAccess =
         SharedSecrets.getJavaIOFileDescriptorAccess();
 
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template jdk24u-jdk-24-29/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template
--- jdk24u-jdk-24-29.orig/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template	2024-12-29 15:19:43.472817047 +0100
+++ jdk24u-jdk-24-29/src/java.base/share/classes/sun/nio/ch/SocketOptionRegistry.java.template	2024-12-29 15:20:25.074604670 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/share/conf/security/java.security jdk24u-jdk-24-29/src/java.base/share/conf/security/java.security
--- jdk24u-jdk-24-29.orig/src/java.base/share/conf/security/java.security	2024-12-29 15:19:43.537205794 +0100
+++ jdk24u-jdk-24-29/src/java.base/share/conf/security/java.security	2024-12-29 15:20:25.075192139 +0100
@@ -110,7 +110,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 jdk24u-jdk-24-29.orig/src/java.base/share/native/libjli/jli_util.h jdk24u-jdk-24-29/src/java.base/share/native/libjli/jli_util.h
--- jdk24u-jdk-24-29.orig/src/java.base/share/native/libjli/jli_util.h	2024-12-29 15:19:43.628607287 +0100
+++ jdk24u-jdk-24-29/src/java.base/share/native/libjli/jli_util.h	2024-12-29 15:20:25.075605933 +0100
@@ -100,7 +100,11 @@
 #define JLI_StrCaseCmp(p1, p2)          strcasecmp((p1), (p2))
 #define JLI_StrNCaseCmp(p1, p2, p3)     strncasecmp((p1), (p2), (p3))
 #define JLI_Open                        open
+#ifdef __solaris__
+#define JLI_Lseek                       llseek
+#else
 #define JLI_Lseek                       lseek
+#endif
 #endif /* _WIN32 */
 
 /*
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/share/native/libnet/net_util.c jdk24u-jdk-24-29/src/java.base/share/native/libnet/net_util.c
--- jdk24u-jdk-24-29.orig/src/java.base/share/native/libnet/net_util.c	2024-12-29 15:19:43.600585892 +0100
+++ jdk24u-jdk-24-29/src/java.base/share/native/libnet/net_util.c	2024-12-29 15:20:25.076024087 +0100
@@ -81,6 +81,7 @@
 
     /* check if SO_REUSEPORT is supported on this platform */
     REUSEPORT_available = reuseport_supported(IPv6_available);
+    parseExclusiveBindProperty(env);
 
     return JNI_VERSION_1_2;
 }
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/share/native/libnet/net_util.h jdk24u-jdk-24-29/src/java.base/share/native/libnet/net_util.h
--- jdk24u-jdk-24-29.orig/src/java.base/share/native/libnet/net_util.h	2024-12-29 15:19:43.601050400 +0100
+++ jdk24u-jdk-24-29/src/java.base/share/native/libnet/net_util.h	2024-12-29 15:20:25.076362529 +0100
@@ -142,6 +142,8 @@
 JNIEXPORT jobject JNICALL
 NET_SockaddrToInetAddress(JNIEnv *env, SOCKETADDRESS *sa, int *port);
 
+void parseExclusiveBindProperty(JNIEnv *env);
+
 JNIEXPORT jint JNICALL NET_GetPortFromSockaddr(SOCKETADDRESS *sa);
 
 JNIEXPORT jboolean JNICALL
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DefaultAsynchronousChannelProvider.java	2024-12-29 15:20:25.109126542 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DefaultSelectorProvider.java	2024-12-29 15:20:25.109394984 +0100
@@ -0,0 +1,46 @@
+/*
+ * 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;
+
+/**
+ * Creates this platform's default SelectorProvider
+ */
+
+public class DefaultSelectorProvider {
+    private static final SelectorProviderImpl INSTANCE = new DevPollSelectorProvider();
+
+    /**
+     * Prevent instantiation.
+     */
+    private DefaultSelectorProvider() { }
+
+    /**
+     * Returns the default SelectorProvider implementation.
+     */
+    public static SelectorProviderImpl get() {
+        return INSTANCE;
+    }
+}
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DevPollArrayWrapper.java	2024-12-29 15:20:25.109694733 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorImpl.java	2024-12-29 15:20:25.110052606 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/DevPollSelectorProvider.java	2024-12-29 15:20:25.110308958 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorImpl.java	2024-12-29 15:20:25.110683821 +0100
@@ -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 retrieve 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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/EventPortSelectorProvider.java	2024-12-29 15:20:25.110940058 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/SolarisAsynchronousChannelProvider.java	2024-12-29 15:20:25.111227229 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/ch/SolarisEventPort.java	2024-12-29 15:20:25.111721390 +0100
@@ -0,0 +1,273 @@
+/*
+ * 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;
+
+    // events (sys/poll.h)
+    static final int POLLIN  = 0x0001;
+    static final int POLLOUT = 0x0004;
+
+    // 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. A time-out of {@code < 0} means
+     * never time-out.
+     */
+    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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/DefaultFileSystemProvider.java	2024-12-29 15:20:25.112073283 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisAclFileAttributeView.java	2024-12-29 15:20:25.112514183 +0100
@@ -0,0 +1,386 @@
+/*
+ * 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;
+    }
+
+    /**
+     * 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
+    {
+        // 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, e -> null);
+        }
+    }
+
+    @Override
+    public void setAcl(List<AclEntry> acl) throws IOException {
+        // 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, e -> null);
+        }
+    }
+
+    @Override
+    public UserPrincipal getOwner()
+        throws IOException
+    {
+        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 {
+        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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisConstants.java.template	2024-12-29 15:20:25.112812200 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisFileStore.java	2024-12-29 15:20:25.113119081 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystem.java	2024-12-29 15:20:25.113416368 +0100
@@ -0,0 +1,121 @@
+/*
+ * 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 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 = System.getProperty("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
+    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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisFileSystemProvider.java	2024-12-29 15:20:25.113708942 +0100
@@ -0,0 +1,93 @@
+/*
+ * 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;
+
+/**
+ * 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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisNativeDispatcher.java	2024-12-29 15:20:25.113980994 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisUserDefinedFileAttributeView.java	2024-12-29 15:20:25.114250627 +0100
@@ -0,0 +1,41 @@
+/*
+ * 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;
+
+class SolarisUserDefinedFileAttributeView
+    extends UnixUserDefinedFileAttributeView
+{
+
+    SolarisUserDefinedFileAttributeView(UnixPath file, boolean followLinks) {
+        super(file, followLinks);
+    }
+
+    @Override
+    protected int maxNameLength() {
+        return 255;
+    }
+
+}
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/classes/sun/nio/fs/SolarisWatchService.java	2024-12-29 15:20:25.114863500 +0100
@@ -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, e -> null);
+        }
+
+        /**
+         * 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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c jdk24u-jdk-24-29/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libjava/ProcessHandleImpl_solaris.c	2024-12-29 15:20:25.115220599 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.c jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_db/libjvm_db.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_db/libjvm_db.c	2024-12-29 15:20:25.116182272 +0100
@@ -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 points 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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.h jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_db/libjvm_db.h
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_db/libjvm_db.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_db/libjvm_db.h	2024-12-29 15:20:25.116453296 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.c	2024-12-29 15:20:25.117042942 +0100
@@ -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 parameter 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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libjvm_dtrace/jvm_dtrace.h	2024-12-29 15:20:25.117336462 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnet/solaris_close.c jdk24u-jdk-24-29/src/java.base/solaris/native/libnet/solaris_close.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnet/solaris_close.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libnet/solaris_close.c	2024-12-29 15:20:25.117676952 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/ch/DevPollArrayWrapper.c	2024-12-29 15:20:25.118056807 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/ch/SolarisEventPort.c	2024-12-29 15:20:25.118352849 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/fs/SolarisNativeDispatcher.c	2024-12-29 15:20:25.118707919 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c
--- jdk24u-jdk-24-29.orig/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.base/solaris/native/libnio/fs/SolarisWatchService.c	2024-12-29 15:20:25.118985012 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/classes/java/lang/ProcessImpl.java jdk24u-jdk-24-29/src/java.base/unix/classes/java/lang/ProcessImpl.java
--- jdk24u-jdk-24-29.orig/src/java.base/unix/classes/java/lang/ProcessImpl.java	2024-12-29 15:19:42.811393248 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/classes/java/lang/ProcessImpl.java	2024-12-29 15:20:25.077023951 +0100
@@ -79,6 +79,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,
@@ -104,6 +107,7 @@
                     return lm;      // All options are valid for Linux
                 case AIX:
                 case MACOS:
+                case SOLARIS:
                     if (lm != LaunchMechanism.VFORK) {
                         return lm; // All but VFORK are valid
                     }
@@ -352,6 +356,44 @@
                 });
                 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) -> {
+                    lock.lock();
+                    try {
+                        this.exitcode = (exitcode == null) ? -1 : exitcode.intValue();
+                        this.hasExited = true;
+                        condition.signalAll();
+                    } finally {
+                        lock.unlock();
+                    }
+                    return null;
+                });
+                break;
+
             case AIX:
                 stdin = (fds[0] == -1) ?
                         ProcessBuilder.NullOutputStream.INSTANCE :
@@ -468,6 +510,32 @@
                 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.
+                lock.lock();
+                try {
+                    if (!hasExited)
+                        processHandle.destroyProcess(force);
+                } finally {
+                    lock.unlock();
+                }
+                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: " + OperatingSystem.current());
         }
     }
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/unix/classes/sun/net/PortConfig.java jdk24u-jdk-24-29/src/java.base/unix/classes/sun/net/PortConfig.java
--- jdk24u-jdk-24-29.orig/src/java.base/unix/classes/sun/net/PortConfig.java	2024-12-29 15:19:42.821359283 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/classes/sun/net/PortConfig.java	2024-12-29 15:20:25.077389238 +0100
@@ -48,6 +48,10 @@
                 defaultLower = 32768;
                 defaultUpper = 61000;
                 break;
+            case SOLARIS:
+                defaultLower = 32768;
+                defaultUpper = 65535;
+                break;
             case MACOS:
                 defaultLower = 49152;
                 defaultUpper = 65535;
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template jdk24u-jdk-24-29/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template
--- jdk24u-jdk-24-29.orig/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template	2024-12-29 15:19:42.816253450 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/classes/sun/nio/fs/UnixConstants.java.template	2024-12-29 15:20:25.077809589 +0100
@@ -35,6 +35,10 @@
 #include <sys/clonefile.h>
 #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 jdk24u-jdk-24-29.orig/src/java.base/unix/classes/sun/security/provider/NativePRNG.java jdk24u-jdk-24-29/src/java.base/unix/classes/sun/security/provider/NativePRNG.java
--- jdk24u-jdk-24-29.orig/src/java.base/unix/classes/sun/security/provider/NativePRNG.java	2024-12-29 15:19:42.820781612 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/classes/sun/security/provider/NativePRNG.java	2024-12-29 15:20:25.078279522 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/io_util_md.c jdk24u-jdk-24-29/src/java.base/unix/native/libjava/io_util_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/io_util_md.c	2024-12-29 15:19:42.799027886 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/io_util_md.c	2024-12-29 15:20:25.081380287 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/java_props_md.c jdk24u-jdk-24-29/src/java.base/unix/native/libjava/java_props_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/java_props_md.c	2024-12-29 15:19:42.798452654 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/java_props_md.c	2024-12-29 15:20:25.081812604 +0100
@@ -323,6 +323,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c jdk24u-jdk-24-29/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	2024-12-29 15:19:42.798670317 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.c	2024-12-29 15:20:25.078980612 +0100
@@ -44,8 +44,16 @@
 #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 __solaris__
+#include <procfs.h>
+#endif
+
 #if defined(_AIX)
   #include <sys/procfs.h>
 #endif
@@ -122,13 +130,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
 
 /* Field id for jString 'command' in java.lang.ProcessHandleImpl.Info */
 jfieldID ProcessHandleImpl_Info_commandID;
@@ -469,7 +482,7 @@
  * The following functions are for Linux
  */
 
-#if defined (__linux__)
+#if defined(__solaris__) || defined (__linux__)
 
 /*
  * Return pids of active processes, and optionally parent pids and
@@ -598,13 +611,13 @@
     return count;
 }
 
-#endif // defined (__linux__)
+#endif // defined(__solaris__) || defined (__linux__)
 
 /*
- * 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".
@@ -661,8 +674,24 @@
 
 void unix_getCmdlineAndUserInfo(JNIEnv *env, jobject jinfo, pid_t pid) {
     psinfo_t psinfo;
+    char fn[32];
+    char exePath[PATH_MAX];
     char prargs[PRARGSZ + 1];
     jstring cmdexe = NULL;
+    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
@@ -693,4 +722,4 @@
                       prargs[0] == '\0' ? NULL : prargs);
 }
 
-#endif // defined(_AIX)
+#endif // defined(__solaris__) || defined(_AIX)
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h jdk24u-jdk-24-29/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h	2024-12-29 15:19:42.800171161 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/ProcessHandleImpl_unix.h	2024-12-29 15:20:25.079311294 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/ProcessImpl_md.c jdk24u-jdk-24-29/src/java.base/unix/native/libjava/ProcessImpl_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/ProcessImpl_md.c	2024-12-29 15:19:42.801137282 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/ProcessImpl_md.c	2024-12-29 15:20:25.079869534 +0100
@@ -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*
@@ -447,7 +454,7 @@
 #endif
 
 /* vfork(2) is deprecated on Darwin */
-#ifndef __APPLE__
+#ifndef __solaris__
 static pid_t
 vforkChild(ChildStuff *c) {
     volatile pid_t resultPid;
@@ -611,7 +618,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/TimeZone_md.c jdk24u-jdk-24-29/src/java.base/unix/native/libjava/TimeZone_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/TimeZone_md.c	2024-12-29 15:19:42.797893702 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/TimeZone_md.c	2024-12-29 15:20:25.080640575 +0100
@@ -35,15 +35,20 @@
 #include <string.h>
 #include <dirent.h>
 #include <unistd.h>
+#if defined(__solaris__)
+#include <libscf.h>
+#endif
 
 #include "jvm.h"
 #include "jni_util.h"
 #include "TimeZone_md.h"
 #include "path_util.h"
 
+#if !defined(__solaris__) || defined(__sparcv9) || defined(amd64)
 #define fileopen        fopen
 #define filegets        fgets
 #define fileclose       fclose
+#endif
 
 #if defined(__linux__) || defined(_ALLBSD_SOURCE)
 static const char *ETC_TIMEZONE_FILE = "/etc/timezone";
@@ -57,7 +62,7 @@
 
 static const char popularZones[][4] = {"UTC", "GMT"};
 
-#if defined(__linux__) || defined(MACOSX)
+#if defined(__linux__) || defined(MACOSX) || defined(__solaris__)
 static char *isFileIdentical(char* buf, size_t size, char *pathname);
 
 /*
@@ -168,6 +173,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;
         }
@@ -239,6 +251,8 @@
     return possibleMatch;
 }
 
+#if defined(__linux__) || defined(MACOSX)
+
 /*
  * Performs Linux specific mapping and returns a zone ID
  * if found. Otherwise, NULL is returned.
@@ -350,6 +364,183 @@
     return tz;
 }
 
+#elif defined(__solaris__)
+
+/*
+ * 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;
+                while (*p == ' ' || *p == '\t') 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 const char *ETC_ENVIRONMENT_FILE = "/etc/environment";
 
@@ -516,6 +707,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);
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/UnixFileSystem_md.c jdk24u-jdk-24-29/src/java.base/unix/native/libjava/UnixFileSystem_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjava/UnixFileSystem_md.c	2024-12-29 15:19:42.800013063 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjava/UnixFileSystem_md.c	2024-12-29 15:20:25.081032028 +0100
@@ -57,6 +57,11 @@
   #endif
   #define statvfs statvfs64
 #endif
+
+#if defined(__solaris__) && !defined(NAME_MAX)
+  #define NAME_MAX MAXNAMLEN
+#endif
+
 /* -- Field IDs -- */
 
 static struct {
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjsig/jsig.c jdk24u-jdk-24-29/src/java.base/unix/native/libjsig/jsig.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libjsig/jsig.c	2024-12-29 15:19:42.802260109 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libjsig/jsig.c	2024-12-29 15:20:25.082548929 +0100
@@ -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>
@@ -44,9 +54,16 @@
 #include <string.h>
 #include <stdbool.h>
 
+#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. */
 
@@ -71,6 +88,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
@@ -130,7 +161,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) {
@@ -139,6 +181,7 @@
   bool sigblocked;
 
   signal_lock();
+  allocate_sact();
 
   sigused = sigismember(&jvmsigs, sig);
   if (jvm_signal_installed && sigused) {
@@ -150,6 +193,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) {
@@ -227,6 +277,7 @@
 
   signal_lock();
 
+  allocate_sact();
   sigused = sigismember(&jvmsigs, sig);
   if (jvm_signal_installed && sigused) {
     /* jvm has installed its signal handler for this signal. */
@@ -293,6 +344,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/Inet4AddressImpl.c jdk24u-jdk-24-29/src/java.base/unix/native/libnet/Inet4AddressImpl.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/Inet4AddressImpl.c	2024-12-29 15:19:42.807755457 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/Inet4AddressImpl.c	2024-12-29 15:20:25.082989651 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/Inet6AddressImpl.c jdk24u-jdk-24-29/src/java.base/unix/native/libnet/Inet6AddressImpl.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/Inet6AddressImpl.c	2024-12-29 15:19:42.807567093 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/Inet6AddressImpl.c	2024-12-29 15:20:25.083450543 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/net_util_md.c jdk24u-jdk-24-29/src/java.base/unix/native/libnet/net_util_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/net_util_md.c	2024-12-29 15:19:42.807165082 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/net_util_md.c	2024-12-29 15:20:25.085524331 +0100
@@ -36,6 +36,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
@@ -50,12 +58,114 @@
 #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
+
 void
 NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                    const char *defaultDetail) {
     JNU_ThrowByNameWithMessageAndLastError(env, name, defaultDetail);
 }
 
+#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_ThrowNew(JNIEnv *env, int errorNumber, char *msg) {
     char fullMsg[512];
@@ -133,6 +243,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.
@@ -197,6 +351,26 @@
     }
 }
 
+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;
@@ -438,6 +612,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) {
@@ -552,10 +785,20 @@
  *
  * 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;
+    int arg, alen;
+#endif
     int rv;
 
 #ifdef __linux__
@@ -572,8 +815,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/net_util_md.h jdk24u-jdk-24-29/src/java.base/unix/native/libnet/net_util_md.h
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/net_util_md.h	2024-12-29 15:19:42.806649976 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/net_util_md.h	2024-12-29 15:20:25.085892248 +0100
@@ -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
@@ -80,4 +82,8 @@
 void NET_ThrowByNameWithLastError(JNIEnv *env, const char *name,
                                   const char *defaultDetail);
 
+#ifdef __solaris__
+int net_getParam(char *driver, char *param);
+#endif
+
 #endif /* NET_UTILS_MD_H */
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/NetworkInterface.c jdk24u-jdk-24-29/src/java.base/unix/native/libnet/NetworkInterface.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/NetworkInterface.c	2024-12-29 15:19:42.806960856 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/NetworkInterface.c	2024-12-29 15:20:25.084326876 +0100
@@ -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
@@ -135,6 +146,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 *****************************/
 
 /*
@@ -1658,6 +1674,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/portconfig.c jdk24u-jdk-24-29/src/java.base/unix/native/libnet/portconfig.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/portconfig.c	2024-12-29 15:19:42.806342822 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/portconfig.c	2024-12-29 15:20:25.086236752 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/SdpSupport.c jdk24u-jdk-24-29/src/java.base/unix/native/libnet/SdpSupport.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnet/SdpSupport.c	2024-12-29 15:19:42.806496029 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnet/SdpSupport.c	2024-12-29 15:20:25.084699140 +0100
@@ -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
@@ -44,7 +48,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c	2024-12-29 15:19:42.804792171 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/DatagramChannelImpl.c	2024-12-29 15:20:25.086663187 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/NativeThread.c jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/NativeThread.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/NativeThread.c	2024-12-29 15:19:42.803462858 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/NativeThread.c	2024-12-29 15:20:25.087041088 +0100
@@ -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
@@ -73,14 +76,22 @@
 JNIEXPORT jlong JNICALL
 Java_sun_nio_ch_NativeThread_current0(JNIEnv *env, jclass cl)
 {
+#ifdef __solaris__
+    return (jlong)thr_self();
+#else
     return (jlong)pthread_self();
+#endif
 }
 
 JNIEXPORT void JNICALL
 Java_sun_nio_ch_NativeThread_signal0(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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/Net.c jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/Net.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/Net.c	2024-12-29 15:19:42.803820428 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/Net.c	2024-12-29 15:20:25.087600281 +0100
@@ -25,6 +25,7 @@
 
 #include <poll.h>
 #include <sys/ioctl.h>
+#include <sys/filio.h>
 #include <sys/types.h>
 #include <sys/socket.h>
 #include <string.h>
@@ -220,7 +221,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
@@ -232,7 +233,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/nio_util.h jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/nio_util.h
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/ch/nio_util.h	2024-12-29 15:19:42.803622089 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnio/ch/nio_util.h	2024-12-29 15:20:25.087923220 +0100
@@ -35,6 +35,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 jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c jdk24u-jdk-24-29/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c
--- jdk24u-jdk-24-29.orig/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c	2024-12-29 15:19:42.805599838 +0100
+++ jdk24u-jdk-24-29/src/java.base/unix/native/libnio/fs/UnixNativeDispatcher.c	2024-12-29 15:20:25.088482155 +0100
@@ -46,10 +46,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>
 #include <sys/sysmacros.h> // makedev macros
@@ -339,7 +346,8 @@
 
     /* system calls that might not be available at run time */
 
-#if defined(_ALLBSD_SOURCE)
+#if defined(__solaris__) || defined(_ALLBSD_SOURCE)
+    /* Solaris 64-bit does not have openat64/fstatat64 */
     my_openat_func = (openat_func*) openat;
     my_fstatat_func = (fstatat_func*) fstatat;
 #else
diff -Nru jdk24u-jdk-24-29.orig/src/java.base/windows/native/libnet/net_util_md.c jdk24u-jdk-24-29/src/java.base/windows/native/libnet/net_util_md.c
--- jdk24u-jdk-24-29.orig/src/java.base/windows/native/libnet/net_util_md.c	2024-12-29 15:19:42.725450635 +0100
+++ jdk24u-jdk-24-29/src/java.base/windows/native/libnet/net_util_md.c	2024-12-29 15:20:25.088970363 +0100
@@ -125,6 +125,8 @@
     }
     return TRUE;
 }
+ 
+void parseExclusiveBindProperty(JNIEnv *env) {}
 
 /*
  * Since winsock doesn't have the equivalent of strerror(errno)
diff -Nru jdk24u-jdk-24-29.orig/src/java.desktop/share/classes/sun/awt/FontConfiguration.java jdk24u-jdk-24-29/src/java.desktop/share/classes/sun/awt/FontConfiguration.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/share/classes/sun/awt/FontConfiguration.java	2024-12-29 15:19:42.498908998 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/share/classes/sun/awt/FontConfiguration.java	2024-12-29 15:20:25.089738571 +0100
@@ -1401,6 +1401,22 @@
                 }
             }
         }
+        if (OSInfo.getOSType() == OSInfo.OSType.SOLARIS) {
+            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 jdk24u-jdk-24-29.orig/src/java.desktop/share/classes/sun/awt/OSInfo.java jdk24u-jdk-24-29/src/java.desktop/share/classes/sun/awt/OSInfo.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/share/classes/sun/awt/OSInfo.java	2024-12-29 15:19:42.497824796 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/share/classes/sun/awt/OSInfo.java	2024-12-29 15:20:25.090179979 +0100
@@ -39,6 +39,7 @@
     public static enum OSType {
         WINDOWS,
         LINUX,
+        SOLARIS,
         MACOSX,
         AIX,
         UNKNOWN
@@ -95,6 +96,7 @@
             // Map OperatingSystem enum values to OSType enum values.
             case WINDOWS -> WINDOWS;
             case LINUX -> LINUX;
+            case SOLARIS -> SOLARIS;
             case MACOS -> MACOSX;
             case AIX -> AIX;
             default -> UNKNOWN;
diff -Nru jdk24u-jdk-24-29.orig/src/java.desktop/share/classes/sun/font/FontUtilities.java jdk24u-jdk-24-29/src/java.desktop/share/classes/sun/font/FontUtilities.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/share/classes/sun/font/FontUtilities.java	2024-12-29 15:19:42.571921436 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/share/classes/sun/font/FontUtilities.java	2024-12-29 15:20:25.090698071 +0100
@@ -39,6 +39,8 @@
  */
 public final class FontUtilities {
 
+    public static boolean isSolaris;
+
     public static boolean isLinux;
 
     public static boolean isMacOSX;
@@ -60,6 +62,8 @@
     @SuppressWarnings("deprecation") // PlatformLogger.setLevel is deprecated.
     private static void initStatic() {
 
+        isSolaris = OSInfo.getOSType() == OSInfo.OSType.SOLARIS;
+
         isLinux = OSInfo.getOSType() == OSInfo.OSType.LINUX;
 
         isMacOSX = OSInfo.getOSType() == OSInfo.OSType.MACOSX;
diff -Nru jdk24u-jdk-24-29.orig/src/java.desktop/share/native/libjsound/SoundDefs.h jdk24u-jdk-24-29/src/java.desktop/share/native/libjsound/SoundDefs.h
--- jdk24u-jdk-24-29.orig/src/java.desktop/share/native/libjsound/SoundDefs.h	2024-12-29 15:19:41.638215839 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/share/native/libjsound/SoundDefs.h	2024-12-29 15:20:25.091180642 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643.java	2024-12-29 15:20:25.119440146 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643P1.java	2024-12-29 15:20:25.119686371 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643P2.java	2024-12-29 15:20:25.119930934 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/classes/sun/font/X11CNS11643P3.java	2024-12-29 15:20:25.120165403 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/data/fontconfig/fontconfig.properties jdk24u-jdk-24-29/src/java.desktop/solaris/data/fontconfig/fontconfig.properties
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/data/fontconfig/fontconfig.properties	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/data/fontconfig/fontconfig.properties	2024-12-29 15:20:25.106221085 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_PCM.c	2024-12-29 15:20:25.120732370 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Ports.c	2024-12-29 15:20:25.121215791 +0100
@@ -0,0 +1,579 @@
+/*
+ * 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
+
+// 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++;
+                    }
+                    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]);
+                }
+                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++;
+                    }
+                    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]);
+                }
+            }
+        }
+        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);
+            selectable = info->audioInfo.play.mod_ports & targetPorts[info->ports[portIndex]];
+        } else {
+            type = PORT_CONTROL_TYPE_RECORD;
+            selectable = info->audioInfo.record.mod_ports & sourcePorts[info->ports[portIndex]];
+        }
+        // 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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.c	2024-12-29 15:20:25.121510507 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h
--- jdk24u-jdk-24-29.orig/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/solaris/native/libjsound/PLATFORM_API_SolarisOS_Utils.h	2024-12-29 15:20:25.121752513 +0100
@@ -0,0 +1,85 @@
+/*
+ * 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>
+#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
+
+/* 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 jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/awt/X11FontManager.java jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/awt/X11FontManager.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	2024-12-29 15:19:42.646205165 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/awt/X11FontManager.java	2024-12-29 15:20:25.091714810 +0100
@@ -686,7 +686,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 jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java	2024-12-29 15:19:42.640121915 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/font/MFontConfiguration.java	2024-12-29 15:20:25.092292020 +0100
@@ -68,7 +68,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",
+                       new String[] {"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", new String[] {"chinese-big5", "chinese-hkscs"});
+        reorderMap.put("UTF-8.zh.CN",
+                       new String[] {"chinese-gb18030-0", "chinese-gb18030-1"});
+        reorderMap.put("UTF-8.zh",
+                       new String[] {"chinese-big5", "chinese-hkscs", "chinese-gb18030-0,chinese-gb18030-1"});
+        reorderMap.put("Big5", "chinese-big5");
+        reorderMap.put("Big5-HKSCS", new String[] {"chinese-big5", "chinese-hkscs"});
+        reorderMap.put("GB2312", new String[] {"chinese-gbk", "chinese-gb2312"});
+        reorderMap.put("x-EUC-TW",
+            new String[] {"chinese-cns11643-1", "chinese-cns11643-2", "chinese-cns11643-3"});
+        reorderMap.put("GBK", "chinese-gbk");
+        reorderMap.put("GB18030",new String[] {"chinese-gb18030-0", "chinese-gb18030-1"});
+
+        reorderMap.put("TIS-620", "thai");
+        reorderMap.put("x-PCK",
+                       new String[] {"japanese-x0201", "japanese-x0208", "japanese-x0212"});
+        reorderMap.put("x-eucJP-Open",
+                       new String[] {"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");
@@ -78,7 +130,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");
+        }
     }
 
     /**
@@ -87,7 +144,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 jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java	2024-12-29 15:19:42.677705067 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/print/PrintServiceLookupProvider.java	2024-12-29 15:20:25.092927803 +0100
@@ -139,6 +139,10 @@
         return OSInfo.getOSType() == OSInfo.OSType.MACOSX;
     }
 
+    static boolean isSysV() {
+        return OSInfo.getOSType() == OSInfo.OSType.SOLARIS;
+    }
+
     static boolean isLinux() {
         return OSInfo.getOSType() == OSInfo.OSType.LINUX;
     }
@@ -281,7 +285,7 @@
                 }
             }
         } else {
-            if (isMac()) {
+            if (isMac() || isSysV()) {
                 printers = getAllPrinterNamesSysV();
             } else if (isAIX()) {
                 printers = getAllPrinterNamesAIX();
@@ -465,7 +469,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);
@@ -620,7 +624,7 @@
                 psuri = printerInfo[1];
             }
         } else {
-            if (isMac()) {
+            if (isMac() || isSysV()) {
                 defaultPrinter = getDefaultPrinterNameSysV();
             } else if (isAIX()) {
                 defaultPrinter = getDefaultPrinterNameAIX();
@@ -839,7 +843,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 jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java	2024-12-29 15:19:42.676481495 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/print/UnixPrintJob.java	2024-12-29 15:20:25.093408737 +0100
@@ -853,25 +853,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.isSysV()) {
+            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 jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/print/UnixPrintService.java jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/print/UnixPrintService.java
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/classes/sun/print/UnixPrintService.java	2024-12-29 15:19:42.677405072 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/classes/sun/print/UnixPrintService.java	2024-12-29 15:20:25.094074563 +0100
@@ -218,6 +218,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) {
@@ -295,7 +320,9 @@
     }
 
     private PrinterIsAcceptingJobs getPrinterIsAcceptingJobs() {
-        if (PrintServiceLookupProvider.isBSD()) {
+        if (PrintServiceLookupProvider.isSysV()) {
+            return getPrinterIsAcceptingJobsSysV();
+        } else if (PrintServiceLookupProvider.isBSD()) {
             return getPrinterIsAcceptingJobsBSD();
         } else if (PrintServiceLookupProvider.isAIX()) {
             return getPrinterIsAcceptingJobsAIX();
@@ -322,6 +349,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) {
@@ -378,7 +413,9 @@
     }
 
     private QueuedJobCount getQueuedJobCount() {
-        if (PrintServiceLookupProvider.isBSD()) {
+        if (PrintServiceLookupProvider.isSysV()) {
+            return getQueuedJobCountSysV();
+        } else if (PrintServiceLookupProvider.isBSD()) {
             return getQueuedJobCountBSD();
         } else if (PrintServiceLookupProvider.isAIX()) {
             return getQueuedJobCountAIX();
@@ -387,6 +424,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());
@@ -420,7 +464,9 @@
     }
 
     private PrintServiceAttributeSet getDynamicAttributes() {
-        if (PrintServiceLookupProvider.isAIX()) {
+        if (PrintServiceLookupProvider.isSysV()) {
+            return getSysVServiceAttributes();
+        } else if (PrintServiceLookupProvider.isAIX()) {
             return getAIXServiceAttributes();
         } else {
             return getBSDServiceAttributes();
diff -Nru jdk24u-jdk-24-29.orig/src/java.desktop/unix/native/common/awt/fontpath.c jdk24u-jdk-24-29/src/java.desktop/unix/native/common/awt/fontpath.c
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/native/common/awt/fontpath.c	2024-12-29 15:19:42.588808284 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/native/common/awt/fontpath.c	2024-12-29 15:20:25.094669487 +0100
@@ -57,7 +57,16 @@
 
 #define MAXFDIRS 512    /* Max number of directories that contain fonts */
 
-#if defined( __linux__)
+#if defined(__solaris__)
+/* These are well known Solaris 11 or illumos X11 directories.
+ */
+static char *fullSolarisFontPath[] = {
+    "/usr/share/fonts/TrueType",
+    "/usr/share/fonts/X11/Type1",
+    NULL, /* terminates the list */
+};
+
+#elif defined( __linux__)
 /* All the known interesting locations we have discovered on
  * various flavors of Linux
  */
@@ -321,6 +330,8 @@
 
 #if defined(__linux__)
     knowndirs = fullLinuxFontPath;
+#elif defined(__solaris__)
+    knowndirs = fullSolarisFontPath;
 #elif defined(_AIX)
     knowndirs = fullAixFontPath;
 #endif
diff -Nru jdk24u-jdk-24-29.orig/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c jdk24u-jdk-24-29/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c	2024-12-29 15:19:42.625116865 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/native/libawt_xawt/awt/awt_GraphicsEnv.c	2024-12-29 15:20:25.095274814 +0100
@@ -401,7 +401,12 @@
             xrenderLibHandle = dlopen("libXrender.so", RTLD_LAZY | RTLD_GLOBAL);
         }
 
-#if defined(_AIX)
+#if defined(__solaris__)
+        if (xrenderLibHandle == NULL) {
+            xrenderLibHandle = dlopen("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 jdk24u-jdk-24-29.orig/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c jdk24u-jdk-24-29/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c
--- jdk24u-jdk-24-29.orig/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c	2024-12-29 15:19:42.620754450 +0100
+++ jdk24u-jdk-24-29/src/java.desktop/unix/native/libawt_xawt/java2d/x11/XRBackendNative.c	2024-12-29 15:20:25.096307209 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java jdk24u-jdk-24-29/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java
--- jdk24u-jdk-24-29.orig/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	2024-12-29 15:19:46.169330391 +0100
+++ jdk24u-jdk-24-29/src/java.security.jgss/share/classes/sun/security/jgss/wrapper/SunNativeProvider.java	2024-12-29 15:20:25.096818744 +0100
@@ -84,6 +84,9 @@
         String defaultLib = System.getProperty("sun.security.jgss.lib");
         if (defaultLib == null || defaultLib.trim().equals("")) {
             gssLibs = switch (OperatingSystem.current()) {
+                case SOLARIS -> new String[]{
+                        "libgss.so",
+                };
                 case LINUX -> new String[]{
                         "libgssapi.so",
                         "libgssapi_krb5.so",
diff -Nru jdk24u-jdk-24-29.orig/src/java.security.jgss/share/classes/sun/security/krb5/Config.java jdk24u-jdk-24-29/src/java.security.jgss/share/classes/sun/security/krb5/Config.java
--- jdk24u-jdk-24-29.orig/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	2024-12-29 15:19:46.180332170 +0100
+++ jdk24u-jdk-24-29/src/java.security.jgss/share/classes/sun/security/krb5/Config.java	2024-12-29 15:20:25.097408576 +0100
@@ -905,6 +905,8 @@
             if (name == null) {
                 name = "c:\\winnt\\krb5.ini";
             }
+        } else if (OperatingSystem.isSolaris()) {
+            name =  "/etc/krb5/krb5.conf";
         } else if (OperatingSystem.isMacOS()) {
             name = findMacosConfigFile();
         } else {
diff -Nru jdk24u-jdk-24-29.orig/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java jdk24u-jdk-24-29/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java
--- jdk24u-jdk-24-29.orig/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java	2024-12-29 15:19:46.190234042 +0100
+++ jdk24u-jdk-24-29/src/java.security.jgss/share/classes/sun/security/krb5/internal/rcache/DflCache.java	2024-12-29 15:20:25.097918030 +0100
@@ -106,7 +106,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 jdk24u-jdk-24-29.orig/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java jdk24u-jdk-24-29/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java
--- jdk24u-jdk-24-29.orig/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java	2024-12-29 15:19:45.838526413 +0100
+++ jdk24u-jdk-24-29/src/java.smartcardio/unix/classes/sun/security/smartcardio/PlatformPCSC.java	2024-12-29 15:20:25.098432578 +0100
@@ -86,8 +86,12 @@
         if (k != -1) {
             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 jdk24u-jdk-24-29.orig/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java jdk24u-jdk-24-29/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java
--- jdk24u-jdk-24-29.orig/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java	2024-12-29 15:19:45.512876468 +0100
+++ jdk24u-jdk-24-29/src/java.xml/share/classes/com/sun/org/apache/xalan/internal/xsltc/runtime/output/WriterOutputBuffer.java	2024-12-29 15:20:25.098958971 +0100
@@ -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 = System.getProperty("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 jdk24u-jdk-24-29.orig/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java jdk24u-jdk-24-29/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java
--- jdk24u-jdk-24-29.orig/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.attach/solaris/classes/sun/tools/attach/AttachProviderImpl.java	2024-12-29 15:20:25.122224133 +0100
@@ -0,0 +1,76 @@
+/*
+ * 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
+    {
+        // 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();
+            return new VirtualMachineImpl(this, vmd.id());
+        } else {
+            return attachVirtualMachine(vmd.id());
+        }
+    }
+
+}
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java jdk24u-jdk-24-29/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java
--- jdk24u-jdk-24-29.orig/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.attach/solaris/classes/sun/tools/attach/VirtualMachineImpl.java	2024-12-29 15:20:25.122559787 +0100
@@ -0,0 +1,273 @@
+/*
+ * 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.
+ */
+@SuppressWarnings("restricted")
+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 = readMessage(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 jdk24u-jdk-24-29.orig/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c jdk24u-jdk-24-29/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c
--- jdk24u-jdk-24-29.orig/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.attach/solaris/native/libattach/VirtualMachineImpl.c	2024-12-29 15:20:25.123043618 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java jdk24u-jdk-24-29/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java
--- jdk24u-jdk-24-29.orig/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java	2024-12-29 15:19:41.090597839 +0100
+++ jdk24u-jdk-24-29/src/jdk.charsets/share/classes/sun/nio/cs/ext/JISAutoDetect.java	2024-12-29 15:20:25.099518367 +0100
@@ -95,7 +95,7 @@
     private static class Decoder extends CharsetDecoder {
 
         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) {
@@ -223,11 +223,24 @@
          * Returned Shift_JIS Charset name is OS dependent
          */
         private static String getSJISName() {
-            if (OperatingSystem.isWindows())
+            if (OperatingSystem.isSolaris())
+                return("PCK");
+            else if (OperatingSystem.isWindows())
                 return("windows-31J");
             else
                 return("Shift_JIS");
         }
 
+        /**
+         * Returned EUC-JP Charset name is OS dependent
+         */
+
+        private static String getEUCJPName() {
+            if (OperatingSystem.isSolaris())
+                return("x-eucjp-open");
+            else
+                return("EUC_JP");
+        }
+
     }
 }
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java jdk24u-jdk-24-29/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java
--- jdk24u-jdk-24-29.orig/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java	2024-12-29 15:19:41.101019690 +0100
+++ jdk24u-jdk-24-29/src/jdk.crypto.cryptoki/share/classes/sun/security/pkcs11/Config.java	2024-12-29 15:20:25.100100492 +0100
@@ -725,10 +725,10 @@
         lib = expand(lib);
         int i = lib.indexOf("/$ISA/");
         if (i != -1) {
-            // replace "/$ISA/" with "/"
+            // replace "/$ISA/" with "/amd64/" on Solaris AMD64.
             String prefix = lib.substring(0, i);
             String suffix = lib.substring(i + 5);
-            lib = prefix + suffix;
+            lib = prefix + "/amd64" + suffix;
         }
         if (DEBUG) {
             System.out.println(keyword + ": " + lib);
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg jdk24u-jdk-24-29/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg
--- jdk24u-jdk-24-29.orig/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.crypto.cryptoki/solaris/conf/security/sunpkcs11-solaris.cfg	2024-12-29 15:20:25.123411243 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java
--- jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/HotSpotSolarisVtblAccess.java	2024-12-29 15:20:25.123693838 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java
--- jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/solaris_amd64/SolarisAMD64JavaThreadPDAccess.java	2024-12-29 15:20:25.124062932 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java
--- jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java	2024-12-29 15:19:45.001712118 +0100
+++ jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/runtime/Threads.java	2024-12-29 15:20:25.100710945 +0100
@@ -28,6 +28,7 @@
 
 import sun.jvm.hotspot.debugger.*;
 import sun.jvm.hotspot.types.*;
+import sun.jvm.hotspot.runtime.solaris_amd64.SolarisAMD64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.win32_amd64.Win32AMD64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.win32_aarch64.Win32AARCH64JavaThreadPDAccess;
 import sun.jvm.hotspot.runtime.linux_x86.LinuxX86JavaThreadPDAccess;
@@ -96,7 +97,9 @@
 
         access = null;
         // FIXME: find the platform specific PD class by reflection?
-        if (os.equals("win32")) {
+        if (os.equals("solaris")) {
+            access = new SolarisAMD64JavaThreadPDAccess();
+        } else if (os.equals("win32")) {
             if (cpu.equals("amd64")) {
                 access =  new Win32AMD64JavaThreadPDAccess();
             } else if (cpu.equals("aarch64")) {
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java
--- jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java	2024-12-29 15:19:44.942933939 +0100
+++ jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/classes/sun/jvm/hotspot/utilities/PlatformInfo.java	2024-12-29 15:20:25.101150548 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c
--- jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c	2024-12-29 15:19:45.051639500 +0100
+++ jdk24u-jdk-24-29/src/jdk.hotspot.agent/share/native/libsaproc/ps_core_common.c	2024-12-29 15:20:25.101599352 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/test/libproc/libproctest.sh jdk24u-jdk-24-29/src/jdk.hotspot.agent/test/libproc/libproctest.sh
--- jdk24u-jdk-24-29.orig/src/jdk.hotspot.agent/test/libproc/libproctest.sh	2024-12-29 15:19:45.055781742 +0100
+++ jdk24u-jdk-24-29/src/jdk.hotspot.agent/test/libproc/libproctest.sh	2024-12-29 15:20:25.101991056 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c jdk24u-jdk-24-29/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c
--- jdk24u-jdk-24-29.orig/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c	2024-12-29 15:19:43.782615561 +0100
+++ jdk24u-jdk-24-29/src/jdk.jdwp.agent/unix/native/libdt_socket/socket_md.c	2024-12-29 15:20:25.102510036 +0100
@@ -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"
@@ -271,6 +275,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;
@@ -296,6 +329,8 @@
     return pthread_getspecific((pthread_key_t)index);
 }
 
+#endif
+
 long
 dbgsysCurrentTimeMillis() {
     struct timeval t;
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c jdk24u-jdk-24-29/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c
--- jdk24u-jdk-24-29.orig/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c	1970-01-01 01:00:00.000000000 +0100
+++ jdk24u-jdk-24-29/src/jdk.management/solaris/native/libmanagement_ext/UnixOperatingSystem.c	2024-12-29 15:20:25.124493431 +0100
@@ -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 jdk24u-jdk-24-29.orig/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c jdk24u-jdk-24-29/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c
--- jdk24u-jdk-24-29.orig/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c	2024-12-29 15:19:43.636481591 +0100
+++ jdk24u-jdk-24-29/src/jdk.management/unix/native/libmanagement_ext/OperatingSystemImpl.c	2024-12-29 15:20:25.103111617 +0100
@@ -77,7 +77,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;
     jlong total = 0, avail = 0;
 
@@ -126,7 +182,37 @@
 Java_com_sun_management_internal_OperatingSystemImpl_getCommittedVirtualMemorySize0
   (JNIEnv *env, jobject mbean)
 {
-#if defined(__APPLE__)
+#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(__APPLE__)
     struct task_basic_info t_info;
     mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
 
@@ -182,7 +268,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 jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java jdk24u-jdk-24-29/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java
--- jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java	2024-12-29 15:19:41.186801079 +0100
+++ jdk24u-jdk-24-29/src/jdk.sctp/unix/classes/sun/nio/ch/sctp/SctpNet.java	2024-12-29 15:20:25.103579921 +0100
@@ -42,6 +42,12 @@
     /* -- Miscellaneous SCTP utilities -- */
 
     private static boolean IPv4MappedAddresses() {
+        if (true) {
+            /* FIXME - nonportable hack */
+            /* Solaris supports IPv4Mapped Addresses with bindx */
+            return true;
+        } /* else {  //other OS/implementations  */
+
         /* lksctp/linux requires Ipv4 addresses */
         return false;
     }
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/native/libsctp/Sctp.h jdk24u-jdk-24-29/src/jdk.sctp/unix/native/libsctp/Sctp.h
--- jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/native/libsctp/Sctp.h	2024-12-29 15:19:41.184657372 +0100
+++ jdk24u-jdk-24-29/src/jdk.sctp/unix/native/libsctp/Sctp.h	2024-12-29 15:20:25.104069218 +0100
@@ -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 dependency 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 jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c jdk24u-jdk-24-29/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c
--- jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c	2024-12-29 15:19:41.184494893 +0100
+++ jdk24u-jdk-24-29/src/jdk.sctp/unix/native/libsctp/SctpChannelImpl.c	2024-12-29 15:20:25.104481587 +0100
@@ -331,11 +331,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 jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/native/libsctp/SctpNet.c jdk24u-jdk-24-29/src/jdk.sctp/unix/native/libsctp/SctpNet.c
--- jdk24u-jdk-24-29.orig/src/jdk.sctp/unix/native/libsctp/SctpNet.c	2024-12-29 15:19:41.184839031 +0100
+++ jdk24u-jdk-24-29/src/jdk.sctp/unix/native/libsctp/SctpNet.c	2024-12-29 15:20:25.104949120 +0100
@@ -371,7 +371,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
         sctpHandleSocketError(env, errno);
         return NULL;
     }
@@ -416,7 +420,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
         sctpHandleSocketError(env, errno);
         return NULL;
     }
diff -Nru jdk24u-jdk-24-29.orig/src/jdk.security.auth/unix/native/libjaas/Unix.c jdk24u-jdk-24-29/src/jdk.security.auth/unix/native/libjaas/Unix.c
--- jdk24u-jdk-24-29.orig/src/jdk.security.auth/unix/native/libjaas/Unix.c	2024-12-29 15:19:45.200116844 +0100
+++ jdk24u-jdk-24-29/src/jdk.security.auth/unix/native/libjaas/Unix.c	2024-12-29 15:20:25.105375094 +0100
@@ -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>
 
 /*
