From: Michael Tremer Date: Wed, 26 May 2021 09:58:45 +0000 (+0000) Subject: scripts: Add a refactored implementation to strip binaries X-Git-Tag: 0.9.28~1285^2~64 X-Git-Url: http://git.ipfire.org/?a=commitdiff_plain;h=ffb65de6f5dfa8b5c1768b8b7401b58f617681d9;p=pakfire.git scripts: Add a refactored implementation to strip binaries Signed-off-by: Michael Tremer --- diff --git a/Makefile.am b/Makefile.am index a4ba14083..5c65960cf 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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 \ diff --git a/macros/arch.macro b/macros/arch.macro index 46f3cb248..19e09ca05 100644 --- a/macros/arch.macro +++ b/macros/arch.macro @@ -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" diff --git a/macros/cflags.macro b/macros/cflags.macro index 46dea1078..3447ef452 100644 --- a/macros/cflags.macro +++ b/macros/cflags.macro @@ -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 diff --git a/src/libpakfire/build.c b/src/libpakfire/build.c index 420ec4466..e5009b459 100644 --- a/src/libpakfire/build.c +++ b/src/libpakfire/build.c @@ -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 index 000000000..2c6959159 --- /dev/null +++ b/src/scripts/strip @@ -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 . # +# # +############################################################################### + +# 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 == "") 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 $?