Home | History | Annotate | Line # | Download | only in recipes
      1      1.1  christos #! /usr/bin/env perl
      2      1.1  christos # -*- mode: Perl -*-
      3  1.1.1.2  christos # Copyright 2016-2021 The OpenSSL Project Authors. All Rights Reserved.
      4      1.1  christos #
      5  1.1.1.3  christos # Licensed under the Apache License 2.0 (the "License").  You may not use
      6      1.1  christos # this file except in compliance with the License.  You can obtain a copy
      7      1.1  christos # in the file LICENSE in the source distribution or at
      8      1.1  christos # https://www.openssl.org/source/license.html
      9      1.1  christos 
     10      1.1  christos use strict;
     11      1.1  christos use File::Spec::Functions qw(devnull);
     12  1.1.1.3  christos use OpenSSL::Test qw(:DEFAULT srctop_file srctop_dir bldtop_dir bldtop_file);
     13      1.1  christos use OpenSSL::Test::Utils;
     14      1.1  christos 
     15  1.1.1.3  christos BEGIN {
     16  1.1.1.3  christos     setup("test_symbol_presence");
     17  1.1.1.3  christos }
     18      1.1  christos 
     19  1.1.1.3  christos use lib srctop_dir('Configurations');
     20  1.1.1.3  christos use lib bldtop_dir('.');
     21  1.1.1.3  christos use platform;
     22  1.1.1.3  christos 
     23  1.1.1.3  christos plan skip_all => "Test is disabled on NonStop" if config('target') =~ m|^nonstop|;
     24  1.1.1.3  christos # MacOS arranges symbol names differently
     25  1.1.1.3  christos plan skip_all => "Test is disabled on MacOS" if config('target') =~ m|^darwin|;
     26  1.1.1.3  christos plan skip_all => "This is unsupported on MSYS, MinGW or MSWin32"
     27  1.1.1.3  christos     if $^O eq 'msys' or $^O eq 'MSWin32' or config('target') =~ m|^mingw|;
     28      1.1  christos plan skip_all => "Only useful when building shared libraries"
     29      1.1  christos     if disabled("shared");
     30      1.1  christos 
     31      1.1  christos my @libnames = ("crypto", "ssl");
     32      1.1  christos my $testcount = scalar @libnames;
     33      1.1  christos 
     34      1.1  christos plan tests => $testcount * 2;
     35      1.1  christos 
     36      1.1  christos note
     37      1.1  christos     "NOTE: developer test!  It's possible that it won't run on your\n",
     38      1.1  christos     "platform, and that's perfectly fine.  This is mainly for developers\n",
     39      1.1  christos     "on Unix to check that our shared libraries are consistent with the\n",
     40      1.1  christos     "ordinals (util/*.num in the source tree), something that should be\n",
     41      1.1  christos     "good enough a check for the other platforms as well.\n";
     42      1.1  christos 
     43      1.1  christos foreach my $libname (@libnames) {
     44      1.1  christos  SKIP:
     45      1.1  christos     {
     46  1.1.1.3  christos         my $shlibname = platform->sharedlib("lib$libname");
     47  1.1.1.3  christos         my $shlibpath = bldtop_file($shlibname);
     48      1.1  christos         *OSTDERR = *STDERR;
     49      1.1  christos         *OSTDOUT = *STDOUT;
     50      1.1  christos         open STDERR, ">", devnull();
     51      1.1  christos         open STDOUT, ">", devnull();
     52  1.1.1.2  christos         my @nm_lines = map { s|\R$||; $_ } `nm -DPg $shlibpath 2> /dev/null`;
     53      1.1  christos         close STDERR;
     54      1.1  christos         close STDOUT;
     55      1.1  christos         *STDERR = *OSTDERR;
     56      1.1  christos         *STDOUT = *OSTDOUT;
     57  1.1.1.2  christos         skip "Can't run 'nm -DPg $shlibpath' => $?...  ignoring", 2
     58      1.1  christos             unless $? == 0;
     59      1.1  christos 
     60      1.1  christos         my $bldtop = bldtop_dir();
     61      1.1  christos         my @def_lines;
     62      1.1  christos         indir $bldtop => sub {
     63      1.1  christos             my $mkdefpath = srctop_file("util", "mkdef.pl");
     64  1.1.1.3  christos             my $libnumpath = srctop_file("util", "lib$libname.num");
     65  1.1.1.3  christos             @def_lines = map { s|\R$||; $_ } `$^X $mkdefpath --ordinals $libnumpath --name $libname --OS linux 2> /dev/null`;
     66  1.1.1.3  christos             ok($? == 0, "running 'cd $bldtop; $^X $mkdefpath --ordinals $libnumpath --name $libname --OS linux' => $?");
     67      1.1  christos         }, create => 0, cleanup => 0;
     68      1.1  christos 
     69      1.1  christos         note "Number of lines in \@nm_lines before massaging: ", scalar @nm_lines;
     70      1.1  christos         note "Number of lines in \@def_lines before massaging: ", scalar @def_lines;
     71      1.1  christos 
     72      1.1  christos         # Massage the nm output to only contain defined symbols
     73  1.1.1.4  christos         # Common symbols need separate treatment
     74  1.1.1.4  christos         my %commons;
     75  1.1.1.4  christos         foreach (@nm_lines) {
     76  1.1.1.4  christos             if (m|^(.*) C .*|) {
     77  1.1.1.4  christos                 $commons{$1}++;
     78  1.1.1.4  christos             }
     79  1.1.1.4  christos         }
     80  1.1.1.4  christos         foreach (sort keys %commons) {
     81  1.1.1.4  christos             note "Common symbol: $_";
     82  1.1.1.4  christos         }
     83  1.1.1.4  christos 
     84  1.1.1.2  christos         @nm_lines =
     85  1.1.1.2  christos             sort
     86  1.1.1.4  christos             ( map {
     87  1.1.1.4  christos                   # Drop the first space and everything following it
     88  1.1.1.4  christos                   s| .*||;
     89  1.1.1.4  christos                   # Drop OpenSSL dynamic version information if there is any
     90  1.1.1.4  christos                   s|\@\@.+$||;
     91  1.1.1.4  christos                   # Return the result
     92  1.1.1.4  christos                   $_
     93  1.1.1.4  christos               }
     94  1.1.1.4  christos               # Drop any symbol starting with a double underscore, they
     95  1.1.1.4  christos               # are reserved for the compiler / system ABI and are none
     96  1.1.1.4  christos               # of our business
     97  1.1.1.4  christos               grep !m|^__|,
     98  1.1.1.4  christos               # Only look at external definitions
     99  1.1.1.4  christos               grep m|.* [BDST] .*|,
    100  1.1.1.4  christos               @nm_lines ),
    101  1.1.1.4  christos             keys %commons;
    102      1.1  christos 
    103      1.1  christos         # Massage the mkdef.pl output to only contain global symbols
    104      1.1  christos         # The output we got is in Unix .map format, which has a global
    105      1.1  christos         # and a local section.  We're only interested in the global
    106      1.1  christos         # section.
    107      1.1  christos         my $in_global = 0;
    108      1.1  christos         @def_lines =
    109      1.1  christos             sort
    110      1.1  christos             map { s|;||; s|\s+||g; $_ }
    111      1.1  christos             grep { $in_global = 1 if m|global:|;
    112      1.1  christos                    $in_global = 0 if m|local:|;
    113      1.1  christos                    $in_global = 0 if m|\}|;
    114      1.1  christos                    $in_global && m|;|; } @def_lines;
    115      1.1  christos 
    116      1.1  christos         note "Number of lines in \@nm_lines after massaging: ", scalar @nm_lines;
    117      1.1  christos         note "Number of lines in \@def_lines after massaging: ", scalar @def_lines;
    118      1.1  christos 
    119      1.1  christos         # Maintain lists of symbols that are missing in the shared library,
    120      1.1  christos         # or that are extra.
    121      1.1  christos         my @missing = ();
    122      1.1  christos         my @extra = ();
    123      1.1  christos 
    124      1.1  christos         while (scalar @nm_lines || scalar @def_lines) {
    125      1.1  christos             my $nm_first = $nm_lines[0];
    126      1.1  christos             my $def_first = $def_lines[0];
    127      1.1  christos 
    128      1.1  christos             if (!defined($nm_first)) {
    129      1.1  christos                 push @missing, shift @def_lines;
    130      1.1  christos             } elsif (!defined($def_first)) {
    131      1.1  christos                 push @extra, shift @nm_lines;
    132      1.1  christos             } elsif ($nm_first gt $def_first) {
    133      1.1  christos                 push @missing, shift @def_lines;
    134      1.1  christos             } elsif ($nm_first lt $def_first) {
    135      1.1  christos                 push @extra, shift @nm_lines;
    136      1.1  christos             } else {
    137      1.1  christos                 shift @def_lines;
    138      1.1  christos                 shift @nm_lines;
    139      1.1  christos             }
    140      1.1  christos         }
    141      1.1  christos 
    142      1.1  christos         if (scalar @missing) {
    143  1.1.1.3  christos             note "The following symbols are missing in ${shlibname}:";
    144      1.1  christos             foreach (@missing) {
    145      1.1  christos                 note "  $_";
    146      1.1  christos             }
    147      1.1  christos         }
    148      1.1  christos         if (scalar @extra) {
    149  1.1.1.3  christos             note "The following symbols are extra in ${shlibname}:";
    150      1.1  christos             foreach (@extra) {
    151      1.1  christos                 note "  $_";
    152      1.1  christos             }
    153      1.1  christos         }
    154      1.1  christos         ok(scalar @missing == 0,
    155  1.1.1.3  christos            "check that there are no missing symbols in ${shlibname}");
    156      1.1  christos     }
    157      1.1  christos }
    158