#!/bin/sh # $FreeBSD: stable/11/tools/build/check-links.sh 294357 2016-01-19 22:42:16Z bdrewery $ proc libkey { setglobal libkey = ""lib_symbols_$1"" setglobal patterns = '[.+,/-]' setglobal replacement = '_' while : { match " $(libkey) " { with *${patterns}* setglobal libkey = ""$(libkey%%${patterns}*)$(replacement)$(libkey#*${patterns})"" with * break } } return 0 } proc usage { cat << """ usage: $0 [-Uv] [-L LD_LIBRARY_PATH] file -L: Specify an alternative LD_LIBRARY_PATH for the library resolution. -U: Skip looking for unresolved symbols. -v: Show which library each symbol is resolved to. """ exit 0 } setglobal ret = '0' setglobal CHECK_UNRESOLVED = '1' setglobal VERBOSE_RESOLVED = '0' while getopts "L:Uv" flag { match $(flag) { with L setglobal LIB_PATH = $(OPTARG) with U setglobal CHECK_UNRESOLVED = '0' with v setglobal VERBOSE_RESOLVED = '1' with * usage } } shift $shExpr('OPTIND-1') if ! test -f $1 { echo "No such file or directory: $1" > !2 exit 1 } setglobal mime = $[file -L --mime-type $1] setglobal isbin = '0' match $mime { with *application/x-executable setglobal isbin = '1' with *application/x-sharedlib with * echo "Not an elf file" > !2 ; exit 1 } # Gather all symbols from the target setglobal unresolved_symbols = $[nm -u -D --format=posix $1 | awk '$2 == "U" {print $1}' | tr '\n' ' ] test $(isbin) -eq 1 && setglobal bss_symbols = $[nm -D --format=posix $1 | awk '$2 == "B" && $4 != "" {print $1}' | tr '\n' ' ] if test -n $(LIB_PATH) { for libc in [/lib/libc.so.*] { setglobal LDD_ENV = ""LD_PRELOAD=$(libc)"" } setglobal LDD_ENV = ""$(LDD_ENV) LD_LIBRARY_PATH=$(LIB_PATH)"" } setglobal ldd_libs = $[env $(LDD_ENV) ldd $[realpath $1] | awk '{print $1 ":" $3}] # Check for useful libs setglobal list_libs = '' setglobal resolved_symbols = '' for lib in [$[readelf -d $1 | awk '$2 ~ /\(?NEEDED\)?/ { sub(/\[/,"",$NF); sub(/\]/,"",$NF); print $NF }]] { echo -n "checking if $lib is needed: " if test -n $(lib##/*) { for libpair in [$(ldd_libs)] { match $(libpair) { with ${lib}:* setglobal libpath = $(libpair#*:) && break } } } else { setglobal libpath = $(lib) } setglobal list_libs = ""$list_libs $lib"" setglobal foundone = '' setglobal lib_symbols = $[nm -D --defined-only --format=posix $(libpath) | awk '$2 ~ /C|R|D|T|W|B|V/ {print $1}' | tr '\n' ' ] if test $(CHECK_UNRESOLVED) -eq 1 { # Save the global symbols for this lib libkey $(lib) setvar $(libkey) $(lib_symbols) } for fct in [$(lib_symbols)] { match " $(unresolved_symbols) $(bss_symbols) " { with *\ ${fct}\ * setglobal foundone = $(fct) && break } } if test -n $(foundone) { echo "yes... $(foundone)" } else { echo "no" setglobal ret = '1' } } if test $(CHECK_UNRESOLVED) -eq 1 { # Add in crt1 symbols setglobal list_libs = ""$(list_libs) crt1.o"" setglobal lib_symbols = $[nm --defined-only --format=posix "/usr/lib/crt1.o" | awk '$2 ~ /C|R|D|T|W|B|V/ {print $1}' | tr '\n' ' ] # Save the global symbols for this lib libkey "crt1.o" setvar $(libkey) $(lib_symbols) # Now search libs for all symbols and report missing ones. for sym in [$(unresolved_symbols)] { setglobal found = '0' for lib in [$(list_libs)] { libkey $(lib) eval "lib_symbols=\"\${$(libkey)}\"" # lib_symbols now contains symbols for the lib. match " $(lib_symbols) " { with *\ ${sym}\ * test $(VERBOSE_RESOLVED) -eq 1 && echo "Resolved symbol $(sym) from $(lib)" setglobal found = '1' break } } if test $found -eq 0 { echo "Unresolved symbol $sym" setglobal ret = '1' } } } exit ${ret}