2 # Copyright 1999-2016 The OpenSSL Project Authors. All Rights Reserved.
4 # Licensed under the OpenSSL license (the "License"). You may not use
5 # this file except in compliance with the License. You can obtain a copy
6 # in the file LICENSE in the source distribution or at
7 # https://www.openssl.org/source/license.html
9 my $config = "crypto/err/openssl.ec";
10 my $hprefix = "openssl/";
18 my $staticloader = "";
20 my $YEAR = @t[5] + 1900;
26 my $year = (localtime)[5] + 1900;
32 $config = shift @ARGV;
33 } elsif($arg eq "-hprefix") {
35 $hprefix = shift @ARGV;
36 } elsif($arg eq "-debug") {
40 } elsif($arg eq "-rebuild") {
43 } elsif($arg eq "-recurse") {
46 } elsif($arg eq "-reindex") {
49 } elsif($arg eq "-nostatic") {
52 } elsif($arg eq "-staticloader") {
53 $staticloader = "static ";
55 } elsif($arg eq "-unref") {
58 } elsif($arg eq "-write") {
61 } elsif($arg eq "-help" || $arg eq "-h" || $arg eq "-?" || $arg eq "--help") {
63 mkerr.pl [options] ...
67 -conf F Use the config file F instead of the default one:
70 -hprefix P Prepend the filenames in generated #include <header>
71 statements with prefix P. Default: 'openssl/' (without
72 the quotes, naturally)
74 -debug Turn on debugging verbose output on stderr.
76 -rebuild Rebuild all header and C source files, irrespective of the
77 fact if any error or function codes have been added/removed.
78 Default: only update files for libraries which saw change
79 (of course, this requires '-write' as well, or no
80 files will be touched!)
82 -recurse scan a preconfigured set of directories / files for error and
84 (<crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <apps/*.c>)
85 When this option is NOT specified, the filelist is taken from
86 the commandline instead. Here, wildcards may be embedded. (Be
87 sure to escape those to prevent the shell from expanding them
88 for you when you wish mkerr.pl to do so instead.)
89 Default: take file list to scan from the command line.
91 -reindex Discard the numeric values previously assigned to the error
92 and function codes as extracted from the scanned header files;
93 instead renumber all of them starting from 100. (Note that
94 the numbers assigned through 'R' records in the config file
96 Default: keep previously assigned numbers. (You are warned
97 when collisions are detected.)
99 -nostatic Generates a different source code, where these additional
100 functions are generated for each library specified in the
102 void ERR_load_<LIB>_strings(void);
103 void ERR_unload_<LIB>_strings(void);
104 void ERR_<LIB>_error(int f, int r, char *fn, int ln);
105 #define <LIB>err(f,r) ERR_<LIB>_error(f,r,OPENSSL_FILE,OPENSSL_LINE)
106 while the code facilitates the use of these in an environment
107 where the error support routines are dynamically loaded at
109 Default: 'static' code generation.
111 -staticloader Prefix generated functions with the 'static' scope modifier.
112 Default: don't write any scope modifier prefix.
114 -unref Print out unreferenced function and reason codes.
116 -write Actually (over)write the generated code to the header and C
117 source files as assigned to each library through the config
119 Default: don't write.
121 -help / -h / -? / --help Show this help text.
123 ... Additional arguments are added to the file list to scan,
124 assuming '-recurse' was NOT specified on the command line.
134 @source = ( <crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <ssl/*/*.c> )
139 # Read in the config file
141 open(IN, "<$config") || die "Can't open config file $config";
147 if(/^L\s+(\S+)\s+(\S+)\s+(\S+)/) {
155 $fassigned{$1} = ":";
156 $rassigned{$1} = ":";
160 } elsif (/^F\s+(\S+)/) {
161 # Add extra function with $1
162 } elsif (/^R\s+(\S+)\s+(\S+)/) {
170 # Scan each header file in turn and make a list of error codes
173 while (($hdr, $lib) = each %libinc)
175 next if($hdr eq "NONE");
176 print STDERR "Scanning header file $hdr\n" if $debug;
177 my $line = "", $def= "", $linenr = 0, $gotfile = 0;
178 if (open(IN, "<$hdr")) {
182 print STDERR "line: $linenr\r" if $debug;
184 last if(/BEGIN\s+ERROR\s+CODES/);
196 if (not /\*\//) { # multiline comment...
197 $line = $_; # ... just accumulate
200 s/\/\*.*?\*\///gs; # wipe it
206 $cpp-- if /^#\s*endif/;
209 $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration
211 next if (/^\#/); # skip preprocessor directives
213 s/{[^{}]*}//gs; # ignore {} blocks
215 if (/\{|\/\*/) { # Add a } so editor works...
223 print STDERR " \r" if $debug;
225 # Delete any DECLARE_ macros
226 $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs;
227 foreach (split /;/, $def) {
229 print STDERR "def: $defnr\r" if $debug;
231 # The goal is to collect function names from function declarations.
236 # Skip over recognized non-function declarations
237 next if(/typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/);
239 # Remove STACK_OF(foo)
240 s/STACK_OF\(\w+\)/void/;
242 # Reduce argument lists to empty ()
243 # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {}
245 s/\([^\(\)]+\)/\{\}/gs;
246 s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f
248 # pretend as we didn't use curly braces: {} -> ()
251 if (/(\w+)\s*\(\).*/s) { # first token prior [first] () is
252 my $name = $1; # a function name!
253 $name =~ tr/[a-z]/[A-Z]/;
255 } elsif (/[\(\)]/ and not (/=/)) {
256 print STDERR "Header $hdr: cannot parse: $_;\n";
260 print STDERR " \r" if $debug;
264 # Scan function and reason codes and store them: keep a note of the
269 if(/^\#\s*define\s+(\S+)\s+(\S+)/) {
272 next if $name =~ /^${lib}err/;
273 unless($name =~ /^${lib}_([RF])_(\w+)$/) {
274 print STDERR "Invalid error code $name\n";
278 $rcodes{$name} = $code;
279 if ($rassigned{$lib} =~ /:$code:/) {
280 print STDERR "!! ERROR: $lib reason code $code assigned twice (collision at $name)\n";
283 $rassigned{$lib} .= "$code:";
284 if(!(exists $rextra{$name}) &&
285 ($code > $rmax{$lib}) ) {
289 if ($fassigned{$lib} =~ /:$code:/) {
290 print STDERR "!! ERROR: $lib function code $code assigned twice (collision at $name)\n";
293 $fassigned{$lib} .= "$code:";
294 if($code > $fmax{$lib}) {
297 $fcodes{$name} = $code;
304 if (defined($fmax{$lib})) {
305 print STDERR "Max function code fmax" . "{" . "$lib" . "} = $fmax{$lib}\n";
306 $fassigned{$lib} =~ m/^:(.*):$/;
307 @fassigned = sort {$a <=> $b} split(":", $1);
308 print STDERR " @fassigned\n";
310 if (defined($rmax{$lib})) {
311 print STDERR "Max reason code rmax" . "{" . "$lib" . "} = $rmax{$lib}\n";
312 $rassigned{$lib} =~ m/^:(.*):$/;
313 @rassigned = sort {$a <=> $b} split(":", $1);
314 print STDERR " @rassigned\n";
319 if ($rmax{$lib} >= 1000) {
320 print STDERR "!! ERROR: SSL error codes 1000+ are reserved for alerts.\n";
321 print STDERR "!! Any new alerts must be added to $config.\n";
329 # Scan each C source file and look for function and reason codes
330 # This is done by looking for strings that "look like" function or
331 # reason codes: basically anything consisting of all upper case and
332 # numerics which has _F_ or _R_ in it and which has the name of an
333 # error library at the start. This seems to work fine except for the
334 # oddly named structure BIO_F_CTX which needs to be ignored.
335 # If a code doesn't exist in list compiled from headers then mark it
336 # with the value "X" as a place holder to give it a value later.
337 # Store all function and reason codes found in %ufcodes and %urcodes
338 # so all those unreferenced can be printed out.
341 foreach $file (@source) {
342 # Don't parse the error source file.
343 next if exists $cskip{$file};
344 print STDERR "File loaded: ".$file."\r" if $debug;
345 open(IN, "<$file") || die "Can't open source file $file\n";
349 # skip obsoleted source files entirely!
350 last if(/^#error\s+obsolete/);
352 if (!/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/)
354 /^([^()]*(\([^()]*\)[^()]*)*)\(/;
355 $1 =~ /([A-Za-z_0-9]*)$/;
359 if(/(([A-Z0-9]+)_F_([A-Z0-9_]+))/) {
360 next unless exists $csrc{$2};
361 next if($1 eq "BIO_F_BUFFER_CTX");
363 if(!exists $fcodes{$1}) {
367 $ftrans{$3} = $func unless exists $ftrans{$3};
368 if (uc $func ne $3) {
369 print STDERR "ERROR: mismatch $file:$linenr $func:$3\n";
372 print STDERR "Function: $1\t= $fcodes{$1} (lib: $2, name: $3)\n" if $debug;
374 if(/(([A-Z0-9]+)_R_[A-Z0-9_]+)/) {
375 next unless exists $csrc{$2};
377 if(!exists $rcodes{$1}) {
381 print STDERR "Reason: $1\t= $rcodes{$1} (lib: $2)\n" if $debug;
386 print STDERR " \n" if $debug;
388 # Now process each library in turn.
390 foreach $lib (keys %csrc)
392 my $hfile = $hinc{$lib};
393 my $cfile = $csrc{$lib};
394 if(!$fnew{$lib} && !$rnew{$lib}) {
395 next unless $rebuild;
397 print STDERR "$lib:\t\t$fnew{$lib} New Functions,";
398 print STDERR " $rnew{$lib} New Reasons.\n";
399 next unless $dowrite;
402 # If we get here then we have some new error codes so we
403 # need to rebuild the header file and C file.
405 # Make a sorted list of error and reason codes for later use.
407 my @function = sort grep(/^${lib}_/,keys %fcodes);
408 my @reasons = sort grep(/^${lib}_/,keys %rcodes);
410 # Rewrite the header file
412 if (open(IN, "<$hfile")) {
413 # Copy across the old file
416 last if (/BEGIN ERROR CODES/);
422 " * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.\n",
424 " * Licensed under the OpenSSL license (the \"License\"). You may not use\n",
425 " * this file except in compliance with the License. You can obtain a copy\n",
426 " * in the file LICENSE in the source distribution or at\n",
427 " * https://www.openssl.org/source/license.html\n",
430 "#ifndef HEADER_${lib}_ERR_H\n",
431 "#define HEADER_${lib}_ERR_H\n",
433 "#ifdef __cplusplus\n",
437 "/* BEGIN ERROR CODES */\n";
439 open (OUT, ">$hfile") || die "Can't Open File $hfile for writing\n";
446 * Content after this point is generated by util/mkerr.pl
452 ${staticloader}void ERR_load_${lib}_strings(void);
456 ${staticloader}void ERR_load_${lib}_strings(void);
457 ${staticloader}void ERR_unload_${lib}_strings(void);
458 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line);
459 # define ${lib}err(f,r) ERR_${lib}_error((f),(r),OPENSSL_FILE,OPENSSL_LINE)
464 /* Error codes for the $lib functions. */
466 /* Function codes. */
469 foreach $i (@function) {
471 if($fcodes{$i} eq "X") {
472 $fassigned{$lib} =~ m/^:([^:]*):/;
474 if (!defined($findcode)) {
475 $findcode = $fmax{$lib};
477 while ($fassigned{$lib} =~ m/:$findcode:/) {
480 $fcodes{$i} = $findcode;
481 $fassigned{$lib} .= "$findcode:";
482 print STDERR "New Function code $i\n" if $debug;
484 printf OUT "# define $i%s $fcodes{$i}\n"," " x $z;
487 print OUT "\n/* Reason codes. */\n";
489 foreach $i (@reasons) {
491 if($rcodes{$i} eq "X") {
492 $rassigned{$lib} =~ m/^:([^:]*):/;
494 if (!defined($findcode)) {
495 $findcode = $rmax{$lib};
497 while ($rassigned{$lib} =~ m/:$findcode:/) {
500 $rcodes{$i} = $findcode;
501 $rassigned{$lib} .= "$findcode:";
502 print STDERR "New Reason code $i\n" if $debug;
504 printf OUT "# define $i%s $rcodes{$i}\n"," " x $z;
515 # Rewrite the C source file containing the error details.
517 # First, read any existing reason string definitions:
518 my %err_reason_strings;
519 if (open(IN,"<$cfile")) {
522 s|\R$||; # Better chomp
525 if (/{ERR_(FUNC|REASON)\(/) {
526 if (/\b(${lib}_R_\w*)\b.*\"(.*)\"/) {
527 $err_reason_strings{$1} = $2;
528 } elsif (/\b${lib}_F_(\w*)\b.*\"(.*)\"/) {
529 if (!exists $ftrans{$1} && ($1 ne $2)) {
530 print STDERR "WARNING: Mismatched function string $2\n";
544 $hfile =~ /([^\/]+)$/;
545 $hincf = "<${hprefix}$1>";
547 $hincf = "\"$hfile\"";
550 # If static we know the error code at compile time so use it
551 # in error definitions.
555 $pack_errcode = "ERR_LIB_${lib}";
561 $load_errcode = "ERR_LIB_${lib}";
565 open (OUT,">$cfile") || die "Can't open $cfile for writing";
569 * Generated by util/mkerr.pl DO NOT EDIT
570 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
572 * Licensed under the OpenSSL license (the "License"). You may not use
573 * this file except in compliance with the License. You can obtain a copy
574 * in the file LICENSE in the source distribution or at
575 * https://www.openssl.org/source/license.html
579 #include <openssl/err.h>
582 /* BEGIN ERROR CODES */
583 #ifndef OPENSSL_NO_ERR
585 # define ERR_FUNC(func) ERR_PACK($pack_errcode,func,0)
586 # define ERR_REASON(reason) ERR_PACK($pack_errcode,0,reason)
588 static ERR_STRING_DATA ${lib}_str_functs[] = {
590 # Add each function code: if a function name is found then use it.
591 foreach $i (@function) {
593 $i =~ /^${lib}_F_(\S+)$/;
595 if(exists $ftrans{$fn}) {
598 # print OUT "{ERR_PACK($pack_errcode,$i,0),\t\"$fn\"},\n";
599 if(length($i) + length($fn) > 58) {
600 print OUT " {ERR_FUNC($i),\n \"$fn\"},\n";
602 print OUT " {ERR_FUNC($i), \"$fn\"},\n";
609 static ERR_STRING_DATA ${lib}_str_reasons[] = {
611 # Add each reason code.
612 foreach $i (@reasons) {
614 my $rstr = "ERR_REASON($i)";
615 if (exists $err_reason_strings{$i}) {
616 $rn = $err_reason_strings{$i};
618 $i =~ /^${lib}_R_(\S+)$/;
620 $rn =~ tr/_[A-Z]/ [a-z]/;
622 if(length($i) + length($rn) > 56) {
623 print OUT " {${rstr},\n \"$rn\"},\n";
625 print OUT " {${rstr}, \"$rn\"},\n";
635 ${staticloader}void ERR_load_${lib}_strings(void)
637 #ifndef OPENSSL_NO_ERR
639 if (ERR_func_error_string(${lib}_str_functs[0].error) == NULL) {
640 ERR_load_strings($load_errcode, ${lib}_str_functs);
641 ERR_load_strings($load_errcode, ${lib}_str_reasons);
653 #ifdef ${lib}_LIB_NAME
654 static ERR_STRING_DATA ${lib}_lib_name[] = {
655 {0, ${lib}_LIB_NAME},
660 static int ${lib}_lib_error_code = 0;
661 static int ${lib}_error_init = 1;
663 ${staticloader}void ERR_load_${lib}_strings(void)
665 if (${lib}_lib_error_code == 0)
666 ${lib}_lib_error_code = ERR_get_next_error_library();
668 if (${lib}_error_init) {
669 ${lib}_error_init = 0;
670 #ifndef OPENSSL_NO_ERR
671 ERR_load_strings(${lib}_lib_error_code, ${lib}_str_functs);
672 ERR_load_strings(${lib}_lib_error_code, ${lib}_str_reasons);
675 #ifdef ${lib}_LIB_NAME
676 ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code, 0, 0);
677 ERR_load_strings(0, ${lib}_lib_name);
682 ${staticloader}void ERR_unload_${lib}_strings(void)
684 if (${lib}_error_init == 0) {
685 #ifndef OPENSSL_NO_ERR
686 ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_functs);
687 ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_reasons);
690 #ifdef ${lib}_LIB_NAME
691 ERR_unload_strings(0, ${lib}_lib_name);
693 ${lib}_error_init = 1;
697 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line)
699 if (${lib}_lib_error_code == 0)
700 ${lib}_lib_error_code = ERR_get_next_error_library();
701 ERR_PUT_error(${lib}_lib_error_code, function, reason, file, line);
708 undef %err_reason_strings;
711 if($debug && %notrans) {
712 print STDERR "The following function codes were not translated:\n";
713 foreach(sort keys %notrans)
719 # Make a list of unreferenced function and reason codes
721 foreach (keys %fcodes) {
722 push (@funref, $_) unless exists $ufcodes{$_};
725 foreach (keys %rcodes) {
726 push (@runref, $_) unless exists $urcodes{$_};
729 if($unref && @funref) {
730 print STDERR "The following function codes were not referenced:\n";
731 foreach(sort @funref)
737 if($unref && @runref) {
738 print STDERR "The following reason codes were not referenced:\n";
739 foreach(sort @runref)
746 print STDERR "There were errors, failing...\n\n";