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";
17 my $staticloader = "";
19 my $YEAR = @t[5] + 1900;
25 my $year = (localtime)[5] + 1900;
31 $config = shift @ARGV;
32 } elsif($arg eq "-hprefix") {
34 $hprefix = shift @ARGV;
35 } elsif($arg eq "-debug") {
39 } elsif($arg eq "-rebuild") {
42 } elsif($arg eq "-recurse") {
45 } elsif($arg eq "-reindex") {
48 } elsif($arg eq "-nostatic") {
51 } elsif($arg eq "-staticloader") {
52 $staticloader = "static ";
54 } elsif($arg eq "-unref") {
57 } elsif($arg eq "-write") {
60 } elsif($arg eq "-help" || $arg eq "-h" || $arg eq "-?" || $arg eq "--help") {
62 mkerr.pl [options] ...
66 -conf F Use the config file F instead of the default one:
69 -hprefix P Prepend the filenames in generated #include <header>
70 statements with prefix P. Default: 'openssl/' (without
71 the quotes, naturally)
72 NOTE: not used any more because our include directory
73 structure has changed.
75 -debug Turn on debugging verbose output on stderr.
77 -rebuild Rebuild all header and C source files, irrespective of the
78 fact if any error or function codes have been added/removed.
79 Default: only update files for libraries which saw change
80 (of course, this requires '-write' as well, or no
81 files will be touched!)
83 -recurse scan a preconfigured set of directories / files for error and
85 (<crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <apps/*.c>)
86 When this option is NOT specified, the filelist is taken from
87 the commandline instead. Here, wildcards may be embedded. (Be
88 sure to escape those to prevent the shell from expanding them
89 for you when you wish mkerr.pl to do so instead.)
90 Default: take file list to scan from the command line.
92 -reindex Discard the numeric values previously assigned to the error
93 and function codes as extracted from the scanned header files;
94 instead renumber all of them starting from 100. (Note that
95 the numbers assigned through 'R' records in the config file
97 Default: keep previously assigned numbers. (You are warned
98 when collisions are detected.)
100 -nostatic Generates a different source code, where these additional
101 functions are generated for each library specified in the
103 void ERR_load_<LIB>_strings(void);
104 void ERR_unload_<LIB>_strings(void);
105 void ERR_<LIB>_error(int f, int r, char *fn, int ln);
106 #define <LIB>err(f,r) ERR_<LIB>_error(f,r,OPENSSL_FILE,OPENSSL_LINE)
107 while the code facilitates the use of these in an environment
108 where the error support routines are dynamically loaded at
110 Default: 'static' code generation.
112 -staticloader Prefix generated functions with the 'static' scope modifier.
113 Default: don't write any scope modifier prefix.
115 -unref Print out unreferenced function and reason codes.
117 -write Actually (over)write the generated code to the header and C
118 source files as assigned to each library through the config
120 Default: don't write.
122 -help / -h / -? / --help Show this help text.
124 ... Additional arguments are added to the file list to scan,
125 assuming '-recurse' was NOT specified on the command line.
135 @source = ( <crypto/*.c>, <crypto/*/*.c>, <ssl/*.c>, <ssl/*/*.c> )
140 # Read in the config file
142 open(IN, "<$config") || die "Can't open config file $config";
148 if(/^L\s+(\S+)\s+(\S+)\s+(\S+)/) {
156 $fassigned{$1} = ":";
157 $rassigned{$1} = ":";
161 } elsif (/^F\s+(\S+)/) {
162 # Add extra function with $1
163 } elsif (/^R\s+(\S+)\s+(\S+)/) {
171 # Scan each header file in turn and make a list of error codes
174 while (($hdr, $lib) = each %libinc)
176 next if($hdr eq "NONE");
177 print STDERR "Scanning header file $hdr\n" if $debug;
178 my $line = "", $def= "", $linenr = 0, $gotfile = 0, $cpp = 0;
179 if (open(IN, "<$hdr")) {
183 print STDERR "line: $linenr\r" if $debug;
185 last if(/BEGIN\s+ERROR\s+CODES/);
197 if (not /\*\//) { # multiline comment...
198 $line = $_; # ... just accumulate
201 s/\/\*.*?\*\///gs; # wipe it
207 $cpp-- if /^#\s*endif/;
210 $cpp = 1 if /^#.*ifdef.*cplusplus/; # skip "C" declaration
212 next if (/^\#/); # skip preprocessor directives
214 s/{[^{}]*}//gs; # ignore {} blocks
216 if (/\{|\/\*/) { # Add a } so editor works...
224 print STDERR " \r" if $debug;
226 # Delete any DECLARE_ macros
227 $def =~ s/DECLARE_\w+\([\w,\s]+\)//gs;
228 foreach (split /;/, $def) {
230 print STDERR "def: $defnr\r" if $debug;
232 # The goal is to collect function names from function declarations.
237 # Skip over recognized non-function declarations
238 next if(/typedef\W/ or /DECLARE_STACK_OF/ or /TYPEDEF_.*_OF/);
240 # Remove STACK_OF(foo)
241 s/STACK_OF\(\w+\)/void/;
243 # Reduce argument lists to empty ()
244 # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {}
246 s/\([^\(\)]+\)/\{\}/gs;
247 s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f
249 # pretend as we didn't use curly braces: {} -> ()
252 if (/(\w+)\s*\(\).*/s) { # first token prior [first] () is
253 my $name = $1; # a function name!
254 $name =~ tr/[a-z]/[A-Z]/;
256 } elsif (/[\(\)]/ and not (/=/)) {
257 print STDERR "Header $hdr: cannot parse: $_;\n";
261 print STDERR " \r" if $debug;
265 # Scan function and reason codes and store them: keep a note of the
270 if(/^\#\s*define\s+(\S+)\s+(\S+)/) {
273 next if $name =~ /^${lib}err/;
274 unless($name =~ /^${lib}_([RF])_(\w+)$/) {
275 print STDERR "Invalid error code $name\n";
279 $rcodes{$name} = $code;
280 if ($rassigned{$lib} =~ /:$code:/) {
281 print STDERR "!! ERROR: $lib reason code $code assigned twice (collision at $name)\n";
284 $rassigned{$lib} .= "$code:";
285 if(!(exists $rextra{$name}) &&
286 ($code > $rmax{$lib}) ) {
290 if ($fassigned{$lib} =~ /:$code:/) {
291 print STDERR "!! ERROR: $lib function code $code assigned twice (collision at $name)\n";
294 $fassigned{$lib} .= "$code:";
295 if($code > $fmax{$lib}) {
298 $fcodes{$name} = $code;
305 if (defined($fmax{$lib})) {
306 print STDERR "Max function code fmax" . "{" . "$lib" . "} = $fmax{$lib}\n";
307 $fassigned{$lib} =~ m/^:(.*):$/;
308 @fassigned = sort {$a <=> $b} split(":", $1);
309 print STDERR " @fassigned\n";
311 if (defined($rmax{$lib})) {
312 print STDERR "Max reason code rmax" . "{" . "$lib" . "} = $rmax{$lib}\n";
313 $rassigned{$lib} =~ m/^:(.*):$/;
314 @rassigned = sort {$a <=> $b} split(":", $1);
315 print STDERR " @rassigned\n";
320 if ($rmax{$lib} >= 1000) {
321 print STDERR "!! ERROR: SSL error codes 1000+ are reserved for alerts.\n";
322 print STDERR "!! Any new alerts must be added to $config.\n";
330 # Scan each C source file and look for function and reason codes
331 # This is done by looking for strings that "look like" function or
332 # reason codes: basically anything consisting of all upper case and
333 # numerics which has _F_ or _R_ in it and which has the name of an
334 # error library at the start. This seems to work fine except for the
335 # oddly named structure BIO_F_CTX which needs to be ignored.
336 # If a code doesn't exist in list compiled from headers then mark it
337 # with the value "X" as a place holder to give it a value later.
338 # Store all function and reason codes found in %ufcodes and %urcodes
339 # so all those unreferenced can be printed out.
342 foreach $file (@source) {
343 # Don't parse the error source file.
344 next if exists $cskip{$file};
345 print STDERR "File loaded: ".$file."\r" if $debug;
346 open(IN, "<$file") || die "Can't open source file $file\n";
350 # skip obsoleted source files entirely!
351 last if(/^#error\s+obsolete/);
353 if (!/;$/ && /^\**([a-zA-Z_].*[\s*])?([A-Za-z_0-9]+)\(.*([),]|$)/)
355 /^([^()]*(\([^()]*\)[^()]*)*)\(/;
356 $1 =~ /([A-Za-z_0-9]*)$/;
360 if(/(([A-Z0-9]+)_F_([A-Z0-9_]+))/) {
361 next unless exists $csrc{$2};
362 next if($1 eq "BIO_F_BUFFER_CTX");
364 if(!exists $fcodes{$1}) {
368 $ftrans{$3} = $func unless exists $ftrans{$3};
369 if (uc $func ne $3) {
370 print STDERR "ERROR: mismatch $file:$linenr $func:$3\n";
373 print STDERR "Function: $1\t= $fcodes{$1} (lib: $2, name: $3)\n" if $debug;
375 if(/(([A-Z0-9]+)_R_[A-Z0-9_]+)/) {
376 next unless exists $csrc{$2};
378 if(!exists $rcodes{$1}) {
382 print STDERR "Reason: $1\t= $rcodes{$1} (lib: $2)\n" if $debug;
387 print STDERR " \n" if $debug;
389 # Now process each library in turn.
391 foreach $lib (keys %csrc)
393 my $hfile = $hinc{$lib};
394 my $cfile = $csrc{$lib};
395 if(!$fnew{$lib} && !$rnew{$lib}) {
396 next unless $rebuild;
398 print STDERR "$lib:\t\t$fnew{$lib} New Functions,";
399 print STDERR " $rnew{$lib} New Reasons.\n";
400 next unless $dowrite;
403 # If we get here then we have some new error codes so we
404 # need to rebuild the header file and C file.
406 # Make a sorted list of error and reason codes for later use.
408 my @function = sort grep(/^${lib}_/,keys %fcodes);
409 my @reasons = sort grep(/^${lib}_/,keys %rcodes);
411 # Rewrite the header file
415 if (open(IN, "<$hfile")) {
416 # Copy across the old file
418 $cplusplus = $cpp if /^#.*ifdef.*cplusplus/;
420 $cpp-- if /^#\s*endif/;
422 last if (/BEGIN ERROR CODES/);
430 " * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.\n",
432 " * Licensed under the OpenSSL license (the \"License\"). You may not use\n",
433 " * this file except in compliance with the License. You can obtain a copy\n",
434 " * in the file LICENSE in the source distribution or at\n",
435 " * https://www.openssl.org/source/license.html\n",
438 "#ifndef HEADER_${lib}_ERR_H\n",
439 "# define HEADER_${lib}_ERR_H\n",
441 "# ifdef __cplusplus\n",
445 "/* BEGIN ERROR CODES */\n";
447 open (OUT, ">$hfile") || die "Can't Open File $hfile for writing\n";
453 * The following lines are auto generated by the script mkerr.pl. Any changes
454 * made after this point may be overwritten when the script is next run.
460 ${staticloader}int ERR_load_${lib}_strings(void);
465 ${staticloader}int ERR_load_${lib}_strings(void);
466 ${staticloader}void ERR_unload_${lib}_strings(void);
467 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line);
468 # define ${lib}err(f,r) ERR_${lib}_error((f),(r),OPENSSL_FILE,OPENSSL_LINE)
473 /* Error codes for the $lib functions. */
475 /* Function codes. */
478 foreach $i (@function) {
480 if($fcodes{$i} eq "X") {
481 $fassigned{$lib} =~ m/^:([^:]*):/;
483 if (!defined($findcode)) {
484 $findcode = $fmax{$lib};
486 while ($fassigned{$lib} =~ m/:$findcode:/) {
489 $fcodes{$i} = $findcode;
490 $fassigned{$lib} .= "$findcode:";
491 print STDERR "New Function code $i\n" if $debug;
493 printf OUT "# define $i%s $fcodes{$i}\n"," " x $z;
496 print OUT "\n/* Reason codes. */\n";
498 foreach $i (@reasons) {
500 if($rcodes{$i} eq "X") {
501 $rassigned{$lib} =~ m/^:([^:]*):/;
503 if (!defined($findcode)) {
504 $findcode = $rmax{$lib};
506 while ($rassigned{$lib} =~ m/:$findcode:/) {
509 $rcodes{$i} = $findcode;
510 $rassigned{$lib} .= "$findcode:";
511 print STDERR "New Reason code $i\n" if $debug;
513 printf OUT "# define $i%s $rcodes{$i}\n"," " x $z;
519 if ($cplusplus == $cpp) {
520 print OUT "#", " "x$cpp, "ifdef __cplusplus\n";
522 print OUT "#", " "x$cpp, "endif\n";
525 print OUT "#", " "x$cpp, "endif\n";
530 # Rewrite the C source file containing the error details.
532 # First, read any existing reason string definitions:
533 my %err_reason_strings;
534 if (open(IN,"<$cfile")) {
537 s|\R$||; # Better chomp
540 if (/{ERR_(FUNC|REASON)\(/) {
541 if (/\b(${lib}_R_\w*)\b.*\"(.*)\"/) {
542 $err_reason_strings{$1} = $2;
543 } elsif (/\b${lib}_F_(\w*)\b.*\"(.*)\"/) {
544 if (!exists $ftrans{$1} && ($1 ne $2)) {
545 print STDERR "WARNING: Mismatched function string $2\n";
560 $hincf =~ s|.*include/||;
561 if ($hincf =~ m|^openssl/|) {
562 $hincf = "<${hincf}>";
564 $hincf = "\"${hincf}\"";
567 $hincf = "\"$hfile\"";
570 # If static we know the error code at compile time so use it
571 # in error definitions.
575 $pack_errcode = "ERR_LIB_${lib}";
581 $load_errcode = "ERR_LIB_${lib}";
585 open (OUT,">$cfile") || die "Can't open $cfile for writing";
589 * Generated by util/mkerr.pl DO NOT EDIT
590 * Copyright 1995-$YEAR The OpenSSL Project Authors. All Rights Reserved.
592 * Licensed under the OpenSSL license (the "License"). You may not use
593 * this file except in compliance with the License. You can obtain a copy
594 * in the file LICENSE in the source distribution or at
595 * https://www.openssl.org/source/license.html
599 #include <openssl/err.h>
602 /* BEGIN ERROR CODES */
603 #ifndef OPENSSL_NO_ERR
605 # define ERR_FUNC(func) ERR_PACK($pack_errcode,func,0)
606 # define ERR_REASON(reason) ERR_PACK($pack_errcode,0,reason)
608 static ERR_STRING_DATA ${lib}_str_functs[] = {
610 # Add each function code: if a function name is found then use it.
611 foreach $i (@function) {
613 $i =~ /^${lib}_F_(\S+)$/;
615 if(exists $ftrans{$fn}) {
618 # print OUT "{ERR_PACK($pack_errcode,$i,0),\t\"$fn\"},\n";
619 if(length($i) + length($fn) > 57) {
620 print OUT " {ERR_FUNC($i),\n \"$fn\"},\n";
622 print OUT " {ERR_FUNC($i), \"$fn\"},\n";
629 static ERR_STRING_DATA ${lib}_str_reasons[] = {
631 # Add each reason code.
632 foreach $i (@reasons) {
634 my $rstr = "ERR_REASON($i)";
635 if (exists $err_reason_strings{$i}) {
636 $rn = $err_reason_strings{$i};
638 $i =~ /^${lib}_R_(\S+)$/;
640 $rn =~ tr/_[A-Z]/ [a-z]/;
642 if(length($i) + length($rn) > 55) {
643 print OUT " {${rstr},\n \"$rn\"},\n";
645 print OUT " {${rstr}, \"$rn\"},\n";
655 ${staticloader}int ERR_load_${lib}_strings(void)
657 #ifndef OPENSSL_NO_ERR
659 if (ERR_func_error_string(${lib}_str_functs[0].error) == NULL) {
660 ERR_load_strings($load_errcode, ${lib}_str_functs);
661 ERR_load_strings($load_errcode, ${lib}_str_reasons);
674 #ifdef ${lib}_LIB_NAME
675 static ERR_STRING_DATA ${lib}_lib_name[] = {
676 {0, ${lib}_LIB_NAME},
681 static int ${lib}_lib_error_code = 0;
682 static int ${lib}_error_init = 1;
684 ${staticloader}int ERR_load_${lib}_strings(void)
686 if (${lib}_lib_error_code == 0)
687 ${lib}_lib_error_code = ERR_get_next_error_library();
689 if (${lib}_error_init) {
690 ${lib}_error_init = 0;
691 #ifndef OPENSSL_NO_ERR
692 ERR_load_strings(${lib}_lib_error_code, ${lib}_str_functs);
693 ERR_load_strings(${lib}_lib_error_code, ${lib}_str_reasons);
696 #ifdef ${lib}_LIB_NAME
697 ${lib}_lib_name->error = ERR_PACK(${lib}_lib_error_code, 0, 0);
698 ERR_load_strings(0, ${lib}_lib_name);
704 ${staticloader}void ERR_unload_${lib}_strings(void)
706 if (${lib}_error_init == 0) {
707 #ifndef OPENSSL_NO_ERR
708 ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_functs);
709 ERR_unload_strings(${lib}_lib_error_code, ${lib}_str_reasons);
712 #ifdef ${lib}_LIB_NAME
713 ERR_unload_strings(0, ${lib}_lib_name);
715 ${lib}_error_init = 1;
719 ${staticloader}void ERR_${lib}_error(int function, int reason, char *file, int line)
721 if (${lib}_lib_error_code == 0)
722 ${lib}_lib_error_code = ERR_get_next_error_library();
723 ERR_PUT_error(${lib}_lib_error_code, function, reason, file, line);
730 undef %err_reason_strings;
733 if($debug && %notrans) {
734 print STDERR "The following function codes were not translated:\n";
735 foreach(sort keys %notrans)
741 # Make a list of unreferenced function and reason codes
743 foreach (keys %fcodes) {
744 push (@funref, $_) unless exists $ufcodes{$_};
747 foreach (keys %rcodes) {
748 push (@runref, $_) unless exists $urcodes{$_};
751 if($unref && @funref) {
752 print STDERR "The following function codes were not referenced:\n";
753 foreach(sort @funref)
759 if($unref && @runref) {
760 print STDERR "The following reason codes were not referenced:\n";
761 foreach(sort @runref)
768 print STDERR "There were errors, failing...\n\n";