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 = "";
24 my $year = (localtime)[5] + 1900;
30 $config = shift @ARGV;
31 } elsif($arg eq "-hprefix") {
33 $hprefix = shift @ARGV;
34 } elsif($arg eq "-debug") {
38 } elsif($arg eq "-rebuild") {
41 } elsif($arg eq "-recurse") {
44 } elsif($arg eq "-reindex") {
47 } elsif($arg eq "-nostatic") {
50 } elsif($arg eq "-staticloader") {
51 $staticloader = "static ";
53 } elsif($arg eq "-unref") {
56 } elsif($arg eq "-write") {
59 } elsif($arg eq "-help" || $arg eq "-h" || $arg eq "-?" || $arg eq "--help") {
61 mkerr.pl [options] ...
65 -conf F Use the config file F instead of the default one:
68 -hprefix P Prepend the filenames in generated #include <header>
69 statements with prefix P. Default: 'openssl/' (without
70 the quotes, naturally)
72 -debug Turn on debugging verbose output on stderr.
74 -rebuild Rebuild all header and C source files, irrespective of the
75 fact if any error or function codes have been added/removed.
76 Default: only update files for libraries which saw change
77 (of course, this requires '-write' as well, or no
78 files will be touched!)
80 -recurse scan a preconfigured set of directories / files for error and
82 (<crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <apps/*.c>)
83 When this option is NOT specified, the filelist is taken from
84 the commandline instead. Here, wildcards may be embedded. (Be
85 sure to escape those to prevent the shell from expanding them
86 for you when you wish mkerr.pl to do so instead.)
87 Default: take file list to scan from the command line.
89 -reindex Discard the numeric values previously assigned to the error
90 and function codes as extracted from the scanned header files;
91 instead renumber all of them starting from 100. (Note that
92 the numbers assigned through 'R' records in the config file
94 Default: keep previously assigned numbers. (You are warned
95 when collisions are detected.)
97 -nostatic Generates a different source code, where these additional
98 functions are generated for each library specified in the
100 void ERR_load_<LIB>_strings(void);
101 void ERR_unload_<LIB>_strings(void);
102 void ERR_<LIB>_error(int f, int r, char *fn, int ln);
103 #define <LIB>err(f,r) ERR_<LIB>_error(f,r,OPENSSL_FILE,OPENSSL_LINE)
104 while the code facilitates the use of these in an environment
105 where the error support routines are dynamically loaded at
107 Default: 'static' code generation.
109 -staticloader Prefix generated functions with the 'static' scope modifier.
110 Default: don't write any scope modifier prefix.
112 -unref Print out unreferenced function and reason codes.
114 -write Actually (over)write the generated code to the header and C
115 source files as assigned to each library through the config
117 Default: don't write.
119 -help / -h / -? / --help Show this help text.
121 ... Additional arguments are added to the file list to scan,
122 assuming '-recurse' was NOT specified on the command line.
132 @source = ( <crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <ssl/*/*.c> )
137 # Read in the config file
139 open(IN, "<$config") || die "Can't open config file $config";
145 if(/^L\s+(\S+)\s+(\S+)\s+(\S+)/) {
153 $fassigned{$1} = ":";
154 $rassigned{$1} = ":";
158 } elsif (/^F\s+(\S+)/) {
159 # Add extra function with $1
160 } elsif (/^R\s+(\S+)\s+(\S+)/) {
168 # Scan each header file in turn and make a list of error codes
171 while (($hdr, $lib) = each %libinc)
173 next if($hdr eq "NONE");
174 print STDERR "Scanning header file $hdr\n" if $debug;
175 my $line = "", $def= "", $linenr = 0, $gotfile = 0;
176 if (open(IN, "<$hdr")) {
180 print STDERR "line: $linenr\r" if $debug;
182 last if(/BEGIN\s+ERROR\s+CODES/);
194 if (not /\*\//) { # multiline comment...
195 $line = $_; # ... just accumulate
198 s/\/\*.*?\*\///gs; # wipe it
204 $cpp-- if /^#\s*endif/;
207 $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration
209 next if (/^\#/); # skip preprocessor directives
211 s/{[^{}]*}//gs; # ignore {} blocks
213 if (/\{|\/\*/) { # Add a } so editor works...
221 print STDERR " \r" if $debug;
223 # Delete any DECLARE_ macros
224 $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs;
225 foreach (split /;/, $def) {
227 print STDERR "def: $defnr\r" if $debug;
229 # The goal is to collect function names from function declarations.
234 # Skip over recognized non-function declarations
235 next if(/typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/);
237 # Remove STACK_OF(foo)
238 s/STACK_OF\(\w+\)/void/;
240 # Reduce argument lists to empty ()
241 # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {}
243 s/\([^\(\)]+\)/\{\}/gs;
244 s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f
246 # pretend as we didn't use curly braces: {} -> ()
249 if (/(\w+)\s*\(\).*/s) { # first token prior [first] () is
250 my $name = $1; # a function name!
251 $name =~ tr/[a-z]/[A-Z]/;
253 } elsif (/[\(\)]/ and not (/=/)) {
254 print STDERR "Header $hdr: cannot parse: $_;\n";
258 print STDERR " \r" if $debug;
262 # Scan function and reason codes and store them: keep a note of the
267 if(/^\#\s*define\s+(\S+)\s+(\S+)/) {
270 next if $name =~ /^${lib}err/;
271 unless($name =~ /^${lib}_([RF])_(\w+)$/) {
272 print STDERR "Invalid error code $name\n";
276 $rcodes{$name} = $code;
277 if ($rassigned{$lib} =~ /:$code:/) {
278 print STDERR "!! ERROR: $lib reason code $code assigned twice (collision at $name)\n";
281 $rassigned{$lib} .= "$code:";
282 if(!(exists $rextra{$name}) &&
283 ($code > $rmax{$lib}) ) {
287 if ($fassigned{$lib} =~ /:$code:/) {
288 print STDERR "!! ERROR: $lib function code $code assigned twice (collision at $name)\n";
291 $fassigned{$lib} .= "$code:";
292 if($code > $fmax{$lib}) {
295 $fcodes{$name} = $code;
302 if (defined($fmax{$lib})) {
303 print STDERR "Max function code fmax" . "{" . "$lib" . "} = $fmax{$lib}\n";
304 $fassigned{$lib} =~ m/^:(.*):$/;
305 @fassigned = sort {$a <=> $b} split(":", $1);
306 print STDERR " @fassigned\n";
308 if (defined($rmax{$lib})) {
309 print STDERR "Max reason code rmax" . "{" . "$lib" . "} = $rmax{$lib}\n";
310 $rassigned{$lib} =~ m/^:(.*):$/;
311 @rassigned = sort {$a <=> $b} split(":", $1);
312 print STDERR " @rassigned\n";
317 if ($rmax{$lib} >= 1000) {
318 print STDERR "!! ERROR: SSL error codes 1000+ are reserved for alerts.\n";
319 print STDERR "!! Any new alerts must be added to $config.\n";
327 # Scan each C source file and look for function and reason codes
328 # This is done by looking for strings that "look like" function or
329 # reason codes: basically anything consisting of all upper case and
330 # numerics which has _F_ or _R_ in it and which has the name of an
331 # error library at the start. This seems to work fine except for the
332 # oddly named structure BIO_F_CTX which needs to be ignored.
333 # If a code doesn't exist in list compiled from headers then mark it
334 # with the value "X" as a place holder to give it a value later.
335 # Store all function and reason codes found in %ufcodes and %urcodes
336 # so all those unreferenced can be printed out.
339 foreach $file (@source) {
340 # Don't parse the error source file.
341 next if exists $cskip{$file};
342 print STDERR "File loaded: ".$file."\r" if $debug;
343 open(IN, "<$file") || die "Can't open source file $file\n";
347 # skip obsoleted source files entirely!
348 last if(/^#error\s+obsolete/);
350 if (!/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/)
352 /^([^()]*(\([^()]*\)[^()]*)*)\(/;
353 $1 =~ /([A-Za-z_0-9]*)$/;
357 if(/(([A-Z0-9]+)_F_([A-Z0-9_]+))/) {
358 next unless exists $csrc{$2};
359 next if($1 eq "BIO_F_BUFFER_CTX");
361 if(!exists $fcodes{$1}) {
365 $ftrans{$3} = $func unless exists $ftrans{$3};
366 if (uc $func ne $3) {
367 print STDERR "ERROR: mismatch $file:$linenr $func:$3\n";
370 print STDERR "Function: $1\t= $fcodes{$1} (lib: $2, name: $3)\n" if $debug;
372 if(/(([A-Z0-9]+)_R_[A-Z0-9_]+)/) {
373 next unless exists $csrc{$2};
375 if(!exists $rcodes{$1}) {
379 print STDERR "Reason: $1\t= $rcodes{$1} (lib: $2)\n" if $debug;
384 print STDERR " \n" if $debug;
386 # Now process each library in turn.
388 foreach $lib (keys %csrc)
390 my $hfile = $hinc{$lib};
391 my $cfile = $csrc{$lib};
392 if(!$fnew{$lib} && !$rnew{$lib}) {
393 next unless $rebuild;
395 print STDERR "$lib:\t\t$fnew{$lib} New Functions,";
396 print STDERR " $rnew{$lib} New Reasons.\n";
397 next unless $dowrite;
400 # If we get here then we have some new error codes so we
401 # need to rebuild the header file and C file.
403 # Make a sorted list of error and reason codes for later use.
405 my @function = sort grep(/^${lib}_/,keys %fcodes);
406 my @reasons = sort grep(/^${lib}_/,keys %rcodes);
408 # Rewrite the header file
410 if (open(IN, "<$hfile")) {
411 # Copy across the old file
414 last if (/BEGIN ERROR CODES/);
420 " * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.\n",
422 " * Licensed under the OpenSSL license (the \"License\"). You may not use\n",
423 " * this file except in compliance with the License. You can obtain a copy\n",
424 " * in the file LICENSE in the source distribution or at\n",
425 " * https://www.openssl.org/source/license.html\n",
428 "#ifndef HEADER_${lib}_ERR_H\n",
429 "#define HEADER_${lib}_ERR_H\n",
431 "#ifdef __cplusplus\n",
435 "/* BEGIN ERROR CODES */\n";
437 open (OUT, ">$hfile") || die "Can't Open File $hfile for writing\n";
443 * The following lines are auto generated by the script mkerr.pl. Any changes
444 * made after this point may be overwritten when the script is next run.
449 ${staticloader}void ERR_load_${lib}_strings(void);
454 ${staticloader}void ERR_load_${lib}_strings(void);
455 ${staticloader}void ERR_unload_${lib}_strings(void);
456 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line);
457 # define ${lib}err(f,r) ERR_${lib}_error((f),(r),OPENSSL_FILE,OPENSSL_LINE)
462 /* Error codes for the $lib functions. */
464 /* Function codes. */
467 foreach $i (@function) {
469 if($fcodes{$i} eq "X") {
470 $fassigned{$lib} =~ m/^:([^:]*):/;
472 if (!defined($findcode)) {
473 $findcode = $fmax{$lib};
475 while ($fassigned{$lib} =~ m/:$findcode:/) {
478 $fcodes{$i} = $findcode;
479 $fassigned{$lib} .= "$findcode:";
480 print STDERR "New Function code $i\n" if $debug;
482 printf OUT "# define $i%s $fcodes{$i}\n"," " x $z;
485 print OUT "\n/* Reason codes. */\n";
487 foreach $i (@reasons) {
489 if($rcodes{$i} eq "X") {
490 $rassigned{$lib} =~ m/^:([^:]*):/;
492 if (!defined($findcode)) {
493 $findcode = $rmax{$lib};
495 while ($rassigned{$lib} =~ m/:$findcode:/) {
498 $rcodes{$i} = $findcode;
499 $rassigned{$lib} .= "$findcode:";
500 print STDERR "New Reason code $i\n" if $debug;
502 printf OUT "# define $i%s $rcodes{$i}\n"," " x $z;
513 # Rewrite the C source file containing the error details.
515 # First, read any existing reason string definitions:
516 my %err_reason_strings;
517 if (open(IN,"<$cfile")) {
520 s|\R$||; # Better chomp
523 if (/{ERR_(FUNC|REASON)\(/) {
524 if (/\b(${lib}_R_\w*)\b.*\"(.*)\"/) {
525 $err_reason_strings{$1} = $2;
526 } elsif (/\b${lib}_F_(\w*)\b.*\"(.*)\"/) {
527 if (!exists $ftrans{$1} && ($1 ne $2)) {
528 print STDERR "WARNING: Mismatched function string $2\n";
542 $hfile =~ /([^\/]+)$/;
543 $hincf = "<${hprefix}$1>";
545 $hincf = "\"$hfile\"";
548 # If static we know the error code at compile time so use it
549 # in error definitions.
553 $pack_errcode = "ERR_LIB_${lib}";
559 $load_errcode = "ERR_LIB_${lib}";
563 open (OUT,">$cfile") || die "Can't open $cfile for writing";
567 * Copyright 1995-2016 The OpenSSL Project Authors. All Rights Reserved.
569 * Licensed under the OpenSSL license (the "License"). You may not use
570 * this file except in compliance with the License. You can obtain a copy
571 * in the file LICENSE in the source distribution or at
572 * https://www.openssl.org/source/license.html
576 * NOTE: this file was auto generated by the mkerr.pl script: any changes
577 * made to it will be overwritten when the script next updates this file,
578 * only reason strings will be preserved.
582 #include <openssl/err.h>
585 /* BEGIN ERROR CODES */
586 #ifndef OPENSSL_NO_ERR
588 # define ERR_FUNC(func) ERR_PACK($pack_errcode,func,0)
589 # define ERR_REASON(reason) ERR_PACK($pack_errcode,0,reason)
591 static ERR_STRING_DATA ${lib}_str_functs[] = {
593 # Add each function code: if a function name is found then use it.
594 foreach $i (@function) {
596 $i =~ /^${lib}_F_(\S+)$/;
598 if(exists $ftrans{$fn}) {
601 # print OUT "{ERR_PACK($pack_errcode,$i,0),\t\"$fn\"},\n";
602 if(length($i) + length($fn) > 58) {
603 print OUT " {ERR_FUNC($i),\n \"$fn\"},\n";
605 print OUT " {ERR_FUNC($i), \"$fn\"},\n";
612 static ERR_STRING_DATA ${lib}_str_reasons[] = {
614 # Add each reason code.
615 foreach $i (@reasons) {
617 my $rstr = "ERR_REASON($i)";
618 if (exists $err_reason_strings{$i}) {
619 $rn = $err_reason_strings{$i};
621 $i =~ /^${lib}_R_(\S+)$/;
623 $rn =~ tr/_[A-Z]/ [a-z]/;
625 if(length($i) + length($rn) > 56) {
626 print OUT " {${rstr},\n \"$rn\"},\n";
628 print OUT " {${rstr}, \"$rn\"},\n";
638 ${staticloader}void ERR_load_${lib}_strings(void)
640 #ifndef OPENSSL_NO_ERR
642 if (ERR_func_error_string(${lib}_str_functs[0].error) == NULL) {
643 ERR_load_strings($load_errcode, ${lib}_str_functs);
644 ERR_load_strings($load_errcode, ${lib}_str_reasons);
656 #ifdef ${lib}_LIB_NAME
657 static ERR_STRING_DATA ${lib}_lib_name[] = {
658 {0, ${lib}_LIB_NAME},
663 static int ${lib}_lib_error_code = 0;
664 static int ${lib}_error_init = 1;
666 ${staticloader}void ERR_load_${lib}_strings(void)
668 if (${lib}_lib_error_code == 0)
669 ${lib}_lib_error_code = ERR_get_next_error_library();
671 if (${lib}_error_init) {
672 ${lib}_error_init = 0;
673 #ifndef OPENSSL_NO_ERR
674 ERR_load_strings(${lib}_lib_error_code, ${lib}_str_functs);
675 ERR_load_strings(${lib}_lib_error_code, ${lib}_str_reasons);
678 #ifdef ${lib}_LIB_NAME
679 ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code, 0, 0);
680 ERR_load_strings(0, ${lib}_lib_name);
685 ${staticloader}void ERR_unload_${lib}_strings(void)
687 if (${lib}_error_init == 0) {
688 #ifndef OPENSSL_NO_ERR
689 ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_functs);
690 ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_reasons);
693 #ifdef ${lib}_LIB_NAME
694 ERR_unload_strings(0, ${lib}_lib_name);
696 ${lib}_error_init = 1;
700 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line)
702 if (${lib}_lib_error_code == 0)
703 ${lib}_lib_error_code = ERR_get_next_error_library();
704 ERR_PUT_error(${lib}_lib_error_code, function, reason, file, line);
711 undef %err_reason_strings;
714 if($debug && %notrans) {
715 print STDERR "The following function codes were not translated:\n";
716 foreach(sort keys %notrans)
722 # Make a list of unreferenced function and reason codes
724 foreach (keys %fcodes) {
725 push (@funref, $_) unless exists $ufcodes{$_};
728 foreach (keys %rcodes) {
729 push (@runref, $_) unless exists $urcodes{$_};
732 if($unref && @funref) {
733 print STDERR "The following function codes were not referenced:\n";
734 foreach(sort @funref)
740 if($unref && @runref) {
741 print STDERR "The following reason codes were not referenced:\n";
742 foreach(sort @runref)
749 print STDERR "There were errors, failing...\n\n";