1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611 612 613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654 655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691 692 693 694 695 696 697 698 699 700 701 702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720 721 722 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 742 743 744 745 746 747 748 749 750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 891 892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907 908 909 910 911 912 913 914 915 916 917 918 919 920 921 922 923 924 925 926 927 928 929 930 931 932 933 934 935 936 937 938 939 940 941 942 943 944 945 946 947 948 949 950 951 952 953 954 955 956 957 958 959 960 961 962 963 964 965 966 967 968 969 970 971 972 973 974 975
|
#!/bin/bash
# @PACKAGE@ @VERSION@
# find-debuginfo - automagically generate debug info and file list
# for inclusion in package file lists.
# Copyright (C) 2002-2021 rpm and debugedit contributors
# Copyright (C) 2025 Red Hat Inc.
#
# 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; version 2 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/>
help()
{
cat <<'EOF'
Usage: find-debuginfo [OPTION]... [builddir]
automagically generates debug info and file lists
Options:
[--strict-build-id] [-g] [-r] [-m] [-i] [-n] [-q] [-v]
[--keep-section SECTION] [--remove-section SECTION]
[--g-libs] [--no-ar-files]
[-j N] [--jobs N]
[-o debugfiles.list]
[-S debugsourcefiles.list]
[--run-dwz] [--dwz-low-mem-die-limit N]
[--dwz-max-die-limit N]
[--dwz-single-file-mode]
[--build-id-seed SEED]
[--unique-debug-suffix SUFFIX]
[--unique-debug-src-base BASE]
[[-l filelist]... [-p 'pattern'] -o debuginfo.list]
[builddir]
The -g flag says to use strip -g instead of full strip on DSOs or EXEs.
The --g-libs flag says to use strip -g instead of full strip ONLY on
DSOs. Options -g and --g-libs are mutually exclusive.
The -r flag says to use eu-strip --reloc-debug-sections.
Use --keep-section SECTION or --remove-section SECTION to explicitly
keep a (non-allocated) section in the main executable or explicitly
remove it into the .debug file. SECTION is an extended wildcard
pattern. Both options can be given more than once.
The --strict-build-id flag says to exit with failure status if
any ELF binary processed fails to contain a build-id note.
The -m flag says to include a .gnu_debugdata section (MiniDebugInfo) in
the main binary.
The -i flag says to include a .gdb_index section in the .debug file.
The -n flag says to not recompute the build-id.
The -j, --jobs N option will spawn N processes to do the debuginfo
extraction in parallel.
A single -o switch before any -l or -p switches simply renames
the primary output file from debugfiles.list to something else.
A -o switch that follows a -p switch or some -l switches produces
an additional output file with the debuginfo for the files in
the -l filelist file, or whose names match the -p pattern.
The -p argument is an grep -E -style regexp matching the a file name,
and must not use anchors (^ or $).
The --run-dwz flag instructs find-debuginfo to run the dwz utility
if available, and --dwz-low-mem-die-limit and --dwz-max-die-limit
provide detailed limits. See dwz(1) -l and -L option for details.
Use --dwz-single-file-mode to disable multi-file mode, see dwz(1) -m
for more details.
If --build-id-seed SEED is given then debugedit is called to
update the build-ids it finds adding the SEED as seed to recalculate
the build-id hash. This makes sure the build-ids in the ELF files
are unique between versions and releases of the same package.
(Use --build-id-seed "%{VERSION}-%{RELEASE}".)
If --unique-debug-suffix SUFFIX is given then the debug files created
for <FILE> will be named <FILE>-<SUFFIX>.debug. This makes sure .debug
are unique between package version, release and architecture.
(Use --unique-debug-suffix "-%{VERSION}-%{RELEASE}.%{_arch}".)
If --unique-debug-src-base BASE is given then the source directory
will be called /usr/debug/src/<BASE>. This makes sure the debug source
dirs are unique between package version, release and achitecture (Use
--unique-debug-src-base "%{name}-%{VERSION}-%{RELEASE}.%{_arch}")
If --no-ar-files is given, then static libraries will be ignored. Otherwise,
they receive only with source-path rewriting and collection. They are
not stripped, since they have no persistent build-ids to accommodate
eventual reunification.
The -q or --quiet flag silences all non-error output from the script.
The -v or --verbose flag add more output for all files processed.
When neither -q or -v is given then only output for each pass is given.
All file names in switches are relative to builddir ('.' if not given).
EOF
}
# Figure out where we are installed so we can call other helper scripts.
# Prefix to PATH to prefer tools from install dir.
install_dir="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
PATH=${install_dir}:$PATH
# A couple of binutils helper tools are used in this script.
# Let the user override them by setting them in environment variables.
# The default is the (target variant) of the tool found when debugedit
# was configured.
READELF=${READELF:=@READELF@}
OBJCOPY=${OBJCOPY:=@OBJCOPY@}
NM=${NM:=@NM@}
AR=${AR:=@AR@}
# With -g arg, pass it to strip on libraries or executables.
strip_g=false
# With --g-libs arg, pass it to strip on libraries.
strip_glibs=false
# with -r arg, pass --reloc-debug-sections to eu-strip.
strip_r=false
# keep or remove arguments to eu-strip.
keep_remove_args=
# with -m arg, add minimal debuginfo to binary.
include_minidebug=false
# with -i arg, add GDB index to .debug file.
include_gdb_index=false
# Barf on missing build IDs.
strict=false
# Do not recompute build IDs.
no_recompute_build_id=false
# DWZ parameters.
run_dwz=false
dwz_low_mem_die_limit=
dwz_max_die_limit=
dwz_single_file_mode=false
# build id seed given by the --build-id-seed option
build_id_seed=
# Arch given by --unique-debug-arch
unique_debug_suffix=
# Base given by --unique-debug-src-base
unique_debug_src_base=
# Number of parallel jobs to spawn
n_jobs=1
# exit early on --version or --help
done=false
# silence all output
quiet=false
# add more non-error output
verbose=false
# process static libraries if ar is new enough (binutils 2.31+) to support O
if [ -n "`ar 2>&1 | grep -F '[O]'`" ]; then
process_ar=true
else
process_ar=false
fi
BUILDDIR=.
out=debugfiles.list
srcout=
nout=0
while [ $# -gt 0 ]; do
case "$1" in
--strict-build-id)
strict=true
;;
--run-dwz)
run_dwz=true
;;
--dwz-low-mem-die-limit)
dwz_low_mem_die_limit=$2
shift
;;
--dwz-max-die-limit)
dwz_max_die_limit=$2
shift
;;
--dwz-single-file-mode)
dwz_single_file_mode=true
;;
--build-id-seed)
build_id_seed=$2
shift
;;
--unique-debug-suffix)
unique_debug_suffix=$2
shift
;;
--unique-debug-src-base)
unique_debug_src_base=$2
shift
;;
--g-libs)
strip_glibs=true
;;
-g)
strip_g=true
;;
-m)
include_minidebug=true
;;
-n)
no_recompute_build_id=true
;;
-i)
include_gdb_index=true
;;
-o)
if [ -z "${lists[$nout]}" ] && [ -z "${ptns[$nout]}" ]; then
out=$2
else
outs[$nout]=$2
((nout++))
fi
shift
;;
-l)
lists[$nout]="${lists[$nout]} $2"
shift
;;
-p)
ptns[$nout]=$2
shift
;;
-r)
strip_r=true
;;
--keep-section)
keep_remove_args="${keep_remove_args} --keep-section $2"
shift
;;
--remove-section)
keep_remove_args="${keep_remove_args} --remove-section $2"
shift
;;
-j)
n_jobs=$2
shift
;;
-j*)
n_jobs=${1#-j}
;;
--jobs)
n_jobs=$2
shift
;;
-S)
srcout=$2
shift
;;
--no-ar-files)
process_ar=false
;;
-q|--quiet)
quiet=true
verbose=false
;;
-v|--verbose)
quiet=false
verbose=true
;;
--version)
echo "find-debuginfo @VERSION@"
done=true;
;;
--help)
help
done=true
;;
*)
BUILDDIR=$1
shift
break
;;
esac
shift
done
# version or help given
if [ "$done" = "true" ]; then exit 0; fi
# Currently this scripts depends on some RPM environment variables
# being set. RPM_BUILD_ROOT as the installation root directory.
# RPM_BUILD_DIR as the top build dir (usually one above BUILDDIR).
# And RPM_PACKAGE_NAME, RPM_PACKAGE_VERSION, RPM_PACKAGE_RELEASE,
# RPM_ARCH to create an unique (dir) name. Warn if they aren't set.
for n in RPM_BUILD_ROOT RPM_BUILD_DIR RPM_PACKAGE_NAME; do
if eval test -z \"\${$n-}\"; then
echo >&2 "$n is not set"
exit 1
fi
done
if test -n "$build_id_seed" -a "$no_recompute_build_id" = "true"; then
echo >&2 "*** ERROR: --build-id-seed (unique build-ids) and -n (do not recompute build-id) cannot be used together"
exit 2
fi
if [ "$strip_g" = "true" ] && [ "$strip_glibs" = "true" ]; then
echo >&2 "*** ERROR: -g and --g-libs cannot be used together"
exit 2
fi
$quiet || echo "find-debuginfo: starting" 2>&1
i=0
while ((i < nout)); do
outs[$i]="$BUILDDIR/${outs[$i]}"
l=''
for f in ${lists[$i]}; do
l="$l $BUILDDIR/$f"
done
lists[$i]=$l
((++i))
done
LISTFILE="$BUILDDIR/$out"
SOURCEFILE="$BUILDDIR/debugsources.list"
LINKSFILE="$BUILDDIR/debuglinks.list"
ELFBINSFILE="$BUILDDIR/elfbins.list"
> "$SOURCEFILE"
> "$LISTFILE"
> "$LINKSFILE"
> "$ELFBINSFILE"
debugdir="${RPM_BUILD_ROOT}/usr/lib/debug"
strip_to_debug()
{
local g=
local r=
$strip_r && r=--reloc-debug-sections
$strip_g && case "$(file -bi "$2")" in
application/x-sharedlib*) g=-g ;;
application/x-executable*) g=-g ;;
application/x-pie-executable*) g=-g ;;
esac
$strip_glibs && case "$(file -bi "$2")" in
application/x-sharedlib*) g=-g ;;
esac
eu-strip --remove-comment $r $g ${keep_remove_args} -f "$1" "$2" || exit
chmod 444 "$1" || exit
}
add_minidebug()
{
local debuginfo="$1"
local binary="$2"
local dynsyms=`mktemp`
local funcsyms=`mktemp`
local keep_symbols=`mktemp`
local mini_debuginfo=`mktemp`
# In the minisymtab we don't need the .debug_ sections (already removed
# by -S) but also not other non-allocated PROGBITS, NOTE or NOBITS sections.
# List and remove them explicitly. We do want to keep the allocated,
# symbol and NOBITS sections so cannot use --keep-only because that is
# too aggressive. Field $2 is the section name, $3 is the section type
# and $8 are the section flags.
local remove_sections=`${READELF} -W -S "$debuginfo" \
| awk '{ if (index($2,".debug_") != 1 \
&& ($3 == "PROGBITS" || $3 == "NOTE" || $3 == "NOBITS") \
&& index($8,"A") == 0) \
printf "--remove-section "$2" " }'`
# Extract the dynamic symbols from the main binary, there is no need to also have these
# in the normal symbol table
${NM} -D "$binary" --format=posix --defined-only | awk '{ print $1 }' | sort > "$dynsyms"
# Extract all the text (i.e. function) symbols from the debuginfo
# Use format sysv to make sure we can match against the actual ELF FUNC
# symbol type. The binutils nm posix format symbol type chars are
# ambigous for architectures that might use function descriptors.
${NM} "$debuginfo" --format=sysv --defined-only | awk -F \| '{ if ($4 ~ "FUNC") print $1 }' | sort > "$funcsyms"
# Keep all the function symbols not already in the dynamic symbol table
comm -13 "$dynsyms" "$funcsyms" > "$keep_symbols"
# Copy the full debuginfo, keeping only a minumal set of symbols and removing some unnecessary sections
${OBJCOPY} -S $remove_sections --keep-symbols="$keep_symbols" "$debuginfo" "$mini_debuginfo" &> /dev/null
#Inject the compressed data into the .gnu_debugdata section of the original binary
xz "$mini_debuginfo"
mini_debuginfo="${mini_debuginfo}.xz"
${OBJCOPY} --add-section .gnu_debugdata="$mini_debuginfo" "$binary"
rm -f "$dynsyms" "$funcsyms" "$keep_symbols" "$mini_debuginfo"
}
# Make a relative symlink to $1 called $3$2
shopt -s extglob
link_relative()
{
local t="$1" f="$2" pfx="$3"
local fn="${f#/}" tn="${t#/}"
local fd td d
while fd="${fn%%/*}"; td="${tn%%/*}"; [ "$fd" = "$td" ]; do
fn="${fn#*/}"
tn="${tn#*/}"
done
d="${fn%/*}"
if [ "$d" != "$fn" ]; then
d="${d//+([!\/])/..}"
tn="${d}/${tn}"
fi
mkdir -p "$(dirname "$pfx$f")" && ln -snf "$tn" "$pfx$f"
}
# Make a symlink in /usr/lib/debug/$2 to $1
debug_link()
{
local l="/usr/lib/debug$2"
local t="$1"
echo >> "$LINKSFILE" "$l $t"
link_relative "$t" "$l" "$RPM_BUILD_ROOT"
}
get_debugfn()
{
dn=$(dirname "${1#$RPM_BUILD_ROOT}")
bn=$(basename "$1" .debug)${unique_debug_suffix}.debug
debugdn=${debugdir}${dn}
debugfn=${debugdn}/${bn}
}
set -o pipefail
strict_error=ERROR
$strict || strict_error=WARNING
temp=$(mktemp -d ${TMPDIR:-/tmp}/find-debuginfo.XXXXXX)
trap 'rm -rf "$temp"' EXIT
# Build a list of unstripped ELF files and their hardlinks
touch "$temp/primary"
touch "$temp/linked"
(
find "$RPM_BUILD_ROOT" ! -path "${debugdir}/*.debug" -type f \( -perm -0100 -or -perm -0010 -or -perm -0001 \) -print |
file -N -f - |
sed -n -e 's/^\(.*\):[ ]*.*ELF.*, not stripped.*/\1/p';
# plus static libraries
$process_ar && find "$RPM_BUILD_ROOT" -type f -name '*.a' -print |
file -N -f - |
sed -n -e 's/^\(.*\):[ ]*current ar archive.*/\1/p';
true
) |
env LC_ALL=C sort |
xargs --no-run-if-empty stat -c '%h %D_%i %n' |
while read nlinks inum f; do
if [ $nlinks -gt 1 ]; then
var=seen_$inum
if test -n "${!var}"; then
echo "$inum $f" >>"$temp/linked"
continue
else
read "$var" < <(echo 1)
fi
fi
echo "$nlinks $inum $f" >>"$temp/primary"
done
# Handle ELF archives
do_ar_file()
{
local nlinks="$1" inum="$2" f="$3" id link linked
local tmpa="$temp/$inum-output.a"
local res=0
# See also cpio SOURCEFILE copy. Directories must match up.
debug_base_name="$RPM_BUILD_DIR"
debug_dest_name="/usr/src/debug"
if [ ! -z "$unique_debug_src_base" ]; then
debug_base_name="$BUILDDIR"
debug_dest_name="/usr/src/debug/${unique_debug_src_base}"
fi
$verbose && echo "processing debug info in $f"
# Extract members from archive, one at a time. There may be
# duplicate names, so we can't just extract the entire archive in
# one go (overwriting each other). Instead, we pick off member
# files one-by-one, into synthetic subdirectories, adding processed
# versions to a new archive, in order.
# Create empty output .a; mktemp would create a 0-byte file, which ar rv doesn't like
${AR} r "$tmpa" 2>/dev/null # no members, suppress "ar: creating foo.a" message
${AR} tvO "$f" | while read line; do
local pattern='^[rwx-]+ [0-9]+/[0-9]+ +([0-9]+) (.................) (.*) (0x[0-9a-f]+)$'
if [[ $line =~ $pattern ]]; then
local size=${BASH_REMATCH[1]}
local date=${BASH_REMATCH[2]}
local member=${BASH_REMATCH[3]}
local offset
(( offset=${BASH_REMATCH[4]} )) # convert from hexadecimal
$verbose && echo "considering ${f#$RPM_BUILD_DIR/} ${member} size ${size} at ${offset}"
local tmpdir="$temp/$inum-archive-member" # super short lived
local member_dn=$(dirname "$member")
if [ "$member_dn" = "." ]; then
member_dn="" # empty
else
member_dn="${member_dn}/" # or suffixed with /
fi
local member_bn=$(basename "$member")
# (re)create a directory to hold the (pathname-inclusive) member
mkdir -p "$tmpdir/$member_dn"
# extract the file by offset, because extracting it by name
# is hard, in case the same name exists multiple times. A
# distinct instance-number would have to be given to ar ("N ###"),
# kept on a per-name basis.
(cd "$tmpdir"; dd status=none if="$f" of="$member_dn$member_bn" bs=1 skip="$offset" count="$size")
if [ $? -ne 0 ]; then
res=1
fi
# preserve timestamp from original file, though debugedit may lose it, PR33096
touch -d "$date" "$tmpdir/$member_dn$member_bn"
if file "$tmpdir/$member_dn$member_bn" |
grep -qE 'ELF.*, not stripped'; then
debugedit -b "$debug_base_name" -d "$debug_dest_name" \
-l "$SOURCEFILE" "$tmpdir/$member_dn$member_bn"
if [ $? -ne 0 ]; then
res=1
$verbose && echo "failed processing ELF object ${member}"
else
$verbose && echo "processed ELF object ${member}"
fi
else
$verbose && echo "skipped ${member}, no debuginfo"
fi
# add the file; qP mode, so strict append, no dupe elimination, path preserved
(cd "$tmpdir"; ${AR} qP "$tmpa" "$member_dn$member_bn")
# remove the entire temporary directory, in case another
# member object comes later with a conflicting name
rm -rf "$tmpdir"
else
$verbose && echo "skipping archive $f with unparseable contents"
res=1
fi
done
if [ $res -eq 0 ]; then
# replace original archive with new version
${AR} sP "$tmpa" # ranlib, preserve paths
mv "$tmpa" "$f"
fi
rm -f "$tmpa"
$verbose && echo found $(tr -dc '\0' < "$SOURCEFILE" | wc -c) source files
# NB: no need to strip or dwz-compress or gdbindex or
# ELFBINSFILE-collect objects / archives. These operations only
# make sense on the final binaries that the static archives are
# linked into.
return $res
}
# Strip ELF binaries
do_file()
{
local nlinks=$1 inum=$2 f=$3 id link linked
# reject files already located under /usr/lib/debug, presumably processed
get_debugfn "$f"
[ -f "${debugfn}" ] && return 0
local ar_re="^.*\.a$"
if [[ $f =~ $ar_re ]]; then # treat as static archive
do_ar_file "$1" "$2" "$3"
return
fi
$verbose && echo "extracting debug info from $f"
# See also cpio SOURCEFILE copy. Directories must match up.
debug_base_name="$RPM_BUILD_DIR"
debug_dest_name="/usr/src/debug"
if [ ! -z "$unique_debug_src_base" ]; then
debug_base_name="$BUILDDIR"
debug_dest_name="/usr/src/debug/${unique_debug_src_base}"
fi
no_recompute=
if [ "$no_recompute_build_id" = "true" ]; then
no_recompute="-n"
fi
id=$(debugedit -b "$debug_base_name" -d "$debug_dest_name" \
$no_recompute -i \
${build_id_seed:+--build-id-seed="$build_id_seed"} \
-l "$SOURCEFILE" "$f") || return 1
if [ -z "$id" ]; then
echo >&2 "*** ${strict_error}: No build ID note found in $f"
$strict && return 2
fi
$verbose && echo found $(tr -dc '\0' < "$SOURCEFILE" | wc -c) source files
# debugedit makes sure to to get write permission to the file and
# restores original state after modifications. Other utilities
# might not.
f_writable="false"
if test -w "$f"; then f_writable="true"; fi
# Add .gdb_index if requested.
if $include_gdb_index; then
if type gdb-add-index >/dev/null 2>&1; then
if test "$f_writable" = "false"; then
chmod u+w "$f"
fi
gdb-add-index "$f" || {
status=$?
echo >&2 "*** ERROR:: GDB exited with exit status $status during index generation"
if test "$f_writable" = "false"; then
chmod u-w "$f"
fi
return 2
}
if test "$f_writable" = "false"; then
chmod u-w "$f"
fi
else
echo >&2 "*** ERROR: GDB index requested, but no gdb-add-index installed"
return 2
fi
fi
# Compress any annobin notes in the original binary.
# Ignore any errors, since older objcopy don't support --merge-notes.
if test "$f_writable" = "false"; then
chmod u+w "$f"
fi
${OBJCOPY} --merge-notes "$f" 2>/dev/null || true
if test "$f_writable" = "false"; then
chmod u-w "$f"
fi
# A binary already copied into /usr/lib/debug doesn't get stripped,
# just has its file names collected and adjusted.
case "$dn" in
/usr/lib/debug/*)
return 0 ;;
esac
mkdir -p "${debugdn}"
if test "$f_writable" = "true"; then
strip_to_debug "${debugfn}" "$f"
else
chmod u+w "$f"
strip_to_debug "${debugfn}" "$f"
chmod u-w "$f"
fi
# strip -g implies we have full symtab, don't add mini symtab in that case.
# It only makes sense to add a minisymtab for executables and shared
# libraries. Other executable ELF files (like kernel modules) don't need it.
if [ "$include_minidebug" = "true" ] && [ "$strip_g" = "false" ]; then
skip_mini=true
if [ "$strip_glibs" = "false" ]; then
case "$(file -bi "$f")" in
application/x-sharedlib*) skip_mini=false ;;
esac
fi
case "$(file -bi "$f")" in
application/x-executable*) skip_mini=false ;;
application/x-pie-executable*) skip_mini=false ;;
esac
if test "$skip_mini" = "false"; then
if test "$f_writable" = "false"; then
chmod u+w "$f"
fi
add_minidebug "${debugfn}" "$f"
if test "$f_writable" = "false"; then
chmod u-w "$f"
fi
fi
fi
echo "./${f#$RPM_BUILD_ROOT}" >> "$ELFBINSFILE"
# If this file has multiple links, make the corresponding .debug files
# all links to one file too.
if [ $nlinks -gt 1 ]; then
grep "^$inum " "$temp/linked" | while read inum linked; do
link=$debugfn
get_debugfn "$linked"
$verbose && echo "hard linked $link to $debugfn"
mkdir -p "$(dirname "$debugfn")" && ln -nf "$link" "$debugfn"
done
fi
return 0
}
# 16^6 - 1 or about 16 million files
FILENUM_DIGITS=6
run_job()
{
local jobid=$1 filenum
local SOURCEFILE=$temp/debugsources.$jobid ELFBINSFILE=$temp/elfbins.$jobid
local res=0
>"$SOURCEFILE"
>"$ELFBINSFILE"
# can't use read -n <n>, because it reads bytes one by one, allowing for
# races
while :; do
filenum=$(dd bs=$(( FILENUM_DIGITS + 1 )) count=1 status=none)
if test -z "$filenum"; then
break
fi
do_file $(sed -n "$(( 0x$filenum )) p" "$temp/primary")
res=$?
if [ $res != 0 ]; then
break
fi
done
echo $res >"$temp/res.$jobid"
}
n_files=$(wc -l <"$temp/primary")
$quiet || echo "Extracting debug info from $n_files files" 2>&1
if [ $n_jobs -gt $n_files ]; then
n_jobs=$n_files
fi
if [ $n_jobs -le 1 ]; then
while read nlinks inum f; do
do_file "$nlinks" "$inum" "$f"
res=$?
if [ "$res" != "0" ]; then
exit $res
fi
done <"$temp/primary"
else
for ((i = 1; i <= n_files; i++)); do
printf "%0${FILENUM_DIGITS}x\\n" $i
done | (
exec 3<&0
for ((i = 0; i < n_jobs; i++)); do
# The shell redirects stdin to /dev/null for background jobs. Work
# around this by duplicating fd 0
run_job $i <&3 &
done
wait
)
for f in "$temp"/res.*; do
test -f "$f" || continue
res=$(< "$f")
if [ "$res" != "0" ]; then
exit $res
fi
done
# List of sources may have lots of duplicates. A kernel build was seen
# with this list reaching 448 megabytes in size. "sort" helps to not have
# _two_ sets of 448 megabytes of temp files here.
LC_ALL=C sort -z -u "$temp"/debugsources.* >"$SOURCEFILE"
cat "$temp"/elfbins.* >"$ELFBINSFILE"
fi
# Invoke the DWARF Compressor utility.
if $run_dwz \
&& [ -d "${RPM_BUILD_ROOT}/usr/lib/debug" ]; then
readarray dwz_files < <(cd "${RPM_BUILD_ROOT}/usr/lib/debug"; find -type f -name \*.debug | LC_ALL=C sort)
if [ ${#dwz_files[@]} -gt 0 ]; then
$quiet || echo "DWARF-compressing ${#dwz_files[@]} files" 2>&1
$verbose && size_before=$(du -sk ${RPM_BUILD_ROOT}/usr/lib/debug | cut -f1)
dwz_multifile_name="${RPM_PACKAGE_NAME}-${RPM_PACKAGE_VERSION}-${RPM_PACKAGE_RELEASE}.${RPM_ARCH}"
dwz_multifile_suffix=
dwz_multifile_idx=0
while [ -f "${RPM_BUILD_ROOT}/usr/lib/debug/.dwz/${dwz_multifile_name}${dwz_multifile_suffix}" ]; do
let ++dwz_multifile_idx
dwz_multifile_suffix=".${dwz_multifile_idx}"
done
dwz_multifile_name="${dwz_multifile_name}${dwz_multifile_suffix}"
dwz_opts="-h -q -r"
[ -n "@DWZ_J@" ] && dwz_opts="${dwz_opts} -j ${n_jobs}"
[ ${#dwz_files[@]} -gt 1 ] && [ "$dwz_single_file_mode" = "false" ] \
&& dwz_opts="${dwz_opts} -m .dwz/${dwz_multifile_name}"
mkdir -p "${RPM_BUILD_ROOT}/usr/lib/debug/.dwz"
[ -n "${dwz_low_mem_die_limit}" ] \
&& dwz_opts="${dwz_opts} -l ${dwz_low_mem_die_limit}"
[ -n "${dwz_max_die_limit}" ] \
&& dwz_opts="${dwz_opts} -L ${dwz_max_die_limit}"
if type dwz >/dev/null 2>&1; then
( cd "${RPM_BUILD_ROOT}/usr/lib/debug" && dwz $dwz_opts ${dwz_files[@]} )
else
echo >&2 "*** ERROR: DWARF compression requested, but no dwz installed"
exit 2
fi
$verbose && size_after=$(du -sk ${RPM_BUILD_ROOT}/usr/lib/debug | cut -f1)
$verbose && echo "original debug info size: ${size_before}kB, size after compression: ${size_after}kB"
# Remove .dwz directory if empty
rmdir "${RPM_BUILD_ROOT}/usr/lib/debug/.dwz" 2>/dev/null
# dwz invalidates .gnu_debuglink CRC32 in the main files.
cat "$ELFBINSFILE" |
(cd "$RPM_BUILD_ROOT"; \
tr '\n' '\0' | xargs -0 sepdebugcrcfix usr/lib/debug)
fi
fi
# For each symlink whose target has a .debug file,
# make a .debug symlink to that file.
$quiet || echo "Creating .debug symlinks for symlinks to ELF files" 2>&1
find "$RPM_BUILD_ROOT" ! -path "${debugdir}/*" -type l -print |
while read f
do
t=$(readlink -m "$f").debug
f=${f#$RPM_BUILD_ROOT}
t=${t#$RPM_BUILD_ROOT}
if [ -f "$debugdir$t" ]; then
$verbose && echo "symlinked /usr/lib/debug$t to /usr/lib/debug${f}.debug"
debug_link "/usr/lib/debug$t" "${f}.debug"
fi
done
if [ -s "$SOURCEFILE" ]; then
# See also debugedit invocation. Directories must match up.
debug_base_name="$RPM_BUILD_DIR"
debug_dest_name="/usr/src/debug"
if [ ! -z "$unique_debug_src_base" ]; then
debug_base_name="$BUILDDIR"
debug_dest_name="/usr/src/debug/${unique_debug_src_base}"
fi
$quiet || echo "Copying sources found by 'debugedit -l' to ${debug_dest_name}" 2>&1
mkdir -p "${RPM_BUILD_ROOT}${debug_dest_name}"
# Filter out anything compiler generated which isn't a source file.
# e.g. <internal>, <built-in>, <__thread_local_inner macros>.
# Some compilers generate them as if they are part of the working
# directory (which is why we match against ^ or /).
LC_ALL=C sort -z -u "$SOURCEFILE" | grep -E -v -z '(^|/)<[a-z _-]+>$' |
(cd "${debug_base_name}"; cpio -pd0mL --quiet "${RPM_BUILD_ROOT}${debug_dest_name}")
# stupid cpio creates new directories in mode 0700,
# and non-standard modes may be inherented from original directories, fixup
find "${RPM_BUILD_ROOT}${debug_dest_name}" -type d -print0 |
xargs --no-run-if-empty -0 chmod 0755
fi
if [ -d "${RPM_BUILD_ROOT}/usr/lib" ] || [ -d "${RPM_BUILD_ROOT}/usr/src" ]; then
((nout > 0)) ||
test ! -d "${RPM_BUILD_ROOT}/usr/lib" ||
(cd "${RPM_BUILD_ROOT}/usr/lib"; find debug -type d) |
sed 's,^,%dir /usr/lib/,' >> "$LISTFILE"
(cd "${RPM_BUILD_ROOT}/usr"
test ! -d lib/debug || find lib/debug ! -type d
test ! -d src/debug -o -n "$srcout" || find src/debug -mindepth 1 -maxdepth 1
) | sed 's,^,/usr/,' >> "$LISTFILE"
fi
if [ -n "$srcout" ]; then
srcout="$BUILDDIR/$srcout"
> "$srcout"
if [ -d "${RPM_BUILD_ROOT}/usr/src/debug" ]; then
(cd "${RPM_BUILD_ROOT}/usr"
find src/debug -mindepth 1 -maxdepth 1
) | sed 's,^,/usr/,' >> "$srcout"
fi
fi
# Append to $1 only the lines from stdin not already in the file.
append_uniq()
{
grep -F -f "$1" -x -v >> "$1"
}
# Helper to generate list of corresponding .debug files from a file list.
filelist_debugfiles()
{
local extra="$1"
shift
sed 's/^%[a-z0-9_][a-z0-9_]*([^)]*) *//
s/^%[a-z0-9_][a-z0-9_]* *//
/^$/d
'"$extra" "$@"
}
# Write an output debuginfo file list based on given input file lists.
filtered_list()
{
local out="$1"
shift
test $# -gt 0 || return
grep -F -f <(filelist_debugfiles 's,^.*$,/usr/lib/debug&.debug,' "$@") \
-x $LISTFILE >> $out
sed -n -f <(filelist_debugfiles 's/[\\.*+#]/\\&/g
h
s,^.*$,s# &$##p,p
g
s,^.*$,s# /usr/lib/debug&.debug$##p,p
' "$@") "$LINKSFILE" | append_uniq "$out"
}
# Write an output debuginfo file list based on an grep -E -style regexp.
pattern_list()
{
local out="$1" ptn="$2"
test -n "$ptn" || return
grep -E -x -e "$ptn" "$LISTFILE" >> "$out"
sed -n -r "\#^$ptn #s/ .*\$//p" "$LINKSFILE" | append_uniq "$out"
}
#
# When given multiple -o switches, split up the output as directed.
#
i=0
while ((i < nout)); do
> ${outs[$i]}
filtered_list ${outs[$i]} ${lists[$i]}
pattern_list ${outs[$i]} "${ptns[$i]}"
grep -Fvx -f ${outs[$i]} "$LISTFILE" > "${LISTFILE}.new"
mv "${LISTFILE}.new" "$LISTFILE"
((++i))
done
if ((nout > 0)); then
# Generate %dir lines for each output list.
generate_percent_dir()
{
while read -r line; do
while test "${line:0:15}" = "/usr/lib/debug/"; do
line="${line%/*}"
printf '%s\n' "$line"
done
done | \
sort -u | \
while read -r line; do
test -d "${RPM_BUILD_ROOT}$line" && printf '%%dir %s\n' "$line"
done
}
i=0
while ((i < nout)); do
generate_percent_dir < "${outs[$i]}" > "${outs[$i]}.new"
cat "${outs[$i]}" >> "${outs[$i]}.new"
mv -f "${outs[$i]}.new" "${outs[$i]}"
((++i))
done
generate_percent_dir < "${LISTFILE}" > "${LISTFILE}.new"
cat "$LISTFILE" >> "${LISTFILE}.new"
mv "${LISTFILE}.new" "$LISTFILE"
fi
$quiet || echo "find-debuginfo: done" 2>&1
exit 0
|