]> git.ipfire.org Git - pakfire.git/commitdiff
scripts: Add a refactored implementation to strip binaries
authorMichael Tremer <michael.tremer@ipfire.org>
Wed, 26 May 2021 09:58:45 +0000 (09:58 +0000)
committerMichael Tremer <michael.tremer@ipfire.org>
Wed, 26 May 2021 09:58:45 +0000 (09:58 +0000)
Signed-off-by: Michael Tremer <michael.tremer@ipfire.org>
Makefile.am
macros/arch.macro
macros/cflags.macro
src/libpakfire/build.c
src/scripts/strip [new file with mode: 0644]

index a4ba1408356ef10249fb131bf685f273ae904094..5c65960cf06c753594d1ecefda6ba5c3d46ecde6 100644 (file)
@@ -577,7 +577,8 @@ dist_scripts_SCRIPTS = \
        src/scripts/perl.prov \
        src/scripts/perl.req \
        src/scripts/py-compile \
-       src/scripts/remove-static-libs
+       src/scripts/remove-static-libs \
+       src/scripts/strip
 
 dist_scripts_DATA = \
        src/scripts/functions-common \
index 46f3cb2483f7e3905cb224a7559c22cb571149b5..19e09ca059e78cff973318c5c4acbd00c54fea8e 100644 (file)
@@ -16,6 +16,7 @@ includedir        = %{prefix}/include
 infodir           = %{datadir}/info
 mandir            = %{datadir}/man
 unitdir           = %{prefix}/lib/systemd/system
+debugsourcedir    = /usr/src/debug
 
 # Libs are installed in /lib64 and %{prefix}/lib64 on aarch64 and x86_64
 if "%{DISTRO_ARCH}" == "aarch64"
index 46dea107804b2a2ec56cc2ed9071d5127b1d81c7..3447ef452d01b4e05472c1e5d9edbfff5f124a08 100644 (file)
@@ -2,7 +2,7 @@
 # Export CFLAGS + CXXFLAGS
 GLOBAL_CFLAGS   = -O2 -g -pipe -Wall -Wp,-D_FORTIFY_SOURCE=2 -Werror=format-security
 GLOBAL_CFLAGS  += -fexceptions -fPIC -fstack-protector-strong --param=ssp-buffer-size=4
-GLOBAL_CFLAGS  += -grecord-gcc-switches
+GLOBAL_CFLAGS  += -grecord-gcc-switches -fdebug-prefix-map=%{DIR_SRC}=%{debugsourcedir}
 
 CFLAGS_i686     = -m32 -march=i686 -mtune=atom -fasynchronous-unwind-tables
 CFLAGS_x86_64   = -m64 -mtune=generic
index 420ec4466165c6f5b76304351961edcc30dc205c..e5009b459264eb79609f86c95c55411102f06460 100644 (file)
@@ -340,6 +340,7 @@ ERROR:
 static const char* post_build_scripts[] = {
        "remove-static-libs",
        "compress-man-pages",
+       "strip",
        NULL,
 };
 
diff --git a/src/scripts/strip b/src/scripts/strip
new file mode 100644 (file)
index 0000000..2c69591
--- /dev/null
@@ -0,0 +1,196 @@
+#!/bin/bash
+###############################################################################
+#                                                                             #
+# Pakfire - The IPFire package management system                              #
+# Copyright (C) 2021 Pakfire development team                                 #
+#                                                                             #
+# This program is free software: you can redistribute it and/or modify        #
+# it under the terms of the GNU General Public License as published by        #
+# the Free Software Foundation, either version 3 of the License, or           #
+# (at your option) any later version.                                         #
+#                                                                             #
+# This program is distributed in the hope that it will be useful,             #
+# but WITHOUT ANY WARRANTY; without even the implied warranty of              #
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               #
+# GNU General Public License for more details.                                #
+#                                                                             #
+# You should have received a copy of the GNU General Public License           #
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.       #
+#                                                                             #
+###############################################################################
+
+# XXX should this be hardcoded?
+SOURCE_DIR="/builddir/source"
+
+DEBUG_DIR="/usr/lib/debug"
+DEBUG_SOURCE_DIR="/usr/src/debug"
+
+error() {
+       echo "${0#/}: $@" >&2
+}
+
+build_id() {
+       local file="${1}"
+
+       LANG=C readelf -n "${file}" | sed -n "/Build ID/ { s/.*: //p; q; }"
+}
+
+list_sources() {
+       local file="${1}"
+
+       LANG=C readelf "${file}" --debug-dump 2>/dev/null | \
+               awk '/DW_AT_name +:/{name=$NF}/DW_AT_comp_dir +:/{{if (name == "<artificial>") next}{if (name !~ /^[<\/]/) {printf "%s/", $NF}}{print name}}'
+}
+
+extract_sources() {
+       local file="${1}"
+
+       local source
+       for source in $(list_sources "${file}"); do
+               local destination="${source/${SOURCE_DIR}/${debug_source_dir}}"
+               if [ -e "${source}" -a ! -e "${destination}" ]; then
+                       mkdir -p "${destination%/*}"
+                       if ! install -m 444 -o root -g root "${source}" "${destination}"; then
+                               return 1
+                       fi
+               fi
+       done
+
+       return 0
+}
+
+process_file() {
+       local file="${1}"
+
+       # The path of the file in BUILDROOT
+       local path="${file/${buildroot}/}"
+
+       echo "  ${path}"
+
+       local build_id="$(build_id "${file}")"
+
+       # Check if this file has already been stripped
+       if [ -n "${build_id}" ]; then
+               if [ -f "${debug_dir}/.build-id/${build_id:0:2}/${build_id:2}.debug" ]; then
+                       return 0
+               fi
+       else
+               if [ -f "${debug_dir}/${path}.debug" ]; then
+                       return 0
+               fi
+       fi
+
+       # Extract sources
+       if ! extract_sources "${file}"; then
+               error "Could not extract sources from ${file}"
+               return 1
+       fi
+
+       mkdir -p "${debug_dir}${path%/*}"
+
+       # Copy all debug sections to the debug directory
+       if ! objcopy --only-keep-debug "${file}" "${debug_dir}/${path}.debug"; then
+               error "Could not extract debug information of ${path}"
+               return 1
+       fi
+
+       local tempfile="$(mktemp "${file}.XXXXXX")"
+
+       # Add a debuglink section to the binary
+       if ! objcopy --add-gnu-debuglink="${debug_dir}/${path}.debug" "${file}" "${tempfile}"; then
+               error "Could not add debuglink section to ${path}"
+               rm -f "${tempfile}"
+               return 1
+       fi
+
+       # Create any hardlinks
+       local link
+       for link in $(find "${buildroot}" -not -path "${file}" -samefile "${file}"); do
+               mkdir -p "${link%/*}"
+
+               if ! ln "${file}" "${link}"; then
+                       return 1
+               fi
+       done
+
+       # Create links using build_id
+       if [ -n "${build_id}" ]; then
+               mkdir -p "${debug_dir}/.build-id/${build_id:0:2}"
+
+               # Link to the binary
+               if ! ln -s --relative "${file}" \
+                               "${debug_dir}/.build-id/${build_id:0:2}/${build_id:2}"; then
+                       return 1
+               fi
+
+               # Link the debug files
+               if ! ln -s --relative "${debug_dir}/${path}.debug" \
+                               "${debug_dir}/.build-id/${build_id:0:2}/${build_id:2}.debug"; then
+                       return 1
+               fi
+       fi
+
+       # Strip all debug symbols
+       if ! strip --strip-debug "${file}" -o "${tempfile}"; then
+               error "Could not strip ${path}"
+               rm -f "${tempfile}"
+               return 1
+       fi
+
+       # Copy back the stripped file
+       cat "${tempfile}" > "${file}"
+       rm -f "${tempfile}"
+
+       return 0
+}
+
+main() {
+       local buildroot="${1}"
+       shift
+
+       # Check if BUILDROOT exists
+       if [ ! -d "${buildroot}" ]; then
+               error "BUILDROOT does not exist"
+               return 1
+       fi
+
+       echo "Stripping unneeded symbols from binaries and libraries..."
+
+       local debug_dir="${buildroot}${DEBUG_DIR}"
+       local debug_source_dir="${buildroot}${DEBUG_SOURCE_DIR}"
+
+       local file
+       for file in $(find "${buildroot}" -type f \
+                       \( -perm -0100 -or -perm -0010 -or -perm -0001 \) | sort); do
+               # Determine the file type
+               local type="$(readelf -h "${file}" 2>/dev/null)"
+
+               case "${type}" in
+                       # Libraries and Relocatable binaries
+                       *Type:*"DYN (Shared object file)"*)
+                               ;;
+
+                       # Binaries
+                       *Type:*"EXEC (Executable file)"*)
+                               ;;
+
+                       # Static libraries
+                       *Type:*"REL (Relocatable file)"*)
+                               ;;
+
+                       # Skip any unrecognised files
+                       *)
+                               continue
+                               ;;
+               esac
+
+               if ! process_file "${file}"; then
+                       error "Could not strip ${file/${buildroot}/}"
+                       return 1
+               fi
+       done
+
+       return 0
+}
+
+main "$@" || exit $?