summaryrefslogtreecommitdiffstats
path: root/dh_strip
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xdh_strip445
1 files changed, 445 insertions, 0 deletions
diff --git a/dh_strip b/dh_strip
new file mode 100755
index 0000000..5cd32c1
--- /dev/null
+++ b/dh_strip
@@ -0,0 +1,445 @@
+#!/usr/bin/perl
+
+=head1 NAME
+
+dh_strip - strip executables, shared libraries, and some static libraries
+
+=cut
+
+use strict;
+use warnings;
+use File::Find;
+use Debian::Debhelper::Dh_Lib;
+
+our $VERSION = DH_BUILTIN_VERSION;
+
+=head1 SYNOPSIS
+
+B<dh_strip> [S<I<debhelper options>>] [B<-X>I<item>] [B<--dbg-package=>I<package>] [B<--keep-debug>]
+
+=head1 DESCRIPTION
+
+B<dh_strip> is a debhelper program that is responsible for stripping
+out debug symbols in executables, shared libraries, and static
+libraries that are not needed during execution.
+
+This program examines your package build directories and works out what
+to strip on its own. It uses L<file(1)> and file permissions and filenames
+to figure out what files are shared libraries (F<*.so>), executable binaries,
+and static (F<lib*.a>) and debugging libraries (F<lib*_g.a>, F<debug/*.so>), and
+strips each as much as is possible. (Which is not at all for debugging
+libraries.) In general it seems to make very good guesses, and will do the
+right thing in almost all cases.
+
+Since it is very hard to automatically guess if a file is a
+module, and hard to determine how to strip a module, B<dh_strip> does not
+currently deal with stripping binary modules such as F<.o> files.
+
+=head1 OPTIONS
+
+=over 4
+
+=item B<-X>I<item>, B<--exclude=>I<item>
+
+Exclude files that contain I<item> anywhere in their filename from being
+stripped. You may use this option multiple times to build up a list of
+things to exclude.
+
+=item B<--dbg-package=>I<package>
+
+B<This option is a now special purpose option that you normally do not
+need>. In most cases, there should be little reason to use this
+option for new source packages as debhelper automatically generates
+debug packages ("dbgsym packages"). B<If you have a manual
+--dbg-package> that you want to replace with an automatically
+generated debug symbol package, please see the B<--dbgsym-migration>
+option.
+
+Causes B<dh_strip> to save debug symbols stripped from the packages it acts on
+as independent files in the package build directory of the specified debugging
+package.
+
+For example, if your packages are libfoo and foo and you want to include a
+I<foo-dbg> package with debugging symbols, use B<dh_strip --dbg-package=>I<foo-dbg>.
+
+This option implies B<--no-automatic-dbgsym> and I<cannot> be used
+with B<--automatic-dbgsym> or B<--dbgsym-migration>.
+
+=item B<-k>, B<--keep-debug>
+
+B<This option is a now special purpose option that you normally do not
+need>. In most cases, there should be little reason to use this
+option for new source packages as debhelper automatically generates
+debug packages ("dbgsym packages"). B<If you have a manual
+--dbg-package> that you want to replace with an automatically
+generated debug symbol package, please see the B<--dbgsym-migration>
+option.
+
+Debug symbols will be retained, but split into an independent
+file in F<usr/lib/debug/> in the package build directory. B<--dbg-package>
+is easier to use than this option, but this option is more flexible.
+
+This option implies B<--no-automatic-dbgsym> and I<cannot> be used
+with B<--automatic-dbgsym>.
+
+=item B<--dbgsym-migration=>I<package-relation>
+
+This option is used to migrate from a manual "-dbg" package (created
+with B<--dbg-package>) to an automatic generated debug symbol
+package. This option should describe a valid B<Replaces>- and
+B<Breaks>-relation, which will be added to the debug symbol package to
+avoid file conflicts with the (now obsolete) -dbg package.
+
+This option implies B<--automatic-dbgsym> and I<cannot> be used with
+B<--keep-debug>, B<--dbg-package> or B<--no-automatic-dbgsym>.
+
+Examples:
+
+ dh_strip --dbgsym-migration='libfoo-dbg (<< 2.1-3~)'
+
+ dh_strip --dbgsym-migration='libfoo-tools-dbg (<< 2.1-3~), libfoo2-dbg (<< 2.1-3~)'
+
+=item B<--automatic-dbgsym>, B<--no-automatic-dbgsym>
+
+Control whether B<dh_strip> should be creating debug symbol packages
+when possible.
+
+The default is to create debug symbol packages.
+
+=item B<--ddebs>, B<--no-ddebs>
+
+Historical name for B<--automatic-dbgsym> and B<--no-automatic-dbgsym>.
+
+=item B<--ddeb-migration=>I<package-relation>
+
+Historical name for B<--dbgsym-migration>.
+
+=back
+
+=head1 NOTES
+
+If the B<DEB_BUILD_OPTIONS> environment variable contains B<nostrip>,
+nothing will be stripped, in accordance with Debian policy (section
+10.1 "Binaries"). This will also inhibit the automatic creation of
+debug symbol packages.
+
+The automatic creation of debug symbol packages can also be prevented
+by adding B<noautodbgsym> to the B<DEB_BUILD_OPTIONS> environment
+variable. However, B<dh_strip> will still add debuglinks to ELF
+binaries when this flag is set. This is to ensure that the regular
+deb package will be identical with and without this flag (assuming it
+is otherwise "bit-for-bit" reproducible).
+
+=head1 CONFORMS TO
+
+Debian policy, version 3.0.1
+
+=cut
+
+init(options => {
+ 'keep-debug|keep|k' => \$dh{K_FLAG},
+ 'dbgsym-migration=s' => \$dh{MIGRATE_DBGSYM},
+ 'automatic-dbgsym!' => \$dh{ENABLE_DBGSYM},
+ # Deprecated variants
+ 'ddeb-migration=s' => \$dh{MIGRATE_DBGSYM},
+ 'ddebs!' => \$dh{ENABLE_DBGSYM},
+
+});
+
+if ($dh{MIGRATE_DBGSYM}) {
+ error("--keep-debug and --dbgsym-migration are mutually exclusive") if ($dh{K_FLAG});
+ error("--dbg-package and --dbgsym-migration are mutually exclusive") if ($dh{DEBUGPACKAGE});
+}
+
+if ($dh{ENABLE_DBGSYM}) {
+ error("--keep-debug and explicit --automatic-dbgsym are mutually exclusive") if ($dh{K_FLAG});
+ error("--dbg-package and explicit --automatic-dbgsym are mutually exclusive") if ($dh{DEBUGPACKAGE});
+}
+
+$dh{ENABLE_DBGSYM} = 1 if not defined($dh{ENABLE_DBGSYM});
+
+if ($dh{MIGRATE_DBGSYM} and not $dh{ENABLE_DBGSYM}) {
+ error("--dbgsym-migration and --no-automatic-dbgsym are mutually exclusive");
+}
+
+# This variable can be used to turn off stripping (see Policy).
+exit 0 if (get_buildoption('nostrip'));
+
+my $no_auto_dbgsym = 0;
+$no_auto_dbgsym = 1 if get_buildoption('noautodbgsym') or get_buildoption('noddebs');
+
+# Check if a file is an elf binary, shared library, or static library,
+# for use by File::Find. It'll fill the 3 first arrays with anything
+# it finds. The @build_ids will be the collected build-ids (if any)
+my (@shared_libs, @executables, @static_libs, @build_ids, %file_output);
+sub testfile {
+ my $fn = $_;
+ return if -l $fn; # Always skip symlinks.
+
+ # See if we were asked to exclude this file.
+ # Note that we have to test on the full filename, including directory.
+ if (excludefile($fn)) {
+ $File::Find::prune = 1 if -d _;
+ return;
+ }
+ # Ignore the .../debug/.build-id/ directory. It is not really helpful
+ # to strip debug symbols.
+ $File::Find::prune = 1 if -d _ && index($fn, '/debug/.build-id/') > -1;
+ return if -d _;
+
+ # Is it a debug library in a debug subdir?
+ return if $fn=~m{debug/.*\.so};
+ return if $fn=~m{/guile/.*\.go$};
+
+ # Exploit the previous stat call to get the $mode, so we can check
+ # later if it is executable or not.
+ #
+ # NB: compat() can issue a stat, so we /should/ do this now
+ my (undef, undef, $mode, undef) = stat(_);
+
+ if (compat(10)) {
+ # In compat 10 and earlier, we used filenames and file(1)
+
+ # Does its filename look like a shared library?
+ # - *.cmxs are OCaml native code shared libraries
+ # - *.node are also native ELF binaries (for node-js)
+ if ($fn =~ m/\.(?:so.*?|cmxs|node)$/) {
+ # Ok, do the expensive test.
+ my $type = get_file_type($fn, 1);
+ if ($type =~ m/ELF.*shared/) {
+ push @shared_libs, $fn;
+ return;
+ }
+ }
+
+ # -x is not good enough for this test
+ if ($mode & 0111) {
+ # Ok, expensive test.
+ my $type = get_file_type($fn, 1);
+ if ($type =~ m/ELF.*(executable|shared)/) {
+ push(@executables, $fn);
+ return;
+ }
+ }
+ } else {
+ # In compat 11, we check the ELF header manually (because bulking file(1) is a pain and
+ # it is too slow otherwise)
+
+ if (is_so_or_exec_elf_file($fn)) {
+ # -x is not good enough for this test
+ if ($mode & 0111) {
+ push(@executables, $fn);
+ } else {
+ push(@shared_libs, $fn);
+ }
+ return;
+ }
+ }
+ # Is it a static library, and not a debug library?
+ if ($fn =~ m/\/lib[^\/]*\.a$/ && $fn !~ m/.*_g\.a$/) {
+ # Is it a binary file, or something else (maybe a linker
+ # script on Hurd, for example? I don't use file, because
+ # file returns a variety of things on static libraries.
+ if (-B $fn) {
+ push @static_libs, $fn;
+ return;
+ }
+ }
+}
+
+sub write_buildid_file {
+ my ($package, $build_ids) = @_;
+ my $dir = "debian/.debhelper/${package}";
+ my $path = "${dir}/dbgsym-build-ids";
+ install_dir($dir);
+ open(my $fd, '>>', $path) or error("open $path failed: $!");
+ print {$fd} join(q{ }, sort(@{$build_ids})) . ' ';
+ close($fd) or error("close $path failed: $!");
+}
+
+# I could just use `file $_[0]`, but this is safer
+sub get_file_type {
+ my ($file, $cache_ok) = @_;
+ return $file_output{$file} if $cache_ok && $file_output{$file};
+ my @file_args = Debian::Debhelper::Dh_Lib::_internal_optional_file_args();
+ my @cmdline = ('file', @file_args, '--brief', '-e', 'apptype', '-e', 'ascii', '-e', 'encoding', '-e', 'cdf',
+ '-e', 'compress', '-e', 'tar', '--', $file);
+
+ open(my $fd, '-|', @cmdline) // error("cannot fork+exec file: $!");
+ my $type = <$fd>;
+ close($fd) || error_exitcode(escape_shell(@cmdline));
+
+ error("file(1) gave no result for $file!?") if (not $type) ;
+ return $file_output{$file} = $type;
+}
+
+sub make_debug {
+ my ($objcopy, $file, $tmp, $desttmp, $use_build_id) = @_;
+ my ($debug_path, $debug_build_id);
+
+ # Don't try to copy debug symbols out if the file is already
+ # stripped.
+ #
+ # Disable caching for non-build-id based extractions.
+ # Unfortunately, it breaks when there are hardlinks to the same
+ # ELF files.
+ my $file_info = get_file_type($file, $use_build_id ? 1 : 0);
+ return unless $file_info =~ /not stripped/;
+
+ if ($use_build_id) {
+ if ($file_info =~ m/BuildID\[sha1]\s*=\s*([0-9a-f]{2})([0-9a-f]+)/ or
+ `LC_ALL=C readelf -n $file`=~ /^\s+Build ID: ([0-9a-f]{2})([0-9a-f]+)$/m) {
+ $debug_path=$desttmp."/usr/lib/debug/.build-id/$1/$2.debug";
+ $debug_build_id="${1}${2}";
+ push(@build_ids, $debug_build_id);
+ } else {
+ # For dbgsyms, we need build-id (else it will not be
+ # co-installable).
+ warning("Could not find the BuildID in $file");
+ return if $use_build_id > 1;
+ }
+ }
+ if (not $debug_path) {
+ # Either not using build_id OR no build-id available
+ my ($base_file)=$file=~/^\Q$tmp\E(.*)/;
+ $debug_path=$desttmp."/usr/lib/debug/".$base_file;
+ }
+ install_dir(dirname($debug_path));
+ if (compat(8) && $use_build_id < 2) {
+ doit($objcopy, "--only-keep-debug", $file, $debug_path);
+ }
+ else {
+ # Compat 9 OR a dbgsym package.
+ doit($objcopy, "--only-keep-debug", "--compress-debug-sections", $file, $debug_path) unless -e $debug_path;
+ }
+
+ # No reason for this to be executable.
+ reset_perm_and_owner(0644, $debug_path);
+ return $debug_path;
+}
+
+sub attach_debug {
+ my ($objcopy, $file, $debug_path) = @_;
+ doit($objcopy, "--add-gnu-debuglink", $debug_path, $file);
+}
+
+my %all_packages = map { $_ => 1 } getpackages();
+
+sub process_packages {
+ foreach my $package (@_) {
+ my $tmp=tmpdir($package);
+ my $objcopy = cross_command($package, "objcopy");
+ my $strip = cross_command($package, "strip");
+
+ # Support for keeping the debugging symbols in a detached file.
+ my $keep_debug=$dh{K_FLAG};
+ my $debugtmp=$tmp;
+ my $use_build_id = compat(8) ? 0 : 1;
+ if ($dh{DEBUGPACKAGE}) {
+ $keep_debug=1;
+ my $debugpackage=$dh{DEBUGPACKAGE};
+ error("debug package $debugpackage is not listed in the control file") if (!$all_packages{$debugpackage});
+ $debugtmp=tmpdir($debugpackage);
+ }
+ # Temporary workaround: Do not build dbgsym packages for udebs as
+ # dpkg-gencontrol and dpkg-deb does not agree on the file
+ # extension.
+ if ($dh{ENABLE_DBGSYM} and not $keep_debug and not package_is_arch_all($package) and not is_udeb($package)) {
+ # Avoid creating a dbgsym that would clash with a registered
+ # package or looks like a manual -dbg package.
+ if (not $all_packages{"${package}-dbgsym"} and $package !~ m/-dbg(?:sym)?$/) {
+ $debugtmp = dbgsym_tmpdir($package);
+ $keep_debug = 1;
+ $use_build_id = 2;
+ }
+ }
+ %file_output=@shared_libs=@executables=@static_libs=();
+ find({
+ wanted => \&testfile,
+ no_chdir => 1,
+ }, $tmp);
+
+ foreach (@shared_libs) {
+ my $debug_path = make_debug($objcopy, $_, $tmp, $debugtmp, $use_build_id) if $keep_debug;
+ # Note that all calls to strip on shared libs
+ # *must* include the --strip-unneeded.
+ doit($strip, "--remove-section=.comment", "--remove-section=.note", "--strip-unneeded", $_);
+ attach_debug($objcopy, $_, $debug_path) if defined $debug_path;
+ }
+
+ foreach (@executables) {
+ my $debug_path = make_debug($objcopy, $_, $tmp, $debugtmp, $use_build_id) if $keep_debug;
+ doit($strip, "--remove-section=.comment", "--remove-section=.note", $_);
+ attach_debug($objcopy, $_, $debug_path) if defined $debug_path;
+ }
+
+ foreach (@static_libs) {
+ # NB: The short variant (-D) is broken in Jessie
+ # (binutils/2.25-3)
+ doit($strip, '--strip-debug', '--remove-section=.comment',
+ '--remove-section=.note', '--enable-deterministic-archives',
+ '-R', '.gnu.lto_*', '-R', '.gnu.debuglto_*',
+ '-N', '__gnu_lto_slim', '-N', '__gnu_lto_v1',
+ $_);
+ }
+ if (-d "$tmp/usr/lib/debug/.dwz" and ($use_build_id > 1 or ($dh{DEBUGPACKAGE} and $dh{DEBUGPACKAGE} ne $package))) {
+ my @files = glob_expand(["$tmp/usr/lib/debug/.dwz"], \&glob_expand_error_handler_reject, '*');
+ install_dir("$debugtmp/usr/lib/debug/.dwz");
+ xargs(\@files, 'cp', '--reflink=auto', "-a", XARGS_INSERT_PARAMS_HERE, "$debugtmp/usr/lib/debug/.dwz");
+ doit('rm', '-fr', "$tmp/usr/lib/debug/.dwz");
+ doit('rmdir', '-p', '--ignore-fail-on-non-empty', "$tmp/usr/lib/debug");
+ }
+
+ if ($no_auto_dbgsym and $use_build_id > 1) {
+ # When DEB_BUILD_OPTIONS contains noautodbgsym, remove the
+ # dbgsym dir and clear the build-ids.
+ #
+ # Note we have to extract the dbg symbols as usual, since
+ # attach_debug (objcopy --add-gnu-debuglink) requires the dbg
+ # file to exist.
+ doit('rm', '-fr', $debugtmp);
+ @build_ids = ();
+ }
+ if ($use_build_id > 1 and -d $debugtmp) {
+ my $dbgsym_docdir = "${debugtmp}/usr/share/doc";
+ my $doc_symlink = "${dbgsym_docdir}/${package}-dbgsym";
+ if ( not -l $doc_symlink and not -e _ ) {
+ install_dir($dbgsym_docdir);
+ make_symlink_raw_target($package, $doc_symlink);
+ }
+ if ($dh{MIGRATE_DBGSYM}) {
+ my $path = "debian/.debhelper/${package}/dbgsym-migration";
+ open(my $fd, '>', $path) or error("open $path failed: $!");
+ print {$fd} "$dh{MIGRATE_DBGSYM}\n";
+ close($fd) or error("close $path failed: $!");
+ }
+ }
+ if ($use_build_id > 1 and @build_ids) {
+ write_buildid_file($package, \@build_ids);
+ @build_ids = ();
+ }
+ }
+ if (@build_ids and $dh{DEBUGPACKAGE}) {
+ write_buildid_file($dh{DEBUGPACKAGE}, \@build_ids);
+ }
+}
+
+if ($dh{DEBUGPACKAGE}) {
+ # Non-deterministic issues with --dbg-package and parallelism (see
+ # #872007). Analysis and patches welcome for this case.
+ process_packages(@{$dh{DOPACKAGES}});
+} else {
+ on_pkgs_in_parallel(\&process_packages);
+}
+
+=head1 SEE ALSO
+
+L<debhelper(7)>
+
+This program is a part of debhelper.
+
+=head1 AUTHOR
+
+Joey Hess <joeyh@debian.org>
+
+=cut