diff --git a/Makefile b/Makefile --- a/Makefile +++ b/Makefile @@ -155,6 +155,7 @@ TGTS= all all-man buildenv buildenvvars buildetc buildkernel buildworld \ check check-old check-old-dirs check-old-files check-old-libs \ + check-symbols \ checkdpadd checkworld clean cleandepend cleandir cleankernel \ cleanworld cleanuniverse \ delete-old delete-old-dirs delete-old-files delete-old-libs \ diff --git a/share/mk/Makefile b/share/mk/Makefile --- a/share/mk/Makefile +++ b/share/mk/Makefile @@ -70,6 +70,7 @@ meta.sys.mk \ ${SRCTOP}/contrib/bmake/mk/posix.mk \ stage-install.sh \ + symref.awk \ sys.mk \ sys.dependfile.mk \ sys.dirdeps.mk \ diff --git a/share/mk/bsd.lib.mk b/share/mk/bsd.lib.mk --- a/share/mk/bsd.lib.mk +++ b/share/mk/bsd.lib.mk @@ -375,6 +375,68 @@ ${SHLIB_NAME}.debug: ${SHLIB_NAME_FULL} ${OBJCOPY} --only-keep-debug ${SHLIB_NAME_FULL} ${.TARGET} .endif + +.if !target(${SHLIB_NAME}.symbols) +SYMREF?=symref.awk + +.if ${MAKE_VERSION} >= 20230123 +_mpath= ${.SYSPATH} +.else +# Compute the make's -m path. +_mpath= +_oarg= +.for _arg in ${.MAKEFLAGS} +.if ${_oarg} == "-m" +_mpath+= ${_arg} +.endif +_oarg= ${_arg} +.endfor +_mpath+= /usr/share/mk +.endif + +# Look up ${VERSION_GEN} in ${_mpath}. +_symref= +.for path in ${_mpath} +.if empty(_symref) +.if exists(${path}/${SYMREF}) +_symref= ${path}/${SYMREF} +.endif +.endif +.endfor +.if empty(_symref) +.error ${SYMREF} not found in the search path. +.endif + +CLEANFILES+= ${SHLIB_NAME}.symbols +${SHLIB_NAME}.symbols: ${SHLIB_NAME_FULL} ${_SYMLIST} + (echo "# ${:U@}generated by bsd.lib.mk"; \ + readelf -sW ${.ALLSRC:[1]} | awk -f ${_symref} | sort ) > ${.TARGET} +.endif + +.if defined(SYMBOLS_REF_MD) +_SYMBOLS_REF_ARCH= -${MACHINE_ARCH} +.else +_SYMBOLS_REF_ARCH= +.endif +SYMBOLS_REF?= ${.CURDIR}/symref${_SYMBOLS_REF_ARCH} +.if make(check-symbols) && ${.MAKE.LEVEL} == 1 +_CHECK_SYMBOLS_WARNING?= echo +.else +_CHECK_SYMBOLS_WARNING?= true +.endif +check-symbols: ${SHLIB_NAME}.symbols + @if [ ! -e ${SYMBOLS_REF} ]; then \ + ${_CHECK_SYMBOLS_WARNING} "WARNING: no symbol reference (${SYMBOLS_REF:T}), run 'make update-symref'" 1>&2; \ + else \ + if ! diff ${SYMBOLS_REF} ${SHLIB_NAME}.symbols; then \ + echo "ERROR: symbol set changed, correct or run 'make update-symref'" 1>&2; \ + false; \ + fi \ + fi + +update-symref: ${SHLIB_NAME}.symbols + cp ${SHLIB_NAME}.symbols ${SYMBOLS_REF} + .endif #defined(SHLIB_NAME) .if defined(INSTALL_PIC_ARCHIVE) && defined(LIB) && !empty(LIB) diff --git a/share/mk/bsd.subdir.mk b/share/mk/bsd.subdir.mk --- a/share/mk/bsd.subdir.mk +++ b/share/mk/bsd.subdir.mk @@ -41,7 +41,8 @@ SUBDIR_TARGETS+= \ all all-man analyze buildconfig buildfiles buildincludes \ - checkdpadd clean cleandepend cleandir cleanilinks \ + checkdpadd check-symbols \ + clean cleandepend cleandir cleanilinks \ cleanobj depend distribute files includes installconfig \ installdirs \ installfiles installincludes print-dir realinstall \ diff --git a/share/mk/symref.awk b/share/mk/symref.awk new file mode 100644 --- /dev/null +++ b/share/mk/symref.awk @@ -0,0 +1,61 @@ +#- +# SPDX-License-Identifier: BSD-2-Clause +# +# Copyright (c) 2024 SRI International +# +# This software was developed by SRI International, the University of +# Cambridge Computer Laboratory (Department of Computer Science and +# Technology), and Capabilities Limited under Defense Advanced Research +# Projects Agency (DARPA) Contract No. FA8750-24-C-B047 ("DEC"). +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# 1. Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# 2. Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# +# THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND +# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE +# ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE +# FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +# DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS +# OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +# HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT +# LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY +# OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF +# SUCH DAMAGE. +# + +# symref.awk - process "readelf -sW" output to compat symbol reference + +BEGIN { + symtab = "" +} + +/^Symbol table / { + symtab = $3 + gsub(/'/, "", symtab) +} + +/^ *[0-9]+:/ { + # We don't (currently) care what symbols the library depends on + if ($7 == "UND") next + + # Don't track symbols in the private namespace. Instead, depend + # on linking with --no-undefined-version to detect dropped symbols. + if ($8 ~ /@FBSDprivate_/) next + + # Only print symbols from .dynsym. Unstriped libraries may have + # internal symbol tables and we can't rely on readelf supporting + # -D (llvm-readelf doesn't). + if (symtab != ".dynsym") next + + # readelf -sW header: + # Num: Value Size Type Bind Vis Ndx Name + # 1 2 3 4 5 6 7 8 + print $8 " " tolower($4) " " tolower($5) " " tolower($6) +}