X-Git-Url: https://git.openssl.org/?p=openssl.git;a=blobdiff_plain;f=util%2Fmkerr.pl;h=52a44c9ffb29ac7f32128a295853151c031cff27;hp=7d0797859fc997b12ed4ace583f2fd38e8b42d8b;hb=f0bbf36599e0dd41e20ee653a7323babc5a4deab;hpb=291a4d91eb9896645475758dee5032351a3f773e diff --git a/util/mkerr.pl b/util/mkerr.pl old mode 100644 new mode 100755 index 7d0797859f..52a44c9ffb --- a/util/mkerr.pl +++ b/util/mkerr.pl @@ -1,590 +1,546 @@ #! /usr/bin/env perl -# Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved. +# Copyright 1999-2018 The OpenSSL Project Authors. All Rights Reserved. # # Licensed under the OpenSSL license (the "License"). You may not use # this file except in compliance with the License. You can obtain a copy # in the file LICENSE in the source distribution or at # https://www.openssl.org/source/license.html -my $config = "crypto/err/openssl.ec"; -my $debug = 0; -my $unref = 0; -my $rebuild = 0; -my $static = 1; -my $recurse = 0; -my $reindex = 0; -my $dowrite = 0; -my $staticloader = ""; -my @t = localtime(); -my $YEAR = @t[5] + 1900; - -my $pack_errcode; -my $load_errcode; - -my $errcount; -my $year = (localtime)[5] + 1900; - -while (@ARGV) { - my $arg = $ARGV[0]; - if($arg eq "-conf") { - shift @ARGV; - $config = shift @ARGV; - } elsif($arg eq "-hprefix") { - shift @ARGV; - $hprefix = shift @ARGV; - } elsif($arg eq "-debug") { - $debug = 1; - $unref = 1; - shift @ARGV; - } elsif($arg eq "-rebuild") { - $rebuild = 1; - shift @ARGV; - } elsif($arg eq "-recurse") { - $recurse = 1; - shift @ARGV; - } elsif($arg eq "-reindex") { - $reindex = 1; - shift @ARGV; - } elsif($arg eq "-nostatic") { - $static = 0; - shift @ARGV; - } elsif($arg eq "-staticloader") { - $staticloader = "static "; - shift @ARGV; - } elsif($arg eq "-unref") { - $unref = 1; - shift @ARGV; - } elsif($arg eq "-write") { - $dowrite = 1; - shift @ARGV; - } elsif($arg eq "-help" || $arg eq "-h" || $arg eq "-?" || $arg eq "--help") { - print STDERR <<"EOF"; -mkerr.pl [options] ... +use strict; +use warnings; + +my $config = "crypto/err/openssl.ec"; +my $debug = 0; +my $internal = 0; +my $nowrite = 0; +my $rebuild = 0; +my $reindex = 0; +my $static = 0; +my $unref = 0; +my %modules = (); + +my $errors = 0; +my @t = localtime(); +my $YEAR = $t[5] + 1900; + +sub phase +{ + my $text = uc(shift); + print STDERR "\n---\n$text\n" if $debug; +} + +sub help +{ + print STDERR <<"EOF"; +mkerr.pl [options] [files...] Options: - -conf F Use the config file F instead of the default one: - crypto/err/openssl.ec - - -hprefix P Prepend the filenames in generated #include
- statements with prefix P. Default: 'openssl/' (without - the quotes, naturally) - NOTE: not used any more because our include directory - structure has changed. - - -debug Turn on debugging verbose output on stderr. - - -rebuild Rebuild all header and C source files, irrespective of the - fact if any error or function codes have been added/removed. - Default: only update files for libraries which saw change - (of course, this requires '-write' as well, or no - files will be touched!) - - -recurse scan a preconfigured set of directories / files for error and - function codes: - (, , , ) - When this option is NOT specified, the filelist is taken from - the commandline instead. Here, wildcards may be embedded. (Be - sure to escape those to prevent the shell from expanding them - for you when you wish mkerr.pl to do so instead.) - Default: take file list to scan from the command line. - - -reindex Discard the numeric values previously assigned to the error - and function codes as extracted from the scanned header files; - instead renumber all of them starting from 100. (Note that - the numbers assigned through 'R' records in the config file - remain intact.) - Default: keep previously assigned numbers. (You are warned - when collisions are detected.) - - -nostatic Generates a different source code, where these additional - functions are generated for each library specified in the - config file: - void ERR_load__strings(void); - void ERR_unload__strings(void); - void ERR__error(int f, int r, char *fn, int ln); - #define err(f,r) ERR__error(f,r,OPENSSL_FILE,OPENSSL_LINE) - while the code facilitates the use of these in an environment - where the error support routines are dynamically loaded at - runtime. - Default: 'static' code generation. - - -staticloader Prefix generated functions with the 'static' scope modifier. - Default: don't write any scope modifier prefix. - - -unref Print out unreferenced function and reason codes. - - -write Actually (over)write the generated code to the header and C - source files as assigned to each library through the config - file. - Default: don't write. - - -help / -h / -? / --help Show this help text. - - ... Additional arguments are added to the file list to scan, - assuming '-recurse' was NOT specified on the command line. + -conf FILE Use the named config file FILE instead of the default. + + -debug Verbose output debugging on stderr. + + -internal Generate code that is to be built as part of OpenSSL itself. + Also scans internal list of files. + + -module M Only useful with -internal! + Only write files for library module M. Whether files are + actually written or not depends on other options, such as + -rebuild. + Note: this option is cumulative. If not given at all, all + internal modules will be considered. + + -nowrite Do not write the header/source files, even if changed. + + -rebuild Rebuild all header and C source files, even if there + were no changes. + + -reindex Ignore previously assigned values (except for R records in + the config file) and renumber everything starting at 100. + + -static Make the load/unload functions static. + + -unref List all unreferenced function and reason codes on stderr; + implies -nowrite. + + -help Show this help text. + + ... Additional arguments are added to the file list to scan, + if '-internal' was NOT specified on the command line. EOF - exit 1; - } else { - last; - } } -if($recurse) { - @source = ( , , , ) -} else { - @source = @ARGV; +while ( @ARGV ) { + my $arg = $ARGV[0]; + last unless $arg =~ /-.*/; + $arg = $1 if $arg =~ /-(-.*)/; + if ( $arg eq "-conf" ) { + $config = $ARGV[1]; + shift @ARGV; + } elsif ( $arg eq "-debug" ) { + $debug = 1; + $unref = 1; + } elsif ( $arg eq "-internal" ) { + $internal = 1; + } elsif ( $arg eq "-nowrite" ) { + $nowrite = 1; + } elsif ( $arg eq "-rebuild" ) { + $rebuild = 1; + } elsif ( $arg eq "-reindex" ) { + $reindex = 1; + } elsif ( $arg eq "-static" ) { + $static = 1; + } elsif ( $arg eq "-unref" ) { + $unref = 1; + $nowrite = 1; + } elsif ( $arg eq "-module" ) { + shift @ARGV; + $modules{uc $ARGV[0]} = 1; + } elsif ( $arg =~ /-*h(elp)?/ ) { + &help(); + exit; + } elsif ( $arg =~ /-.*/ ) { + die "Unknown option $arg; use -h for help.\n"; + } + shift @ARGV; } -# Read in the config file - -open(IN, "<$config") || die "Can't open config file $config"; +my @source; +if ( $internal ) { + die "Cannot mix -internal and -static\n" if $static; + die "Extra parameters given.\n" if @ARGV; + @source = ( glob('crypto/*.c'), glob('crypto/*/*.c'), + glob('ssl/*.c'), glob('ssl/*/*.c') ); +} else { + die "-module isn't useful without -internal\n" if scalar keys %modules > 0; + @source = @ARGV; +} -# Parse config file +# Data parsed out of the config and state files. +my %hinc; # lib -> header +my %libinc; # header -> lib +my %cskip; # error_file -> lib +my %errorfile; # lib -> error file name +my %fmax; # lib -> max assigned function code +my %rmax; # lib -> max assigned reason code +my %fassigned; # lib -> colon-separated list of assigned function codes +my %rassigned; # lib -> colon-separated list of assigned reason codes +my %fnew; # lib -> count of new function codes +my %rnew; # lib -> count of new reason codes +my %rextra; # "extra" reason code -> lib +my %rcodes; # reason-name -> value +my %ftrans; # old name -> #define-friendly name (all caps) +my %fcodes; # function-name -> value +my $statefile; # state file with assigned reason and function codes +my %strings; # define -> text + +# Read and parse the config file +open(IN, "$config") || die "Can't open config file $config, $!,"; +while ( ) { + next if /^#/ || /^$/; + if ( /^L\s+(\S+)\s+(\S+)\s+(\S+)/ ) { + my $lib = $1; + my $hdr = $2; + my $err = $3; + $hinc{$lib} = $hdr; + $libinc{$hdr} = $lib; + $cskip{$err} = $lib; + next if $err eq 'NONE'; + $errorfile{$lib} = $err; + $fmax{$lib} = 100; + $rmax{$lib} = 100; + $fassigned{$lib} = ":"; + $rassigned{$lib} = ":"; + $fnew{$lib} = 0; + $rnew{$lib} = 0; + } elsif ( /^R\s+(\S+)\s+(\S+)/ ) { + $rextra{$1} = $2; + $rcodes{$1} = $2; + } elsif ( /^S\s+(\S+)/ ) { + $statefile = $1; + } else { + die "Illegal config line $_\n"; + } +} +close IN; -while() -{ - if(/^L\s+(\S+)\s+(\S+)\s+(\S+)/) { - $hinc{$1} = $2; - $libinc{$2} = $1; - $cskip{$3} = $1; - if($3 ne "NONE") { - $csrc{$1} = $3; - $fmax{$1} = 100; - $rmax{$1} = 100; - $fassigned{$1} = ":"; - $rassigned{$1} = ":"; - $fnew{$1} = 0; - $rnew{$1} = 0; - } - } elsif (/^F\s+(\S+)/) { - # Add extra function with $1 - } elsif (/^R\s+(\S+)\s+(\S+)/) { - $rextra{$1} = $2; - $rcodes{$1} = $2; - } +if ( ! $statefile ) { + $statefile = $config; + $statefile =~ s/.ec/.txt/; } -close IN; +# The statefile has all the previous assignments. +&phase("Reading state"); +my $skippedstate = 0; +if ( ! $reindex && $statefile ) { + open(STATE, "<$statefile") || die "Can't open $statefile, $!"; + + # Scan function and reason codes and store them: keep a note of the + # maximum code used. + while ( ) { + next if /^#/ || /^$/; + my $name; + my $code; + if ( /^(.+):(\d+):\\$/ ) { + $name = $1; + $code = $2; + my $next = ; + $next =~ s/^\s*(.*)\s*$/$1/; + die "Duplicate define $name" if exists $strings{$name}; + $strings{$name} = $next; + } elsif ( /^(\S+):(\d+):(.*)$/ ) { + $name = $1; + $code = $2; + die "Duplicate define $name" if exists $strings{$name}; + $strings{$name} = $3; + } else { + die "Bad line in $statefile:\n$_\n"; + } + my $lib = $name; + $lib =~ s/^((?:OSSL_|OPENSSL_)?[^_]{2,}).*$/$1/; + $lib = "SSL" if $lib =~ /TLS/; + if ( !defined $errorfile{$lib} ) { + print "Skipping $_"; + $skippedstate++; + next; + } + if ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_R_/ ) { + die "$lib reason code $code collision at $name\n" + if $rassigned{$lib} =~ /:$code:/; + $rassigned{$lib} .= "$code:"; + if ( !exists $rextra{$name} ) { + $rmax{$lib} = $code if $code > $rmax{$lib}; + } + $rcodes{$name} = $code; + } elsif ( $name =~ /^(?:OSSL_|OPENSSL_)?[A-Z0-9]{2,}_F_/ ) { + die "$lib function code $code collision at $name\n" + if $fassigned{$lib} =~ /:$code:/; + $fassigned{$lib} .= "$code:"; + $fmax{$lib} = $code if $code > $fmax{$lib}; + $fcodes{$name} = $code; + } else { + die "Bad line in $statefile:\n$_\n"; + } + } + close(STATE); + + if ( $debug ) { + foreach my $lib ( sort keys %rmax ) { + print STDERR "Reason codes for ${lib}:\n"; + if ( $rassigned{$lib} =~ m/^:(.*):$/ ) { + my @rassigned = sort { $a <=> $b } split( ":", $1 ); + print STDERR " ", join(' ', @rassigned), "\n"; + } else { + print STDERR " --none--\n"; + } + } + print STDERR "\n"; + foreach my $lib ( sort keys %fmax ) { + print STDERR "Function codes for ${lib}:\n"; + if ( $fassigned{$lib} =~ m/^:(.*):$/ ) { + my @fassigned = sort { $a <=> $b } split( ":", $1 ); + print STDERR " ", join(' ', @fassigned), "\n"; + } else { + print STDERR " --none--\n"; + } + } + } +} -# Scan each header file in turn and make a list of error codes +# Scan each header file and make a list of error codes # and function names +&phase("Scanning headers"); +while ( ( my $hdr, my $lib ) = each %libinc ) { + next if $hdr eq "NONE"; + print STDERR " ." if $debug; + my $line = ""; + my $def = ""; + my $linenr = 0; + my $cpp = 0; + + open(IN, "<$hdr") || die "Can't open $hdr, $!,"; + while ( ) { + $linenr++; + + if ( $line ne '' ) { + $_ = $line . $_; + $line = ''; + } + + if ( /\\$/ ) { + $line = $_; + next; + } + + if ( /\/\*/ ) { + if ( not /\*\// ) { # multiline comment... + $line = $_; # ... just accumulate + next; + } else { + s/\/\*.*?\*\///gs; # wipe it + } + } -while (($hdr, $lib) = each %libinc) -{ - next if($hdr eq "NONE"); - print STDERR "Scanning header file $hdr\n" if $debug; - my $line = "", $def= "", $linenr = 0, $gotfile = 0, $cpp = 0; - if (open(IN, "<$hdr")) { - $gotfile = 1; - while() { - $linenr++; - print STDERR "line: $linenr\r" if $debug; - - last if(/BEGIN\s+ERROR\s+CODES/); - if ($line ne '') { - $_ = $line . $_; - $line = ''; - } - - if (/\\$/) { - $line = $_; - next; - } - - if(/\/\*/) { - if (not /\*\//) { # multiline comment... - $line = $_; # ... just accumulate - next; - } else { - s/\/\*.*?\*\///gs; # wipe it - } - } - - if ($cpp) { - $cpp++ if /^#\s*if/; - $cpp-- if /^#\s*endif/; - next; - } - $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration - - next if (/^\#/); # skip preprocessor directives - - s/{[^{}]*}//gs; # ignore {} blocks - - if (/\{|\/\*/) { # Add a } so editor works... - $line = $_; - } else { - $def .= $_; - } - } - } - - print STDERR " \r" if $debug; - $defnr = 0; - # Delete any DECLARE_ macros - $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs; - foreach (split /;/, $def) { - $defnr++; - print STDERR "def: $defnr\r" if $debug; - - # The goal is to collect function names from function declarations. - - s/^[\n\s]*//g; - s/[\n\s]*$//g; - - # Skip over recognized non-function declarations - next if(/typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/); - - # Remove STACK_OF(foo) - s/STACK_OF\(\w+\)/void/; - - # Reduce argument lists to empty () - # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {} - while(/\(.*\)/s) { - s/\([^\(\)]+\)/\{\}/gs; - s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f - } - # pretend as we didn't use curly braces: {} -> () - s/\{\}/\(\)/gs; - - if (/(\w+)\s*\(\).*/s) { # first token prior [first] () is - my $name = $1; # a function name! - $name =~ tr/[a-z]/[A-Z]/; - $ftrans{$name} = $1; - } elsif (/[\(\)]/ and not (/=/)) { - print STDERR "Header $hdr: cannot parse: $_;\n"; - } - } - - print STDERR " \r" if $debug; - - next if $reindex; - - # Scan function and reason codes and store them: keep a note of the - # maximum code used. - - if ($gotfile) { - while() { - if(/^\#\s*define\s+(\S+)\s+(\S+)/) { - $name = $1; - $code = $2; - next if $name =~ /^${lib}err/; - unless($name =~ /^${lib}_([RF])_(\w+)$/) { - print STDERR "Invalid error code $name\n"; - next; - } - if($1 eq "R") { - $rcodes{$name} = $code; - if ($rassigned{$lib} =~ /:$code:/) { - print STDERR "!! ERROR: $lib reason code $code assigned twice (collision at $name)\n"; - ++$errcount; - } - $rassigned{$lib} .= "$code:"; - if(!(exists $rextra{$name}) && - ($code > $rmax{$lib}) ) { - $rmax{$lib} = $code; - } - } else { - if ($fassigned{$lib} =~ /:$code:/) { - print STDERR "!! ERROR: $lib function code $code assigned twice (collision at $name)\n"; - ++$errcount; - } - $fassigned{$lib} .= "$code:"; - if($code > $fmax{$lib}) { - $fmax{$lib} = $code; - } - $fcodes{$name} = $code; - } - } - } - } - - if ($debug) { - if (defined($fmax{$lib})) { - print STDERR "Max function code fmax" . "{" . "$lib" . "} = $fmax{$lib}\n"; - $fassigned{$lib} =~ m/^:(.*):$/; - @fassigned = sort {$a <=> $b} split(":", $1); - print STDERR " @fassigned\n"; - } - if (defined($rmax{$lib})) { - print STDERR "Max reason code rmax" . "{" . "$lib" . "} = $rmax{$lib}\n"; - $rassigned{$lib} =~ m/^:(.*):$/; - @rassigned = sort {$a <=> $b} split(":", $1); - print STDERR " @rassigned\n"; - } - } - - if ($lib eq "SSL") { - if ($rmax{$lib} >= 1000) { - print STDERR "!! ERROR: SSL error codes 1000+ are reserved for alerts.\n"; - print STDERR "!! Any new alerts must be added to $config.\n"; - ++$errcount; - print STDERR "\n"; - } - } - close IN; + if ( $cpp ) { + $cpp++ if /^#\s*if/; + $cpp-- if /^#\s*endif/; + next; + } + $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration + + next if /^\#/; # skip preprocessor directives + + s/{[^{}]*}//gs; # ignore {} blocks + + if ( /\{|\/\*/ ) { # Add a so editor works... + $line = $_; + } else { + $def .= $_; + } + } + + # Delete any DECLARE_ macros + my $defnr = 0; + $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs; + foreach ( split /;/, $def ) { + $defnr++; + # The goal is to collect function names from function declarations. + + s/^[\n\s]*//g; + s/[\n\s]*$//g; + + # Skip over recognized non-function declarations + next if /typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/; + + # Remove STACK_OF(foo) + s/STACK_OF\(\w+\)/void/; + + # Reduce argument lists to empty () + # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {} + while ( /\(.*\)/s ) { + s/\([^\(\)]+\)/\{\}/gs; + s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f + } + + # pretend as we didn't use curly braces: {} -> () + s/\{\}/\(\)/gs; + + # Last token just before the first () is a function name. + if ( /(\w+)\s*\(\).*/s ) { + my $name = $1; + $name =~ tr/[a-z]/[A-Z]/; + $ftrans{$name} = $1; + } elsif ( /[\(\)]/ and not(/=/) ) { + print STDERR "Header $hdr: cannot parse: $_;\n"; + } + } + + next if $reindex; + + if ( $lib eq "SSL" && $rmax{$lib} >= 1000 ) { + print STDERR "SSL error codes 1000+ are reserved for alerts.\n"; + print STDERR "Any new alerts must be added to $config.\n"; + $errors++; + } + close IN; } +print STDERR "\n" if $debug; # Scan each C source file and look for function and reason codes # This is done by looking for strings that "look like" function or # reason codes: basically anything consisting of all upper case and # numerics which has _F_ or _R_ in it and which has the name of an -# error library at the start. This seems to work fine except for the +# error library at the start. This seems to work fine except for the # oddly named structure BIO_F_CTX which needs to be ignored. # If a code doesn't exist in list compiled from headers then mark it # with the value "X" as a place holder to give it a value later. -# Store all function and reason codes found in %ufcodes and %urcodes +# Store all function and reason codes found in %usedfuncs and %usedreasons # so all those unreferenced can be printed out. - - -foreach $file (@source) { - # Don't parse the error source file. - next if exists $cskip{$file}; - print STDERR "File loaded: ".$file."\r" if $debug; - open(IN, "<$file") || die "Can't open source file $file\n"; - my $func; - my $linenr = 0; - while() { - # skip obsoleted source files entirely! - last if(/^#error\s+obsolete/); - $linenr++; - if (!/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/) - { - /^([^()]*(\([^()]*\)[^()]*)*)\(/; - $1 =~ /([A-Za-z_0-9]*)$/; - $func = $1; - } - - if(/(([A-Z0-9]+)_F_([A-Z0-9_]+))/) { - next unless exists $csrc{$2}; - next if($1 eq "BIO_F_BUFFER_CTX"); - $ufcodes{$1} = 1; - if(!exists $fcodes{$1}) { - $fcodes{$1} = "X"; - $fnew{$2}++; - } - $ftrans{$3} = $func unless exists $ftrans{$3}; - if (uc $func ne $3) { +&phase("Scanning source"); +my %usedfuncs; +my %usedreasons; +foreach my $file ( @source ) { + # Don't parse the error source file. + next if exists $cskip{$file}; + open( IN, "<$file" ) || die "Can't open $file, $!,"; + my $func; + my $linenr = 0; + print STDERR "$file:\n" if $debug; + while ( ) { + + # skip obsoleted source files entirely! + last if /^#error\s+obsolete/; + $linenr++; + if ( !/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/ ) { + /^([^()]*(\([^()]*\)[^()]*)*)\(/; + $1 =~ /([A-Za-z_0-9]*)$/; + $func = $1; + } + + if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_F_([A-Z0-9_]+))/ ) { + next unless exists $errorfile{$2}; + next if $1 eq "BIO_F_BUFFER_CTX"; + $usedfuncs{$1} = 1; + if ( !exists $fcodes{$1} ) { + print STDERR " New function $1\n" if $debug; + $fcodes{$1} = "X"; + $fnew{$2}++; + } + $ftrans{$3} = $func unless exists $ftrans{$3}; + if ( uc($func) ne $3 ) { print STDERR "ERROR: mismatch $file:$linenr $func:$3\n"; - $errcount++; + $errors++; + } + print STDERR " Function $1 = $fcodes{$1}\n" + if $debug; + } + if ( /(((?:OSSL_|OPENSSL_)?[A-Z0-9]{2,})_R_[A-Z0-9_]+)/ ) { + next unless exists $errorfile{$2}; + $usedreasons{$1} = 1; + if ( !exists $rcodes{$1} ) { + print STDERR " New reason $1\n" if $debug; + $rcodes{$1} = "X"; + $rnew{$2}++; } - print STDERR "Function: $1\t= $fcodes{$1} (lib: $2, name: $3)\n" if $debug; - } - if(/(([A-Z0-9]+)_R_[A-Z0-9_]+)/) { - next unless exists $csrc{$2}; - $urcodes{$1} = 1; - if(!exists $rcodes{$1}) { - $rcodes{$1} = "X"; - $rnew{$2}++; - } - print STDERR "Reason: $1\t= $rcodes{$1} (lib: $2)\n" if $debug; - } - } - close IN; + print STDERR " Reason $1 = $rcodes{$1}\n" if $debug; + } + } + close IN; } -print STDERR " \n" if $debug; +print STDERR "\n" if $debug; # Now process each library in turn. +&phase("Writing files"); +my $newstate = 0; +foreach my $lib ( keys %errorfile ) { + if ( ! $fnew{$lib} && ! $rnew{$lib} ) { + next unless $rebuild; + } + next if scalar keys %modules > 0 && !$modules{$lib}; + next if $nowrite; + print STDERR "$lib: $fnew{$lib} new functions\n" if $fnew{$lib}; + print STDERR "$lib: $rnew{$lib} new reasons\n" if $rnew{$lib}; + $newstate = 1; -foreach $lib (keys %csrc) -{ - my $hfile = $hinc{$lib}; - my $cfile = $csrc{$lib}; - if(!$fnew{$lib} && !$rnew{$lib}) { - next unless $rebuild; - } else { - print STDERR "$lib:\t\t$fnew{$lib} New Functions,"; - print STDERR " $rnew{$lib} New Reasons.\n"; - next unless $dowrite; - } - - # If we get here then we have some new error codes so we - # need to rebuild the header file and C file. - - # Make a sorted list of error and reason codes for later use. - - my @function = sort grep(/^${lib}_/,keys %fcodes); - my @reasons = sort grep(/^${lib}_/,keys %rcodes); - - # Rewrite the header file - - $cpp = 0; - $cplusplus = 0; - if (open(IN, "<$hfile")) { - # Copy across the old file - while() { - $cplusplus = $cpp if /^#.*ifdef.*cplusplus/; - $cpp++ if /^#\s*if/; - $cpp-- if /^#\s*endif/; - push @out, $_; - last if (/BEGIN ERROR CODES/); - } - close IN; - } else { - $cpp = 1; - $cplusplus = 1; - push @out, -"/*\n", -" * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.\n", -" *\n", -" * Licensed under the OpenSSL license (the \"License\"). You may not use\n", -" * this file except in compliance with the License. You can obtain a copy\n", -" * in the file LICENSE in the source distribution or at\n", -" * https://www.openssl.org/source/license.html\n", -" */\n", -"\n", -"#ifndef HEADER_${lib}_ERR_H\n", -"# define HEADER_${lib}_ERR_H\n", -"\n", -"# ifdef __cplusplus\n", -"extern \"C\" {\n", -"# endif\n", -"\n", -"/* BEGIN ERROR CODES */\n"; - } - open (OUT, ">$hfile") || die "Can't Open File $hfile for writing\n"; - - print OUT @out; - undef @out; - print OUT <<"EOF"; + # If we get here then we have some new error codes so we + # need to rebuild the header file and C file. + + # Make a sorted list of error and reason codes for later use. + my @function = sort grep( /^${lib}_/, keys %fcodes ); + my @reasons = sort grep( /^${lib}_/, keys %rcodes ); + + # Rewrite the header file + + my $hfile = $hinc{$lib}; + $hfile =~ s/.h$/err.h/ if $internal; + open( OUT, ">$hfile" ) || die "Can't write to $hfile, $!,"; + print OUT <<"EOF"; /* - * The following lines are auto generated by the script mkerr.pl. Any changes - * made after this point may be overwritten when the script is next run. + * Generated by util/mkerr.pl DO NOT EDIT + * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved. + * + * Licensed under the OpenSSL license (the \"License\"). You may not use + * this file except in compliance with the License. You can obtain a copy + * in the file LICENSE in the source distribution or at + * https://www.openssl.org/source/license.html */ -EOF - if($static) { - print OUT <<"EOF"; -${staticloader}void ERR_load_${lib}_strings(void); +#ifndef HEADER_${lib}ERR_H +# define HEADER_${lib}ERR_H EOF - } else { - print OUT <<"EOF"; -${staticloader}void ERR_load_${lib}_strings(void); -${staticloader}void ERR_unload_${lib}_strings(void); -${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line); -# define ${lib}err(f,r) ERR_${lib}_error((f),(r),OPENSSL_FILE,OPENSSL_LINE) - + if ( $internal ) { + # Declare the load function because the generate C file + # includes "fooerr.h" not "foo.h" + print OUT <<"EOF"; +# ifdef __cplusplus +extern \"C\" { +# endif +int ERR_load_${lib}_strings(void); +# ifdef __cplusplus +} +# endif EOF - } - print OUT <<"EOF"; -/* Error codes for the $lib functions. */ + } else { + print OUT <<"EOF"; +# define ${lib}err(f, r) ERR_${lib}_error((f), (r), OPENSSL_FILE, OPENSSL_LINE) -/* Function codes. */ EOF + if ( ! $static ) { + print OUT <<"EOF"; + +# ifdef __cplusplus +extern \"C\" { +# endif +int ERR_load_${lib}_strings(void); +void ERR_unload_${lib}_strings(void); +void ERR_${lib}_error(int function, int reason, char *file, int line); +# ifdef __cplusplus +} +# endif +EOF + } + } - foreach $i (@function) { - $z=48 - length($i); - if($fcodes{$i} eq "X") { - $fassigned{$lib} =~ m/^:([^:]*):/; - $findcode = $1; - if (!defined($findcode)) { - $findcode = $fmax{$lib}; - } - while ($fassigned{$lib} =~ m/:$findcode:/) { - $findcode++; - } - $fcodes{$i} = $findcode; - $fassigned{$lib} .= "$findcode:"; - print STDERR "New Function code $i\n" if $debug; - } - printf OUT "# define $i%s $fcodes{$i}\n"," " x $z; - } - - print OUT "\n/* Reason codes. */\n"; - - foreach $i (@reasons) { - $z=48 - length($i); - if($rcodes{$i} eq "X") { - $rassigned{$lib} =~ m/^:([^:]*):/; - $findcode = $1; - if (!defined($findcode)) { - $findcode = $rmax{$lib}; - } - while ($rassigned{$lib} =~ m/:$findcode:/) { - $findcode++; - } - $rcodes{$i} = $findcode; - $rassigned{$lib} .= "$findcode:"; - print STDERR "New Reason code $i\n" if $debug; - } - printf OUT "# define $i%s $rcodes{$i}\n"," " x $z; - } - print OUT <<"EOF"; + print OUT "\n/*\n * $lib function codes.\n */\n"; + foreach my $i ( @function ) { + my $z = 48 - length($i); + $z = 0 if $z < 0; + if ( $fcodes{$i} eq "X" ) { + $fassigned{$lib} =~ m/^:([^:]*):/; + my $findcode = $1; + $findcode = $fmax{$lib} if !defined $findcode; + while ( $fassigned{$lib} =~ m/:$findcode:/ ) { + $findcode++; + } + $fcodes{$i} = $findcode; + $fassigned{$lib} .= "$findcode:"; + print STDERR "New Function code $i\n" if $debug; + } + printf OUT "# define $i%s $fcodes{$i}\n", " " x $z; + } -EOF - do { - if ($cplusplus == $cpp) { - print OUT "#", " "x$cpp, "ifdef __cplusplus\n"; - print OUT "}\n"; - print OUT "#", " "x$cpp, "endif\n"; - } - if ($cpp-- > 0) { - print OUT "#", " "x$cpp, "endif\n"; - } - } while ($cpp); - close OUT; - - # Rewrite the C source file containing the error details. - - # First, read any existing reason string definitions: - my %err_reason_strings; - if (open(IN,"<$cfile")) { - my $line = ""; - while () { - s|\R$||; # Better chomp - $_ = $line . $_; - $line = ""; - if (/{ERR_(FUNC|REASON)\(/) { - if (/\b(${lib}_R_\w*)\b.*\"(.*)\"/) { - $err_reason_strings{$1} = $2; - } elsif (/\b${lib}_F_(\w*)\b.*\"(.*)\"/) { - if (!exists $ftrans{$1} && ($1 ne $2)) { - print STDERR "WARNING: Mismatched function string $2\n"; - $ftrans{$1} = $2; - } - } else { - $line = $_; - } - } - } - close(IN); - } - - - my $hincf; - if($static) { - $hincf = $hfile; - $hincf =~ s|.*include/||; - if ($hincf =~ m|^openssl/|) { - $hincf = "<${hincf}>"; - } else { - $hincf = "\"${hincf}\""; - } - } else { - $hincf = "\"$hfile\""; - } - - # If static we know the error code at compile time so use it - # in error definitions. - - if ($static) - { - $pack_errcode = "ERR_LIB_${lib}"; - $load_errcode = "0"; - } - else - { - $pack_errcode = "0"; - $load_errcode = "ERR_LIB_${lib}"; - } - - - open (OUT,">$cfile") || die "Can't open $cfile for writing"; - - print OUT <<"EOF"; + print OUT "\n/*\n * $lib reason codes.\n */\n"; + foreach my $i ( @reasons ) { + my $z = 48 - length($i); + $z = 0 if $z < 0; + if ( $rcodes{$i} eq "X" ) { + $rassigned{$lib} =~ m/^:([^:]*):/; + my $findcode = $1; + $findcode = $rmax{$lib} if !defined $findcode; + while ( $rassigned{$lib} =~ m/:$findcode:/ ) { + $findcode++; + } + $rcodes{$i} = $findcode; + $rassigned{$lib} .= "$findcode:"; + print STDERR "New Reason code $i\n" if $debug; + } + printf OUT "# define $i%s $rcodes{$i}\n", " " x $z; + } + print OUT "\n"; + + print OUT "#endif\n"; + + # Rewrite the C source file containing the error details. + + # First, read any existing reason string definitions: + my $cfile = $errorfile{$lib}; + my $pack_lib = $internal ? "ERR_LIB_${lib}" : "0"; + my $hincf = $hfile; + $hincf =~ s|.*include/||; + if ( $hincf =~ m|^openssl/| ) { + $hincf = "<${hincf}>"; + } else { + $hincf = "\"${hincf}\""; + } + + open( OUT, ">$cfile" ) + || die "Can't open $cfile for writing, $!, stopped"; + + my $const = $internal ? 'const ' : ''; + + print OUT <<"EOF"; /* * Generated by util/mkerr.pl DO NOT EDIT * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved. @@ -595,175 +551,187 @@ EOF * https://www.openssl.org/source/license.html */ -#include #include #include $hincf -/* BEGIN ERROR CODES */ #ifndef OPENSSL_NO_ERR -# define ERR_FUNC(func) ERR_PACK($pack_errcode,func,0) -# define ERR_REASON(reason) ERR_PACK($pack_errcode,0,reason) - -static ERR_STRING_DATA ${lib}_str_functs[] = { +static ${const}ERR_STRING_DATA ${lib}_str_functs[] = { EOF - # Add each function code: if a function name is found then use it. - foreach $i (@function) { - my $fn; - $i =~ /^${lib}_F_(\S+)$/; - $fn = $1; - if(exists $ftrans{$fn}) { - $fn = $ftrans{$fn}; - } -# print OUT "{ERR_PACK($pack_errcode,$i,0),\t\"$fn\"},\n"; - if(length($i) + length($fn) > 57) { - print OUT " {ERR_FUNC($i),\n \"$fn\"},\n"; - } else { - print OUT " {ERR_FUNC($i), \"$fn\"},\n"; - } - } - print OUT <<"EOF"; + + # Add each function code: if a function name is found then use it. + foreach my $i ( @function ) { + my $fn; + if ( exists $strings{$i} and $strings{$i} ne '' ) { + $fn = $strings{$i}; + $fn = "" if $fn eq '*'; + } else { + $i =~ /^${lib}_F_(\S+)$/; + $fn = $1; + $fn = $ftrans{$fn} if exists $ftrans{$fn}; + $strings{$i} = $fn; + } + my $short = " {ERR_PACK($pack_lib, $i, 0), \"$fn\"},"; + if ( length($short) <= 80 ) { + print OUT "$short\n"; + } else { + print OUT " {ERR_PACK($pack_lib, $i, 0),\n \"$fn\"},\n"; + } + } + print OUT <<"EOF"; {0, NULL} }; -static ERR_STRING_DATA ${lib}_str_reasons[] = { +static ${const}ERR_STRING_DATA ${lib}_str_reasons[] = { EOF - # Add each reason code. - foreach $i (@reasons) { - my $rn; - my $rstr = "ERR_REASON($i)"; - if (exists $err_reason_strings{$i}) { - $rn = $err_reason_strings{$i}; - } else { - $i =~ /^${lib}_R_(\S+)$/; - $rn = $1; - $rn =~ tr/_[A-Z]/ [a-z]/; - } - if(length($i) + length($rn) > 55) { - print OUT " {${rstr},\n \"$rn\"},\n"; - } else { - print OUT " {${rstr}, \"$rn\"},\n"; - } - } -if($static) { - print OUT <<"EOF"; + + # Add each reason code. + foreach my $i ( @reasons ) { + my $rn; + if ( exists $strings{$i} ) { + $rn = $strings{$i}; + $rn = "" if $rn eq '*'; + } else { + $i =~ /^${lib}_R_(\S+)$/; + $rn = $1; + $rn =~ tr/_[A-Z]/ [a-z]/; + $strings{$i} = $rn; + } + my $short = " {ERR_PACK($pack_lib, 0, $i), \"$rn\"},"; + if ( length($short) <= 80 ) { + print OUT "$short\n"; + } else { + print OUT " {ERR_PACK($pack_lib, 0, $i),\n \"$rn\"},\n"; + } + } + print OUT <<"EOF"; {0, NULL} }; #endif +EOF + if ( $internal ) { + print OUT <<"EOF"; -${staticloader}void ERR_load_${lib}_strings(void) +int ERR_load_${lib}_strings(void) { #ifndef OPENSSL_NO_ERR - if (ERR_func_error_string(${lib}_str_functs[0].error) == NULL) { - ERR_load_strings($load_errcode, ${lib}_str_functs); - ERR_load_strings($load_errcode, ${lib}_str_reasons); + ERR_load_strings_const(${lib}_str_functs); + ERR_load_strings_const(${lib}_str_reasons); } #endif + return 1; } EOF -} else { - print OUT <<"EOF"; - {0, NULL} -}; - -#endif - -#ifdef ${lib}_LIB_NAME -static ERR_STRING_DATA ${lib}_lib_name[] = { - {0, ${lib}_LIB_NAME}, - {0, NULL} -}; -#endif + } else { + my $st = $static ? "static " : ""; + print OUT <<"EOF"; -static int ${lib}_lib_error_code = 0; -static int ${lib}_error_init = 1; +static int lib_code = 0; +static int error_loaded = 0; -${staticloader}void ERR_load_${lib}_strings(void) +${st}int ERR_load_${lib}_strings(void) { - if (${lib}_lib_error_code == 0) - ${lib}_lib_error_code = ERR_get_next_error_library(); + if (lib_code == 0) + lib_code = ERR_get_next_error_library(); - if (${lib}_error_init) { - ${lib}_error_init = 0; + if (!error_loaded) { #ifndef OPENSSL_NO_ERR - ERR_load_strings(${lib}_lib_error_code, ${lib}_str_functs); - ERR_load_strings(${lib}_lib_error_code, ${lib}_str_reasons); -#endif - -#ifdef ${lib}_LIB_NAME - ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code, 0, 0); - ERR_load_strings(0, ${lib}_lib_name); + ERR_load_strings(lib_code, ${lib}_str_functs); + ERR_load_strings(lib_code, ${lib}_str_reasons); #endif + error_loaded = 1; } + return 1; } -${staticloader}void ERR_unload_${lib}_strings(void) +${st}void ERR_unload_${lib}_strings(void) { - if (${lib}_error_init == 0) { + if (error_loaded) { #ifndef OPENSSL_NO_ERR - ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_functs); - ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_reasons); -#endif - -#ifdef ${lib}_LIB_NAME - ERR_unload_strings(0, ${lib}_lib_name); + ERR_unload_strings(lib_code, ${lib}_str_functs); + ERR_unload_strings(lib_code, ${lib}_str_reasons); #endif - ${lib}_error_init = 1; + error_loaded = 0; } } -${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line) +${st}void ERR_${lib}_error(int function, int reason, char *file, int line) { - if (${lib}_lib_error_code == 0) - ${lib}_lib_error_code = ERR_get_next_error_library(); - ERR_PUT_error(${lib}_lib_error_code, function, reason, file, line); + if (lib_code == 0) + lib_code = ERR_get_next_error_library(); + ERR_PUT_error(lib_code, function, reason, file, line); } EOF -} - - close OUT; - undef %err_reason_strings; -} + } -if($debug && %notrans) { - print STDERR "The following function codes were not translated:\n"; - foreach(sort keys %notrans) - { - print STDERR "$_\n"; - } + close OUT; } +&phase("Ending"); # Make a list of unreferenced function and reason codes - -foreach (keys %fcodes) { - push (@funref, $_) unless exists $ufcodes{$_}; -} - -foreach (keys %rcodes) { - push (@runref, $_) unless exists $urcodes{$_}; -} - -if($unref && @funref) { - print STDERR "The following function codes were not referenced:\n"; - foreach(sort @funref) - { - print STDERR "$_\n"; - } +if ( $unref ) { + my @funref; + foreach ( keys %fcodes ) { + push( @funref, $_ ) unless exists $usedfuncs{$_}; + } + my @runref; + foreach ( keys %rcodes ) { + push( @runref, $_ ) unless exists $usedreasons{$_}; + } + if ( @funref ) { + print STDERR "The following function codes were not referenced:\n"; + foreach ( sort @funref ) { + print STDERR " $_\n"; + } + } + if ( @runref ) { + print STDERR "The following reason codes were not referenced:\n"; + foreach ( sort @runref ) { + print STDERR " $_\n"; + } + } } -if($unref && @runref) { - print STDERR "The following reason codes were not referenced:\n"; - foreach(sort @runref) - { - print STDERR "$_\n"; - } -} +die "Found $errors errors, quitting" if $errors; -if($errcount) { - print STDERR "There were errors, failing...\n\n"; - exit $errcount; +# Update the state file +if ( $newstate ) { + open(OUT, ">$statefile.new") + || die "Can't write $statefile.new, $!"; + print OUT <<"EOF"; +# Copyright 1999-$YEAR The OpenSSL Project Authors. All Rights Reserved. +# +# Licensed under the OpenSSL license (the "License"). You may not use +# this file except in compliance with the License. You can obtain a copy +# in the file LICENSE in the source distribution or at +# https://www.openssl.org/source/license.html +EOF + print OUT "\n# Function codes\n"; + foreach my $i ( sort keys %fcodes ) { + my $short = "$i:$fcodes{$i}:"; + my $t = exists $strings{$i} ? $strings{$i} : ""; + $t = "\\\n\t" . $t if length($short) + length($t) > 80; + print OUT "$short$t\n"; + } + print OUT "\n#Reason codes\n"; + foreach my $i ( sort keys %rcodes ) { + my $short = "$i:$rcodes{$i}:"; + my $t = exists $strings{$i} ? "$strings{$i}" : ""; + $t = "\\\n\t" . $t if length($short) + length($t) > 80; + print OUT "$short$t\n" if !exists $rextra{$i}; + } + close(OUT); + if ( $skippedstate ) { + print "Skipped state, leaving update in $statefile.new"; + } else { + rename "$statefile", "$statefile.old" + || die "Can't backup $statefile to $statefile.old, $!"; + rename "$statefile.new", "$statefile" + || die "Can't rename $statefile to $statefile.new, $!"; + } } +exit;