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