summaryrefslogtreecommitdiffstats
path: root/lib/Lintian/Check/Libraries
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Lintian/Check/Libraries')
-rw-r--r--lib/Lintian/Check/Libraries/DebugSymbols.pm59
-rw-r--r--lib/Lintian/Check/Libraries/Embedded.pm124
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Exit.pm72
-rw-r--r--lib/Lintian/Check/Libraries/Shared/FilePermissions.pm72
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Links.pm167
-rw-r--r--lib/Lintian/Check/Libraries/Shared/MultiArch.pm79
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Obsolete.pm56
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Relocation.pm58
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Soname.pm123
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Soname/Missing.pm73
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Stack.pm69
-rw-r--r--lib/Lintian/Check/Libraries/Shared/Trigger/Ldconfig.pm131
-rw-r--r--lib/Lintian/Check/Libraries/Static.pm121
-rw-r--r--lib/Lintian/Check/Libraries/Static/LinkTimeOptimization.pm70
-rw-r--r--lib/Lintian/Check/Libraries/Static/Name.pm61
-rw-r--r--lib/Lintian/Check/Libraries/Static/NoCode.pm95
16 files changed, 1430 insertions, 0 deletions
diff --git a/lib/Lintian/Check/Libraries/DebugSymbols.pm b/lib/Lintian/Check/Libraries/DebugSymbols.pm
new file mode 100644
index 0000000..4f04e6f
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/DebugSymbols.pm
@@ -0,0 +1,59 @@
+# libraries/debug-symbols -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz and Richard Braakman
+# Copyright (C) 2012 Kees Cook
+# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::DebugSymbols;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ /^ [^,]* \b ELF \b /x;
+
+ # stripped but a debug or profiling library?
+ $self->pointed_hint('stripped-library', $item->pointer)
+ if $item->file_type !~ m{\bnot stripped\b}
+ && $item->name =~ m{^ (?:usr/)? lib/ (?: debug | profile ) / }x
+ && $item->size;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Embedded.pm b/lib/Lintian/Check/Libraries/Embedded.pm
new file mode 100644
index 0000000..502af47
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Embedded.pm
@@ -0,0 +1,124 @@
+# libraries/embedded -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz and Richard Braakman
+# Copyright (C) 2012 Kees Cook
+# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Embedded;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Const::Fast;
+use List::Compare;
+use Unicode::UTF8 qw(encode_utf8);
+
+const my $SPACE => q{ };
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+has EMBEDDED_LIBRARIES => (
+ is => 'rw',
+ lazy => 1,
+ default => sub {
+ my ($self) = @_;
+
+ my %embedded_libraries;
+
+ my $data
+ = $self->data->load('binaries/embedded-libs',qr{ \s*+ [|][|] }x);
+
+ for my $label ($data->all) {
+
+ my $details = $data->value($label);
+
+ my ($pairs, $pattern) = split(m{ [|][|] }x, $details, 2);
+
+ my %result;
+ for my $kvpair (split($SPACE, $pairs)) {
+
+ my ($key, $value) = split(/=/, $kvpair, 2);
+ $result{$key} = $value;
+ }
+
+ my $lc= List::Compare->new([keys %result],
+ [qw{libname source source-regex}]);
+ my @unknown = $lc->get_Lonly;
+
+ die encode_utf8(
+"Unknown options @unknown for $label (in binaries/embedded-libs)"
+ )if @unknown;
+
+ die encode_utf8(
+"Both source and source-regex used for $label (in binaries/embedded-libs)"
+ )if length $result{source} && length $result{'source-regex'};
+
+ $result{match} = qr/$pattern/;
+
+ $result{libname} //= $label;
+ $result{source} //= $label;
+
+ $embedded_libraries{$label} = \%result;
+ }
+
+ return \%embedded_libraries;
+ }
+);
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ /^ [^,]* \b ELF \b /x;
+
+ for my $embedded_name (keys %{$self->EMBEDDED_LIBRARIES}) {
+
+ my $library_data = $self->EMBEDDED_LIBRARIES->{$embedded_name};
+
+ next
+ if length $library_data->{'source-regex'}
+ && $self->processable->source_name=~ $library_data->{'source-regex'};
+
+ next
+ if length $library_data->{source}
+ && $self->processable->source_name eq $library_data->{source};
+
+ $self->pointed_hint('embedded-library', $item->pointer,
+ $library_data->{libname})
+ if $item->strings =~ $library_data->{match};
+ }
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Exit.pm b/lib/Lintian/Check/Libraries/Shared/Exit.pm
new file mode 100644
index 0000000..5788808
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Exit.pm
@@ -0,0 +1,72 @@
+# libraries/shared/exit -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Exit;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use List::SomeUtils qw(any none);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+# not presently used
+#my $UNKNOWN_SHARED_LIBRARY_EXCEPTIONS
+# = $self->data->load('shared-libs/unknown-shared-library-exceptions');
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # shared library
+ return
+ unless @{$item->elf->{SONAME} // [] };
+
+ my @symbols = grep { $_->section eq '.text' || $_->section eq 'UND' }
+ @{$item->elf->{SYMBOLS} // []};
+
+ my @symbol_names = map { $_->name } @symbols;
+
+ # If it has an INTERP section it might be an application with
+ # a SONAME (hi openjdk-6, see #614305). Also see the comment
+ # for "shared-library-is-executable" below.
+ $self->pointed_hint('exit-in-shared-library', $item->pointer)
+ if (any { m/^_?exit$/ } @symbol_names)
+ && (none { $_ eq 'fork' } @symbol_names)
+ && !length $item->elf->{INTERP};
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/FilePermissions.pm b/lib/Lintian/Check/Libraries/Shared/FilePermissions.pm
new file mode 100644
index 0000000..663205e
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/FilePermissions.pm
@@ -0,0 +1,72 @@
+# libraries/shared/file-permissions -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::FilePermissions;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Const::Fast;
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+const my $WIDELY_READABLE => oct(644);
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # shared library
+ return
+ unless @{$item->elf->{SONAME} // [] };
+
+ # Yes. But if the library has an INTERP section, it's
+ # designed to do something useful when executed, so don't
+ # report an error. Also give ld.so a pass, since it's
+ # special.
+ $self->pointed_hint('shared-library-is-executable',
+ $item->pointer, $item->octal_permissions)
+ if $item->is_executable
+ && !$item->elf->{INTERP}
+ && $item->name !~ m{^lib.*/ld-[\d.]+\.so$};
+
+ $self->pointed_hint('odd-permissions-on-shared-library',
+ $item->pointer, $item->octal_permissions)
+ if !$item->is_executable
+ && $item->operm != $WIDELY_READABLE;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Links.pm b/lib/Lintian/Check/Libraries/Shared/Links.pm
new file mode 100644
index 0000000..e25d3fd
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Links.pm
@@ -0,0 +1,167 @@
+# libraries/shared/links -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Links;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Const::Fast;
+use List::SomeUtils qw(none);
+
+const my $ARROW => q{->};
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+has development_packages => (
+ is => 'rw',
+ lazy => 1,
+ default => sub {
+ my ($self) = @_;
+
+ my @development_packages;
+
+ for my $installable ($self->group->get_installables) {
+
+ push(@development_packages, $installable)
+ if $installable->name =~ /-dev$/
+ && $installable->relation('strong')
+ ->satisfies($self->processable->name);
+ }
+
+ return \@development_packages;
+ }
+);
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # shared library
+ return
+ unless @{$item->elf->{SONAME} // [] };
+
+ my $soname = $item->elf->{SONAME}[0];
+
+ my @ldconfig_folders = @{$self->data->architectures->ldconfig_folders};
+ return
+ if none { $item->dirname eq $_ } @ldconfig_folders;
+
+ my $installed = $self->processable->installed;
+
+ my $versioned_name = $item->dirname . $soname;
+ my $versioned_item = $installed->lookup($versioned_name);
+
+ my $unversioned_name = $versioned_name;
+ # libtool "-release" variant
+ $unversioned_name =~ s/-[\d\.]+\.so$/.so/;
+ # determine shlib link name (w/o version)
+ $unversioned_name =~ s/\.so.+$/.so/;
+
+ $self->pointed_hint('lacks-versioned-link-to-shared-library',
+ $item->pointer, $versioned_name)
+ unless defined $versioned_item;
+
+ $self->pointed_hint(
+ 'ldconfig-symlink-referencing-wrong-file',
+ $versioned_item->pointer,'should point to',
+ $versioned_item->link,'instead of',$item->basename
+ )
+ if $versioned_name ne $item->name
+ && defined $versioned_item
+ && $versioned_item->is_symlink
+ && $versioned_item->link ne $item->basename;
+
+ $self->pointed_hint(
+ 'ldconfig-symlink-is-not-a-symlink',
+ $versioned_item->pointer,'should point to',
+ $item->name
+ )
+ if $versioned_name ne $item->name
+ && defined $versioned_item
+ && !$versioned_item->is_symlink;
+
+ # shlib symlink may not exist.
+ # if shlib doesn't _have_ a version, then $unversioned_name and
+ # $item->name will be equal, and it's not a development link,
+ # so don't complain.
+ $self->pointed_hint(
+ 'link-to-shared-library-in-wrong-package',
+ $installed->lookup($unversioned_name)->pointer,
+ $item->name
+ )
+ if $unversioned_name ne $item->name
+ && defined $installed->lookup($unversioned_name);
+
+ # If the shared library is in /lib, we have to look for
+ # the dev symlink in /usr/lib
+ $unversioned_name = "usr/$unversioned_name"
+ unless $item->name =~ m{^usr/};
+
+ my @dev_links;
+ for my $dev_installable (@{$self->development_packages}) {
+ for my $dev_item (@{$dev_installable->installed->sorted_list}) {
+
+ next
+ unless $dev_item->is_symlink;
+
+ next
+ unless $dev_item->name =~ m{^ usr/lib/ }x;
+
+ # try absolute first
+ my $resolved = $installed->resolve_path($dev_item->link);
+
+ # otherwise relative
+ $resolved
+ = $installed->resolve_path($dev_item->dirname . $dev_item->link)
+ unless defined $resolved;
+
+ next
+ unless defined $resolved;
+
+ push(@dev_links, $dev_item)
+ if $resolved->name eq $item->name;
+ }
+ }
+
+ # found -dev package; library needs a symlink
+ $self->pointed_hint('lacks-unversioned-link-to-shared-library',
+ $item->pointer, "example: $unversioned_name")
+ if @{$self->development_packages}
+ && (none { $_->name =~ m{ [.]so $}x } @dev_links);
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/MultiArch.pm b/lib/Lintian/Check/Libraries/Shared/MultiArch.pm
new file mode 100644
index 0000000..52c1bc5
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/MultiArch.pm
@@ -0,0 +1,79 @@
+# libraries/shared/multi-arch -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::MultiArch;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use List::SomeUtils qw(none uniq);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+has shared_libraries => (is => 'rw', default => sub { [] });
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ m{^ [^,]* \b ELF \b }x;
+
+ return
+ unless $item->file_type
+ =~ m{(?: shared [ ] object | pie [ ] executable )}x;
+
+ my @ldconfig_folders = @{$self->data->architectures->ldconfig_folders};
+ return
+ if none { $item->dirname eq $_ } @ldconfig_folders;
+
+ push(@{$self->shared_libraries}, $item->name);
+
+ return;
+}
+
+sub installable {
+ my ($self) = @_;
+
+ $self->hint(
+ 'shared-library-is-multi-arch-foreign',
+ (sort +uniq @{$self->shared_libraries})
+ )
+ if @{$self->shared_libraries}
+ && $self->processable->fields->value('Multi-Arch') eq 'foreign';
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Obsolete.pm b/lib/Lintian/Check/Libraries/Shared/Obsolete.pm
new file mode 100644
index 0000000..699b70c
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Obsolete.pm
@@ -0,0 +1,56 @@
+# libraries/shared/obsolete -- lintian check script -*- perl -*-
+
+# Copyright (C) 2020 Mo Zhou
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Obsolete;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ /^[^,]*\bELF\b/;
+
+ my @needed = @{$item->elf->{NEEDED} // []};
+ my @obsolete = grep { /^libcblas\.so\.\d/ } @needed;
+
+ $self->pointed_hint('linked-with-obsolete-library', $item->pointer, $_)
+ for @obsolete;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Relocation.pm b/lib/Lintian/Check/Libraries/Shared/Relocation.pm
new file mode 100644
index 0000000..8c3dac9
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Relocation.pm
@@ -0,0 +1,58 @@
+# libraries/shared/relocation -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Relocation;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # shared library
+ return
+ unless @{$item->elf->{SONAME} // [] };
+
+ # Now that we're sure this is really a shared library, report on
+ # non-PIC problems.
+ $self->pointed_hint('specific-address-in-shared-library', $item->pointer)
+ if $item->elf->{TEXTREL};
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Soname.pm b/lib/Lintian/Check/Libraries/Shared/Soname.pm
new file mode 100644
index 0000000..9887e3b
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Soname.pm
@@ -0,0 +1,123 @@
+# libraries/shared/soname -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz and Richard Braakman
+# Copyright (C) 2012 Kees Cook
+# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Soname;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Const::Fast;
+use List::SomeUtils qw(any none uniq);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+const my $SPACE => q{ };
+const my $SLASH => q{/};
+
+has DEB_HOST_MULTIARCH => (
+ is => 'rw',
+ lazy => 1,
+ default => sub {
+ my ($self) = @_;
+
+ return $self->data->architectures->deb_host_multiarch;
+ }
+);
+
+sub installable {
+ my ($self) = @_;
+
+ return
+ if $self->processable->type eq 'udeb';
+
+ my $architecture = $self->processable->fields->value('Architecture');
+ my $multiarch_component = $self->DEB_HOST_MULTIARCH->{$architecture};
+
+ my @common_folders = qw{lib usr/lib};
+ push(@common_folders, map { "$_/$multiarch_component" } @common_folders)
+ if length $multiarch_component;
+
+ my @duplicated;
+ for my $item (@{$self->processable->installed->sorted_list}) {
+
+ # For the package naming check, filter out SONAMEs where all the
+ # files are at paths other than /lib, /usr/lib and /usr/lib/<MA-DIR>.
+ # This avoids false positives with plugins like Apache modules,
+ # which may have their own SONAMEs but which don't matter for the
+ # purposes of this check.
+ next
+ if none { $item->dirname eq $_ . $SLASH } @common_folders;
+
+ # Also filter out nsswitch modules
+ next
+ if $item->basename =~ m{^ libnss_[^.]+\.so(?:\.\d+) $}x;
+
+ push(@duplicated, @{$item->elf->{SONAME} // []});
+ }
+
+ my @sonames = uniq @duplicated;
+
+ # try to strip transition strings
+ my $shortened_name = $self->processable->name;
+ $shortened_name =~ s/c102\b//;
+ $shortened_name =~ s/c2a?\b//;
+ $shortened_name =~ s/\dg$//;
+ $shortened_name =~ s/gf$//;
+ $shortened_name =~ s/v[5-6]$//; # GCC-5 / libstdc++6 C11 ABI breakage
+ $shortened_name =~ s/-udeb$//;
+ $shortened_name =~ s/^lib64/lib/;
+
+ my $match_found = 0;
+ for my $soname (@sonames) {
+
+ $soname =~ s/ ([0-9]) [.]so[.] /$1-/x;
+ $soname =~ s/ [.]so (?:[.]|\z) //x;
+ $soname =~ s/_/-/g;
+
+ my $lowercase = lc $soname;
+
+ $match_found = any { $lowercase eq $_ }
+ ($self->processable->name, $shortened_name);
+
+ last
+ if $match_found;
+ }
+
+ $self->hint('package-name-doesnt-match-sonames',
+ join($SPACE, sort @sonames))
+ if @sonames && !$match_found;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Soname/Missing.pm b/lib/Lintian/Check/Libraries/Shared/Soname/Missing.pm
new file mode 100644
index 0000000..a01a878
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Soname/Missing.pm
@@ -0,0 +1,73 @@
+# libraries/shared/soname/missing -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Soname::Missing;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use List::SomeUtils qw(none);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ m{^ [^,]* \b ELF \b }x;
+
+ return
+ unless $item->file_type
+ =~ m{(?: shared [ ] object | pie [ ] executable )}x;
+
+ # does not have SONAME
+ return
+ if @{$item->elf->{SONAME} // [] };
+
+ my @ldconfig_folders = @{$self->data->architectures->ldconfig_folders};
+ return
+ if none { $item->dirname eq $_ } @ldconfig_folders;
+
+ # disregard executables
+ $self->pointed_hint('sharedobject-in-library-directory-missing-soname',
+ $item->pointer)
+ if !$item->is_executable
+ || !defined $item->elf->{DEBUG}
+ || $item->name =~ / [.]so (?: [.] | $ ) /msx;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Stack.pm b/lib/Lintian/Check/Libraries/Shared/Stack.pm
new file mode 100644
index 0000000..f3e1d03
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Stack.pm
@@ -0,0 +1,69 @@
+# libraries/shared/stack -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Stack;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # shared library
+ return
+ unless @{$item->elf->{SONAME} // [] };
+
+ $self->pointed_hint('shared-library-lacks-stack-section',$item->pointer)
+ if $self->processable->fields->declares('Architecture')
+ && !exists $item->elf->{PH}{STACK};
+
+ $self->pointed_hint('executable-stack-in-shared-library', $item->pointer)
+ if exists $item->elf->{PH}{STACK}
+ && $item->elf->{PH}{STACK}{flags} ne 'rw-'
+ # Once the following line is removed again, please also remove
+ # the Test-Architectures line in
+ # t/recipes/checks/libraries/shared/stack/shared-libs-exec-stack/eval/desc
+ # and the MIPS-related notes in
+ # tags/e/executable-stack-in-shared-library.tag. See
+ # https://bugs.debian.org/1025436 and
+ # https://bugs.debian.org/1022787 for details
+ && $self->processable->fields->value('Architecture') !~ /mips/;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Shared/Trigger/Ldconfig.pm b/lib/Lintian/Check/Libraries/Shared/Trigger/Ldconfig.pm
new file mode 100644
index 0000000..66f5961
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Shared/Trigger/Ldconfig.pm
@@ -0,0 +1,131 @@
+# libraries/shared/trigger/ldconfig -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz
+# Copyright (C) 2018-2019 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Shared::Trigger::Ldconfig;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use List::SomeUtils qw(any uniq);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+has soname_by_filename => (
+ is => 'rw',
+ lazy => 1,
+ default => sub {
+ my ($self) = @_;
+
+ my %soname_by_filename;
+ for my $item (@{$self->processable->installed->sorted_list}) {
+
+ $soname_by_filename{$item->name}= $item->elf->{SONAME}[0]
+ if exists $item->elf->{SONAME};
+ }
+
+ return \%soname_by_filename;
+ }
+);
+
+has must_call_ldconfig => (is => 'rw', default => sub { [] });
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ my $resolved_name = $item->name;
+ $resolved_name = $item->link_normalized
+ if length $item->link;
+
+ # Installed in a directory controlled by the dynamic
+ # linker? We have to strip off directories named for
+ # hardware capabilities.
+ # yes! so postinst must call ldconfig
+ push(@{$self->must_call_ldconfig}, $resolved_name)
+ if exists $self->soname_by_filename->{$resolved_name}
+ && $self->needs_ldconfig($item);
+
+ return;
+}
+
+sub installable {
+ my ($self) = @_;
+
+ # determine if the package had an ldconfig trigger
+ my $triggers = $self->processable->control->resolve_path('triggers');
+
+ my $we_trigger_ldconfig = 0;
+ $we_trigger_ldconfig = 1
+ if defined $triggers
+ && $triggers->decoded_utf8
+ =~ /^ \s* activate-noawait \s+ ldconfig \s* $/mx;
+
+ $self->hint('package-has-unnecessary-activation-of-ldconfig-trigger')
+ if !@{$self->must_call_ldconfig}
+ && $we_trigger_ldconfig
+ && $self->processable->type ne 'udeb';
+
+ $self->hint('lacks-ldconfig-trigger',
+ (sort +uniq @{$self->must_call_ldconfig}))
+ if @{$self->must_call_ldconfig}
+ && !$we_trigger_ldconfig
+ && $self->processable->type ne 'udeb';
+
+ return;
+}
+
+sub needs_ldconfig {
+ my ($self, $item) = @_;
+
+ # Libraries that should only be used in the presence of certain capabilities
+ # may be located in subdirectories of the standard ldconfig search path with
+ # one of the following names.
+ my $HWCAP_DIRS = $self->data->load('shared-libs/hwcap-dirs');
+ my @ldconfig_folders = @{$self->data->architectures->ldconfig_folders};
+
+ my $dirname = $item->dirname;
+ my $encapsulator;
+ do {
+ $dirname =~ s{ ([^/]+) / $}{}x;
+ $encapsulator = $1;
+
+ } while ($encapsulator && $HWCAP_DIRS->recognizes($encapsulator));
+
+ $dirname .= "$encapsulator/" if $encapsulator;
+
+ # yes! so postinst must call ldconfig
+ return 1
+ if any { $dirname eq $_ } @ldconfig_folders;
+
+ return 0;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Static.pm b/lib/Lintian/Check/Libraries/Static.pm
new file mode 100644
index 0000000..72c8b97
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Static.pm
@@ -0,0 +1,121 @@
+# libraries/static -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz and Richard Braakman
+# Copyright (C) 2012 Kees Cook
+# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Static;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Const::Fast;
+use List::Compare;
+use List::SomeUtils qw(any none uniq);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+const my $SPACE => q{ };
+const my $LEFT_PARENTHESIS => q{(};
+const my $RIGHT_PARENTHESIS => q{)};
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ m{ \b current [ ] ar [ ] archive \b }x;
+
+ my @unstripped_members;
+ my %stripped_sections_by_member;
+
+ for my $member_name (keys %{$item->elf_by_member}) {
+
+ my $member_elf = $item->elf_by_member->{$member_name};
+
+ my @elf_sections = values %{$member_elf->{'SECTION-HEADERS'}};
+ my @have_section_names = map { $_->name } @elf_sections;
+
+ # These are the ones file(1) looks for. The ".zdebug_info" being the
+ # compressed version of .debug_info.
+ # - Technically, file(1) also looks for .symtab, but that is apparently
+ # not strippable for static libs. Accordingly, it is omitted below.
+ my @KNOWN_DEBUG_SECTION_NAMES = qw{.debug_info .zdebug_info};
+ my $lc_debug = List::Compare->new(\@have_section_names,
+ \@KNOWN_DEBUG_SECTION_NAMES);
+
+ my @have_debug_sections = $lc_debug->get_intersection;
+
+ if (@have_debug_sections) {
+
+ push(@unstripped_members, $member_name);
+ next;
+ }
+
+ my @KNOWN_STRIPPED_SECTION_NAMES = qw{.note .comment};
+ my $lc_stripped = List::Compare->new(\@have_section_names,
+ \@KNOWN_STRIPPED_SECTION_NAMES);
+
+ my @have_stripped_sections = $lc_stripped->get_intersection;
+
+ $stripped_sections_by_member{$member_name} //= [];
+ push(
+ @{$stripped_sections_by_member{$member_name}},
+ @have_stripped_sections
+ );
+ }
+
+ $self->pointed_hint('unstripped-static-library', $item->pointer,
+ $LEFT_PARENTHESIS
+ . join($SPACE, sort +uniq @unstripped_members)
+ . $RIGHT_PARENTHESIS)
+ if @unstripped_members
+ && $item->name !~ m{ _g [.]a $}x;
+
+ # "libfoo_g.a" is usually a "debug" library, so ignore
+ # unneeded sections in those.
+ for my $member (keys %stripped_sections_by_member) {
+
+ $self->pointed_hint(
+ 'static-library-has-unneeded-sections',
+ $item->pointer,
+ "($member)",
+ join($SPACE, sort +uniq @{$stripped_sections_by_member{$member}})
+ )
+ if @{$stripped_sections_by_member{$member}}
+ && $item->name !~ m{ _g [.]a $}x;
+ }
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Static/LinkTimeOptimization.pm b/lib/Lintian/Check/Libraries/Static/LinkTimeOptimization.pm
new file mode 100644
index 0000000..04e65e8
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Static/LinkTimeOptimization.pm
@@ -0,0 +1,70 @@
+# libraries/static/link-time-optimization -- lintian check script -*- perl -*-
+
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Static::LinkTimeOptimization;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use List::SomeUtils qw(uniq);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # not sure if that captures everything GHC, or too much
+ return
+ if $item->name =~ m{^ usr/lib/ghc/ }x;
+
+ return
+ unless $item->file_type =~ m{ \b current [ ] ar [ ] archive \b }x;
+
+ for my $member_name (keys %{$item->elf_by_member}) {
+
+ my $member_elf = $item->elf_by_member->{$member_name};
+
+ my @elf_sections = values %{$member_elf->{'SECTION-HEADERS'}};
+ my @section_names = map { $_->name } @elf_sections;
+
+ my @lto_section_names = grep { m{^ [.]gnu[.]lto }x } @section_names;
+
+ $self->pointed_hint('static-link-time-optimization',
+ $item->pointer, $member_name)
+ if @lto_section_names;
+ }
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Static/Name.pm b/lib/Lintian/Check/Libraries/Static/Name.pm
new file mode 100644
index 0000000..a4c47d1
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Static/Name.pm
@@ -0,0 +1,61 @@
+# libraries/static/name -- lintian check script -*- perl -*-
+
+# Copyright (C) 1998 Christian Schwarz and Richard Braakman
+# Copyright (C) 2012 Kees Cook
+# Copyright (C) 2017-2020 Chris Lamb <lamby@debian.org>
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Static::Name;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ return
+ unless $item->file_type =~ m{ \b current [ ] ar [ ] archive \b }x;
+
+ my $shortened = $item->name;
+
+ if ($shortened =~ s{ _s[.]a $}{.a}x) {
+
+ $self->pointed_hint('odd-static-library-name', $item->pointer)
+ unless defined $self->processable->installed->lookup($shortened);
+ }
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et
diff --git a/lib/Lintian/Check/Libraries/Static/NoCode.pm b/lib/Lintian/Check/Libraries/Static/NoCode.pm
new file mode 100644
index 0000000..0d2415a
--- /dev/null
+++ b/lib/Lintian/Check/Libraries/Static/NoCode.pm
@@ -0,0 +1,95 @@
+# libraries/static/no-code -- lintian check script -*- perl -*-
+
+# Copyright (C) 2021 Felix Lechner
+#
+# 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 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, you can find it on the World Wide
+# Web at https://www.gnu.org/copyleft/gpl.html, or write to the Free
+# Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
+# MA 02110-1301, USA.
+
+package Lintian::Check::Libraries::Static::NoCode;
+
+use v5.20;
+use warnings;
+use utf8;
+
+use Const::Fast;
+use List::SomeUtils qw(any uniq);
+use Unicode::UTF8 qw(encode_utf8);
+
+use Moo;
+use namespace::clean;
+
+with 'Lintian::Check';
+
+const my $SPACE => q{ };
+
+sub visit_installed_files {
+ my ($self, $item) = @_;
+
+ return
+ unless $item->is_file;
+
+ # not sure if that captures everything GHC, or too much
+ return
+ if $item->name =~ m{^ usr/lib/ghc/ }x;
+
+ return
+ unless $item->file_type =~ m{ \b current [ ] ar [ ] archive \b }x;
+
+ my @codeful_members;
+ for my $member_name (keys %{$item->elf_by_member}) {
+
+ my $member_elf = $item->elf_by_member->{$member_name};
+
+ my @elf_sections = values %{$member_elf->{'SECTION-HEADERS'}};
+ my @sections_with_size = grep { $_->size > 0 } @elf_sections;
+
+ my @names_with_size = map { $_->name } @sections_with_size;
+
+ my @KNOWN_ARRAY_SECTIONS = qw{.preinit_array .init_array .fini_array};
+ my $lc_array
+ = List::Compare->new(\@names_with_size, \@KNOWN_ARRAY_SECTIONS);
+
+ my @have_array_sections = $lc_array->get_intersection;
+
+# adapted from https://github.com/rpm-software-management/rpmlint/blob/main/rpmlint/checks/BinariesCheck.py#L242-L249
+ my $has_code = 0;
+
+ $has_code = 1
+ if any { m{^ [.]text }x } @names_with_size;
+
+ $has_code = 1
+ if any { m{^ [.]data }x } @names_with_size;
+
+ $has_code = 1
+ if @have_array_sections;
+
+ push(@codeful_members, $member_name)
+ if $has_code;
+ }
+
+ $self->pointed_hint('no-code-sections', $item->pointer)
+ unless @codeful_members;
+
+ return;
+}
+
+1;
+
+# Local Variables:
+# indent-tabs-mode: nil
+# cperl-indent-level: 4
+# End:
+# vim: syntax=perl sw=4 sts=4 sr et