xref: /freebsd/crypto/openssl/util/mknum.pl (revision e0c4386e7e71d93b0edc0c8fa156263fc4a8b0b6)
1
2#! /usr/bin/env perl
3# Copyright 2018-2021 The OpenSSL Project Authors. All Rights Reserved.
4#
5# Licensed under the Apache License 2.0 (the "License").  You may not use
6# this file except in compliance with the License.  You can obtain a copy
7# in the file LICENSE in the source distribution or at
8# https://www.openssl.org/source/license.html
9
10use strict;
11use warnings;
12
13use Getopt::Long;
14use FindBin;
15use lib "$FindBin::Bin/perl";
16
17use OpenSSL::Ordinals;
18use OpenSSL::ParseC;
19
20my $ordinals_file = undef;      # the ordinals file to use
21my $symhacks_file = undef;      # a symbol hacking file (optional)
22my $version = undef;            # the version to use for added symbols
23my $checkexist = 0;             # (unsure yet)
24my $warnings = 1;
25my $renumber = 0;
26my $verbose = 0;
27my $debug = 0;
28
29GetOptions('ordinals=s' => \$ordinals_file,
30           'symhacks=s' => \$symhacks_file,
31           'version=s'  => \$version,
32           'exist'      => \$checkexist,
33           'renumber'   => \$renumber,
34           'warnings!'  => \$warnings,
35           'verbose'    => \$verbose,
36           'debug'      => \$debug)
37    or die "Error in command line arguments\n";
38
39die "Please supply ordinals file\n"
40    unless $ordinals_file;
41
42my $ordinals = OpenSSL::Ordinals->new(from => $ordinals_file,
43                                      warnings => $warnings,
44                                      verbose => $verbose,
45                                      debug => $debug);
46$ordinals->set_version($version);
47
48my %orig_names = ();
49%orig_names = map { $_->name() => 1 }
50    $ordinals->items(comparator => sub { $_[0] cmp $_[1] },
51                     filter => sub { $_->exists() })
52    if $checkexist;
53
54# Invalidate all entries, they get revalidated when we re-check below
55$ordinals->invalidate();
56
57foreach my $f (($symhacks_file // (), @ARGV)) {
58    print STDERR $f," ","-" x (69 - length($f)),"\n" if $verbose;
59    open IN, $f or die "Couldn't open $f: $!\n";
60    foreach (parse(<IN>, { filename => $f,
61                           warnings => $warnings,
62                           verbose => $verbose,
63                           debug => $debug })) {
64        $_->{value} = $_->{value}||"";
65        next if grep { $_ eq 'CONST_STRICT' } @{$_->{conds}};
66        printf STDERR "%s> %s%s : %s\n",
67            $_->{type},
68            $_->{name},
69            ($_->{type} eq 'M' && defined $symhacks_file && $f eq $symhacks_file
70             ? ' = ' . $_->{value}
71             : ''),
72            join(', ', @{$_->{conds}})
73            if $verbose;
74        if ($_->{type} eq 'M'
75                && defined $symhacks_file
76                && $f eq $symhacks_file
77                && $_->{value} =~ /^\w(?:\w|\d)*/) {
78            $ordinals->add_alias($f, $_->{value}, $_->{name}, @{$_->{conds}});
79        } else {
80            next if $_->{returntype} =~ /\b(?:ossl_)inline/;
81            my $type = {
82                F => 'FUNCTION',
83                V => 'VARIABLE',
84            } -> {$_->{type}};
85            if ($type) {
86                $ordinals->add($f, $_->{name}, $type, @{$_->{conds}});
87            }
88        }
89    }
90    close IN;
91}
92
93$ordinals->renumber() if $renumber;
94
95if ($checkexist) {
96    my %new_names = map { $_->name() => 1 }
97        $ordinals->items(comparator => sub { $_[0] cmp $_[1] },
98                         filter => sub { $_->exists() });
99    # Eliminate common names
100    foreach (keys %orig_names) {
101        next unless exists $new_names{$_};
102        delete $orig_names{$_};
103        delete $new_names{$_};
104    }
105    if (%orig_names) {
106        print "The following symbols do not seem to exist in code:\n";
107        foreach (sort keys %orig_names) {
108            print "\t$_\n";
109        }
110    }
111    if (%new_names) {
112        print "The following existing symbols are not in ordinals file:\n";
113        foreach (sort keys %new_names) {
114            print "\t$_\n";
115        }
116    }
117} else {
118    my $dropped = 0;
119    my $unassigned;
120    my $filter = sub {
121        my $item = shift;
122        my $result = $item->number() ne '?' || $item->exists();
123        $dropped++ unless $result;
124        return $result;
125    };
126    $ordinals->rewrite(filter => $filter);
127    my %stats = $ordinals->stats();
128    print STDERR
129        "${ordinals_file}: $stats{modified} old symbols have updated info\n"
130        if $stats{modified};
131    if ($stats{new}) {
132        print STDERR "${ordinals_file}: Added $stats{new} new symbols\n";
133    } else {
134        print STDERR "${ordinals_file}: No new symbols added\n";
135    }
136    if ($dropped) {
137        print STDERR "${ordinals_file}: Dropped $dropped new symbols\n";
138    }
139    $stats{unassigned} = 0 unless defined $stats{unassigned};
140    $unassigned = $stats{unassigned} - $dropped;
141    if ($unassigned) {
142        my $symbol = $unassigned == 1 ? "symbol" : "symbols";
143        my $is = $unassigned == 1 ? "is" : "are";
144        print STDERR "${ordinals_file}: $unassigned $symbol $is without ordinal number\n";
145    }
146}
147