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