2 # Copyright 1995-2018 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
10 # generate a .def file
12 # It does this by parsing the header files and looking for the
13 # prototyped functions: it then prunes the output.
15 # Intermediary files are created, call libcrypto.num and libssl.num,
16 # The format of these files is:
18 # routine-name nnnn vers info
20 # The "nnnn" and "vers" fields are the numeric id and version for the symbol
21 # respectively. The "info" part is actually a colon-separated string of fields
22 # with the following meaning:
24 # existence:platform:kind:algorithms
26 # - "existence" can be "EXIST" or "NOEXIST" depending on if the symbol is
27 # found somewhere in the source,
28 # - "platforms" is empty if it exists on all platforms, otherwise it contains
29 # comma-separated list of the platform, just as they are if the symbol exists
30 # for those platforms, or prepended with a "!" if not. This helps resolve
31 # symbol name variants for platforms where the names are too long for the
32 # compiler or linker, or if the systems is case insensitive and there is a
33 # clash, or the symbol is implemented differently (see
34 # EXPORT_VAR_AS_FUNCTION). This script assumes renaming of symbols is found
35 # in the file crypto/symhacks.h.
36 # The semantics for the platforms is that every item is checked against the
37 # environment. For the negative items ("!FOO"), if any of them is false
38 # (i.e. "FOO" is true) in the environment, the corresponding symbol can't be
39 # used. For the positive items, if all of them are false in the environment,
40 # the corresponding symbol can't be used. Any combination of positive and
41 # negative items are possible, and of course leave room for some redundancy.
42 # - "kind" is "FUNCTION" or "VARIABLE". The meaning of that is obvious.
43 # - "algorithms" is a comma-separated list of algorithm names. This helps
44 # exclude symbols that are part of an algorithm that some user wants to
50 use File::Spec::Functions;
53 use lib "$FindBin::Bin/perl";
60 my $crypto_num= catfile($config{sourcedir},"util","libcrypto.num");
61 my $ssl_num= catfile($config{sourcedir},"util","libssl.num");
70 my $do_checkexist = 0;
78 # Set this to make typesafe STACK definitions appear in DEF
79 my $safe_stack_def = 0;
81 my @known_platforms = ( "__FreeBSD__", "PERL5",
82 "EXPORT_VAR_AS_FUNCTION", "ZLIB", "_WIN32"
84 my @known_ossl_platforms = ( "UNIX", "VMS", "WIN32", "WINNT", "OS2" );
85 my @known_algorithms = ( # These are algorithms we know are guarded in relevant
86 # header files, but aren't actually disablable.
87 # Without these, this script will warn a lot.
89 # @disablables comes from configdata.pm
90 map { (my $x = uc $_) =~ s|-|_|g; $x; } @disablables,
91 # Deprecated functions. Not really algorithmss, but
92 # treated as such here for the sake of simplicity
99 # %disabled comes from configdata.pm
100 my %disabled_algorithms =
101 map { (my $x = uc $_) =~ s|-|_|g; $x => 1; } keys %disabled;
103 my $apiv = sprintf "%x%02x%02x", split(/\./, $config{api});
104 foreach (@known_algorithms) {
105 if (/^DEPRECATEDIN_(\d+)_(\d+)_(\d+)$/) {
106 my $depv = sprintf "%x%02x%02x", $1, $2, $3;
107 $disabled_algorithms{$_} = 1 if $apiv ge $depv;
113 foreach (@ARGV, split(/ /, $config{options}))
115 $debug=1 if $_ eq "debug";
116 $trace=1 if $_ eq "trace";
117 $verbose=1 if $_ eq "verbose";
118 $W32=1 if $_ eq "32";
119 die "win16 not supported" if $_ eq "16";
123 } elsif ($_ eq "linux") {
126 } elsif ($_ eq "aix") {
129 } elsif ($_ eq "VMS") {
132 if ($_ eq "zlib" || $_ eq "enable-zlib" || $_ eq "zlib-dynamic"
133 || $_ eq "enable-zlib-dynamic") {
137 $do_crypto=1 if $_ eq "libcrypto" || $_ eq "crypto";
138 $do_ssl=1 if $_ eq "libssl" || $_ eq "ssl";
140 $do_update=1 if $_ eq "update";
141 $do_rewrite=1 if $_ eq "rewrite";
142 $do_checkexist=1 if $_ eq "exist";
144 $libname = $unified_info{sharednames}->{libcrypto} if $do_crypto;
145 $libname = $unified_info{sharednames}->{libssl} if $do_ssl;
152 $libname="LIBCRYPTO";
156 if (!$do_ssl && !$do_crypto)
158 print STDERR "usage: $0 ( ssl | crypto )\n";
162 %ssl_list=&load_numbers($ssl_num);
164 %crypto_list=&load_numbers($crypto_num);
165 $max_crypto = $max_num;
167 my $ssl="include/openssl/ssl.h";
168 $ssl.=" include/openssl/sslerr.h";
169 $ssl.=" include/openssl/tls1.h";
170 $ssl.=" include/openssl/srtp.h";
172 # When scanning include/openssl, skip all SSL files and some internal ones.
174 foreach my $f ( split(/\s+/, $ssl) ) {
177 $skipthese{'include/openssl/conf_api.h'} = 1;
178 $skipthese{'include/openssl/ebcdic.h'} = 1;
179 $skipthese{'include/openssl/opensslconf.h'} = 1;
181 # We use headers found in include/openssl and include/internal only.
182 # The latter is needed so libssl.so/.dll/.exe can link properly.
183 my $crypto ="include/internal/dso.h";
184 $crypto.=" include/internal/o_dir.h";
185 $crypto.=" include/internal/o_str.h";
186 $crypto.=" include/internal/err.h";
187 $crypto.=" include/internal/sslconf.h";
188 foreach my $f ( glob(catfile($config{sourcedir},'include/openssl/*.h')) ) {
189 my $fn = "include/openssl/" . lc(basename($f));
190 $crypto .= " $fn" if !defined $skipthese{$fn};
193 my $symhacks="include/openssl/symhacks.h";
195 my @ssl_symbols = &do_defs("LIBSSL", $ssl, $symhacks);
196 my @crypto_symbols = &do_defs("LIBCRYPTO", $crypto, $symhacks);
202 &maybe_add_info("LIBSSL",*ssl_list,@ssl_symbols);
203 if ($do_rewrite == 1) {
204 open(OUT, ">$ssl_num");
205 &rewrite_numbers(*OUT,"LIBSSL",*ssl_list,@ssl_symbols);
207 open(OUT, ">>$ssl_num");
209 &update_numbers(*OUT,"LIBSSL",*ssl_list,$max_ssl,@ssl_symbols);
213 if($do_crypto == 1) {
215 &maybe_add_info("LIBCRYPTO",*crypto_list,@crypto_symbols);
216 if ($do_rewrite == 1) {
217 open(OUT, ">$crypto_num");
218 &rewrite_numbers(*OUT,"LIBCRYPTO",*crypto_list,@crypto_symbols);
220 open(OUT, ">>$crypto_num");
222 &update_numbers(*OUT,"LIBCRYPTO",*crypto_list,$max_crypto,@crypto_symbols);
226 } elsif ($do_checkexist) {
227 &check_existing(*ssl_list, @ssl_symbols)
229 &check_existing(*crypto_list, @crypto_symbols)
232 print STDERR "Nothing to do\n";
238 my($name,$files,$symhacksfile)=@_;
242 my %platform; # For anything undefined, we assume ""
243 my %kind; # For anything undefined, we assume "FUNCTION"
244 my %algorithm; # For anything undefined, we assume ""
246 my %variant_cnt; # To be able to allocate "name{n}" if "name"
247 # is the same name as the original.
249 my %unknown_algorithms = ();
252 foreach $file (split(/\s+/,$symhacksfile." ".$files))
254 my $fn = catfile($config{sourcedir},$file);
255 print STDERR "DEBUG: starting on $fn:\n" if $debug;
256 print STDERR "TRACE: start reading $fn\n" if $trace;
257 open(IN,"<$fn") || die "Can't open $fn, $!,";
258 my $line = "", my $def= "";
260 (map { $_ => 0 } @known_platforms),
261 (map { "OPENSSL_SYS_".$_ => 0 } @known_ossl_platforms),
262 (map { "OPENSSL_NO_".$_ => 0 } @known_algorithms),
263 (map { "OPENSSL_USE_".$_ => 0 } @known_algorithms),
264 (grep /^DEPRECATED_/, @known_algorithms),
271 my $symhacking = $file eq $symhacksfile;
272 my @current_platforms = ();
273 my @current_algorithms = ();
275 # params: symbol, alias, platforms, kind
276 # The reason to put this subroutine in a variable is that
277 # it will otherwise create it's own, unshared, version of
278 # %tag and %variant...
279 my $make_variant = sub
281 my ($s, $a, $p, $k) = @_;
284 print STDERR "DEBUG: make_variant: Entered with ",$s,", ",$a,", ",(defined($p)?$p:""),", ",(defined($k)?$k:""),"\n" if $debug;
289 map { $tag{$_} == 1 ? $_ : "" }
296 map { $tag{$_} == 1 ? $_ : "" }
301 map { $tag{"OPENSSL_SYS_".$_} == 1 ? $_ : "" }
302 @known_ossl_platforms));
303 print STDERR "DEBUG: make_variant: a1 = $a1; a2 = $a2\n" if $debug;
304 if ($a1 eq "") { $a1 = $a2; }
305 elsif ($a1 ne "" && $a2 ne "") { $a1 .= ",".$a2; }
308 if (!defined($variant_cnt{$s}))
310 $variant_cnt{$s} = 0;
313 $a .= "{$variant_cnt{$s}}";
315 my $toadd = $a.":".$a1.(defined($k)?":".$k:"");
316 my $togrep = $s.'(\{[0-9]+\})?:'.$a1.(defined($k)?":".$k:"");
317 if (!grep(/^$togrep$/,
318 split(/;/, defined($variant{$s})?$variant{$s}:""))) {
319 if (defined($variant{$s})) { $variant{$s} .= ";"; }
320 $variant{$s} .= $toadd;
322 print STDERR "DEBUG: make_variant: Exit with variant of ",$s," = ",$variant{$s},"\n" if $debug;
325 print STDERR "DEBUG: parsing ----------\n" if $debug;
327 s|\R$||; # Better chomp
329 #Inside a DEPRECATEDIN
330 $stored_multiline .= $_;
331 print STDERR "DEBUG: Continuing multiline DEPRECATEDIN: $stored_multiline\n" if $debug;
332 $parens = count_parens($stored_multiline);
334 $def .= do_deprecated($stored_multiline,
336 \@current_algorithms);
340 if (/\/\* Error codes for the \w+ functions\. \*\//)
351 $line = $`; # keep what was before the backslash
356 if (not /\*\//) { # multi-line comment...
357 $line = $_; # ... just accumulate
360 s/\/\*.*?\*\///gs;# wipe it
366 $cpp-- if /^#\s*endif/;
369 if (/^#.*ifdef.*cplusplus/) {
374 s/{[^{}]*}//gs; # ignore {} blocks
375 print STDERR "DEBUG: \$def=\"$def\"\n" if $debug && $def ne "";
376 print STDERR "DEBUG: \$_=\"$_\"\n" if $debug;
377 if (/^\#\s*if\s+OPENSSL_API_COMPAT\s*(\S)\s*(0x[0-9a-fA-F]{8})L\s*$/) {
380 if ($op ne '<' && $op ne '>=') {
381 die "$file unacceptable operator $op: $_\n";
383 my ($one, $major, $minor) =
387 my $t = "DEPRECATEDIN_${one}_${major}_${minor}";
390 $tag{$t}=($op eq '<' ? 1 : -1);
391 print STDERR "DEBUG: $file: found tag $t = $tag{$t}\n" if $debug;
392 } elsif (/^\#\s*ifndef\s+(.*)/) {
396 print STDERR "DEBUG: $file: found tag $1 = -1\n" if $debug;
397 } elsif (/^\#\s*if\s+!defined\s*\(([^\)]+)\)/) {
399 if (/^\#\s*if\s+(!defined\s*\(([^\)]+)\)(\s+\&\&\s+!defined\s*\(([^\)]+)\))*)$/) {
402 foreach $tmp_ (split '\&\&',$tmp_1) {
403 $tmp_ =~ /!defined\s*\(([^\)]+)\)/;
404 print STDERR "DEBUG: $file: found tag $1 = -1\n" if $debug;
409 print STDERR "Warning: $file: taking only '!defined($1)' of complicated expression: $_" if $verbose; # because it is O...
410 print STDERR "DEBUG: $file: found tag $1 = -1\n" if $debug;
414 } elsif (/^\#\s*ifdef\s+(\S*)/) {
418 print STDERR "DEBUG: $file: found tag $1 = 1\n" if $debug;
419 } elsif (/^\#\s*if\s+defined\s*\(([^\)]+)\)/) {
421 if (/^\#\s*if\s+(defined\s*\(([^\)]+)\)(\s+\|\|\s+defined\s*\(([^\)]+)\))*)$/) {
424 foreach $tmp_ (split '\|\|',$tmp_1) {
425 $tmp_ =~ /defined\s*\(([^\)]+)\)/;
426 print STDERR "DEBUG: $file: found tag $1 = 1\n" if $debug;
431 print STDERR "Warning: $file: taking only 'defined($1)' of complicated expression: $_\n" if $verbose; # because it is O...
432 print STDERR "DEBUG: $file: found tag $1 = 1\n" if $debug;
436 } elsif (/^\#\s*error\s+(\w+) is disabled\./) {
438 while($tag[$tag_i] ne "-") {
439 if ($tag[$tag_i] eq "OPENSSL_NO_".$1) {
440 $tag{$tag[$tag_i]}=2;
441 print STDERR "DEBUG: $file: changed tag $1 = 2\n" if $debug;
445 } elsif (/^\#\s*endif/) {
447 while($tag_i > 0 && $tag[$tag_i] ne "-") {
449 print STDERR "DEBUG: \$t=\"$t\"\n" if $debug;
455 print STDERR "DEBUG: $file: changed tag ",$t," = ",$tag{$t},"\n" if $debug;
457 if ($t =~ /^OPENSSL_NO_([A-Z0-9_]+)$/) {
459 } elsif($t =~ /^OPENSSL_USE_([A-Z0-9_]+)$/) {
465 && !grep(/^$t$/, @known_algorithms)) {
466 $unknown_algorithms{$t} = 1;
467 #print STDERR "DEBUG: Added as unknown algorithm: $t\n" if $debug;
472 } elsif (/^\#\s*else/) {
474 die "$file unmatched else\n" if $tag_i < 0;
475 while($tag[$tag_i] ne "-") {
478 print STDERR "DEBUG: $file: changed tag ",$t," = ",$tag{$t},"\n" if $debug;
481 } elsif (/^\#\s*if\s+1/) {
486 print STDERR "DEBUG: $file: found 1\n" if $debug;
487 } elsif (/^\#\s*if\s+0/) {
492 print STDERR "DEBUG: $file: found 0\n" if $debug;
493 } elsif (/^\#\s*if\s+/) {
494 #Some other unrecognized "if" style
496 print STDERR "Warning: $file: ignoring unrecognized expression: $_\n" if $verbose; # because it is O...
497 } elsif (/^\#\s*define\s+(\w+)\s+(\w+)/
498 && $symhacking && $tag{'TRUE'} != -1) {
499 # This is for aliasing. When we find an alias,
501 &$make_variant($1,$2);
502 print STDERR "DEBUG: $file: defined $1 = $2\n" if $debug;
507 map { $tag{$_} == 1 ? $_ :
508 $tag{$_} == -1 ? "!".$_ : "" }
510 push @current_platforms
512 map { $tag{"OPENSSL_SYS_".$_} == 1 ? $_ :
513 $tag{"OPENSSL_SYS_".$_} == -1 ? "!".$_ : "" }
514 @known_ossl_platforms);
515 @current_algorithms = ();
516 @current_algorithms =
518 map { $tag{"OPENSSL_NO_".$_} == -1 ? $_ : "" }
520 push @current_algorithms
522 map { $tag{"OPENSSL_USE_".$_} == 1 ? $_ : "" }
524 push @current_algorithms,
525 grep { /^DEPRECATEDIN_/ && $tag{$_} == 1 }
529 .join(',',@current_platforms).":"
530 .join(',',@current_algorithms).";";
533 if ($tag{'TRUE'} != -1) {
534 if (/^\s*DEFINE_STACK_OF\s*\(\s*(\w*)\s*\)/
535 || /^\s*DEFINE_STACK_OF_CONST\s*\(\s*(\w*)\s*\)/) {
537 } elsif (/^\s*DECLARE_ASN1_ENCODE_FUNCTIONS\s*\(\s*(\w*)\s*,\s*(\w*)\s*,\s*(\w*)\s*\)/) {
538 $def .= "int d2i_$3(void);";
539 $def .= "int i2d_$3(void);";
540 # Variant for platforms that do not
541 # have to access global variables
542 # in shared libraries through functions
545 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
546 .join(',',@current_algorithms).";";
547 $def .= "OPENSSL_EXTERN int $2_it;";
550 .join(',',@current_platforms).":"
551 .join(',',@current_algorithms).";";
552 # Variant for platforms that have to
553 # access global variables in shared
554 # libraries through functions
555 &$make_variant("$2_it","$2_it",
556 "EXPORT_VAR_AS_FUNCTION",
559 } elsif (/^\s*DECLARE_ASN1_FUNCTIONS_fname\s*\(\s*(\w*)\s*,\s*(\w*)\s*,\s*(\w*)\s*\)/) {
560 $def .= "int d2i_$3(void);";
561 $def .= "int i2d_$3(void);";
562 $def .= "int $3_free(void);";
563 $def .= "int $3_new(void);";
564 # Variant for platforms that do not
565 # have to access global variables
566 # in shared libraries through functions
569 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
570 .join(',',@current_algorithms).";";
571 $def .= "OPENSSL_EXTERN int $2_it;";
574 .join(',',@current_platforms).":"
575 .join(',',@current_algorithms).";";
576 # Variant for platforms that have to
577 # access global variables in shared
578 # libraries through functions
579 &$make_variant("$2_it","$2_it",
580 "EXPORT_VAR_AS_FUNCTION",
583 } elsif (/^\s*DECLARE_ASN1_FUNCTIONS\s*\(\s*(\w*)\s*\)/ ||
584 /^\s*DECLARE_ASN1_FUNCTIONS_const\s*\(\s*(\w*)\s*\)/) {
585 $def .= "int d2i_$1(void);";
586 $def .= "int i2d_$1(void);";
587 $def .= "int $1_free(void);";
588 $def .= "int $1_new(void);";
589 # Variant for platforms that do not
590 # have to access global variables
591 # in shared libraries through functions
594 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
595 .join(',',@current_algorithms).";";
596 $def .= "OPENSSL_EXTERN int $1_it;";
599 .join(',',@current_platforms).":"
600 .join(',',@current_algorithms).";";
601 # Variant for platforms that have to
602 # access global variables in shared
603 # libraries through functions
604 &$make_variant("$1_it","$1_it",
605 "EXPORT_VAR_AS_FUNCTION",
608 } elsif (/^\s*DECLARE_ASN1_ENCODE_FUNCTIONS_const\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
609 $def .= "int d2i_$2(void);";
610 $def .= "int i2d_$2(void);";
611 # Variant for platforms that do not
612 # have to access global variables
613 # in shared libraries through functions
616 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
617 .join(',',@current_algorithms).";";
618 $def .= "OPENSSL_EXTERN int $2_it;";
621 .join(',',@current_platforms).":"
622 .join(',',@current_algorithms).";";
623 # Variant for platforms that have to
624 # access global variables in shared
625 # libraries through functions
626 &$make_variant("$2_it","$2_it",
627 "EXPORT_VAR_AS_FUNCTION",
630 } elsif (/^\s*DECLARE_ASN1_ALLOC_FUNCTIONS\s*\(\s*(\w*)\s*\)/) {
631 $def .= "int $1_free(void);";
632 $def .= "int $1_new(void);";
634 } elsif (/^\s*DECLARE_ASN1_FUNCTIONS_name\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
635 $def .= "int d2i_$2(void);";
636 $def .= "int i2d_$2(void);";
637 $def .= "int $2_free(void);";
638 $def .= "int $2_new(void);";
639 # Variant for platforms that do not
640 # have to access global variables
641 # in shared libraries through functions
644 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
645 .join(',',@current_algorithms).";";
646 $def .= "OPENSSL_EXTERN int $2_it;";
649 .join(',',@current_platforms).":"
650 .join(',',@current_algorithms).";";
651 # Variant for platforms that have to
652 # access global variables in shared
653 # libraries through functions
654 &$make_variant("$2_it","$2_it",
655 "EXPORT_VAR_AS_FUNCTION",
658 } elsif (/^\s*DECLARE_ASN1_ITEM\s*\(\s*(\w*)\s*\)/) {
659 # Variant for platforms that do not
660 # have to access global variables
661 # in shared libraries through functions
664 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
665 .join(',',@current_algorithms).";";
666 $def .= "OPENSSL_EXTERN int $1_it;";
669 .join(',',@current_platforms).":"
670 .join(',',@current_algorithms).";";
671 # Variant for platforms that have to
672 # access global variables in shared
673 # libraries through functions
674 &$make_variant("$1_it","$1_it",
675 "EXPORT_VAR_AS_FUNCTION",
678 } elsif (/^\s*DECLARE_ASN1_NDEF_FUNCTION\s*\(\s*(\w*)\s*\)/) {
679 $def .= "int i2d_$1_NDEF(void);";
680 } elsif (/^\s*DECLARE_ASN1_SET_OF\s*\(\s*(\w*)\s*\)/) {
682 } elsif (/^\s*DECLARE_ASN1_PRINT_FUNCTION\s*\(\s*(\w*)\s*\)/) {
683 $def .= "int $1_print_ctx(void);";
685 } elsif (/^\s*DECLARE_ASN1_PRINT_FUNCTION_name\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
686 $def .= "int $2_print_ctx(void);";
688 } elsif (/^\s*DECLARE_PKCS12_STACK_OF\s*\(\s*(\w*)\s*\)/) {
690 } elsif (/^DECLARE_PEM_rw\s*\(\s*(\w*)\s*,/ ||
691 /^DECLARE_PEM_rw_cb\s*\(\s*(\w*)\s*,/ ||
692 /^DECLARE_PEM_rw_const\s*\(\s*(\w*)\s*,/ ) {
695 .join(',',@current_platforms).":"
696 .join(',',"STDIO",@current_algorithms).";";
697 $def .= "int PEM_read_$1(void);";
698 $def .= "int PEM_write_$1(void);";
701 .join(',',@current_platforms).":"
702 .join(',',@current_algorithms).";";
703 # Things that are everywhere
704 $def .= "int PEM_read_bio_$1(void);";
705 $def .= "int PEM_write_bio_$1(void);";
707 } elsif (/^DECLARE_PEM_write\s*\(\s*(\w*)\s*,/ ||
708 /^DECLARE_PEM_write_const\s*\(\s*(\w*)\s*,/ ||
709 /^DECLARE_PEM_write_cb\s*\(\s*(\w*)\s*,/ ) {
712 .join(',',@current_platforms).":"
713 .join(',',"STDIO",@current_algorithms).";";
714 $def .= "int PEM_write_$1(void);";
717 .join(',',@current_platforms).":"
718 .join(',',@current_algorithms).";";
719 # Things that are everywhere
720 $def .= "int PEM_write_bio_$1(void);";
722 } elsif (/^DECLARE_PEM_read\s*\(\s*(\w*)\s*,/ ||
723 /^DECLARE_PEM_read_cb\s*\(\s*(\w*)\s*,/ ) {
726 .join(',',@current_platforms).":"
727 .join(',',"STDIO",@current_algorithms).";";
728 $def .= "int PEM_read_$1(void);";
731 .join(',',@current_platforms).":"
732 .join(',',"STDIO",@current_algorithms).";";
733 # Things that are everywhere
734 $def .= "int PEM_read_bio_$1(void);";
736 } elsif (/^OPENSSL_DECLARE_GLOBAL\s*\(\s*(\w*)\s*,\s*(\w*)\s*\)/) {
737 # Variant for platforms that do not
738 # have to access global variables
739 # in shared libraries through functions
742 .join(',',"!EXPORT_VAR_AS_FUNCTION",@current_platforms).":"
743 .join(',',@current_algorithms).";";
744 $def .= "OPENSSL_EXTERN int _shadow_$2;";
747 .join(',',@current_platforms).":"
748 .join(',',@current_algorithms).";";
749 # Variant for platforms that have to
750 # access global variables in shared
751 # libraries through functions
752 &$make_variant("_shadow_$2","_shadow_$2",
753 "EXPORT_VAR_AS_FUNCTION",
755 } elsif (/^\s*DEPRECATEDIN/) {
756 $parens = count_parens($_);
758 $def .= do_deprecated($_,
760 \@current_algorithms);
762 $stored_multiline = $_;
763 print STDERR "DEBUG: Found multiline DEPRECATEDIN starting with: $stored_multiline\n" if $debug;
766 } elsif ($tag{'CONST_STRICT'} != 1) {
767 if (/\{|\/\*|\([^\)]*$/) {
776 die "$file: Unmatched tags\n" if $#tag >= 0;
781 print STDERR "DEBUG: postprocessing ----------\n" if $debug;
782 foreach (split /;/, $def) {
783 my $s; my $k = "FUNCTION"; my $p; my $a;
787 next if(/typedef\W/);
790 print STDERR "TRACE: processing $_\n" if $trace && !/^\#INFO:/;
791 # Reduce argument lists to empty ()
792 # fold round brackets recursively: (t(*v)(t),t) -> (t{}{},t) -> {}
793 my $nsubst = 1; # prevent infinite loop, e.g., on int fn()
794 while($nsubst && /\(.*\)/s) {
795 $nsubst = s/\([^\(\)]+\)/\{\}/gs;
796 $nsubst+= s/\(\s*\*\s*(\w+)\s*\{\}\s*\)/$1/gs; #(*f{}) -> f
798 # pretend as we didn't use curly braces: {} -> ()
801 s/STACK_OF\(\)/void/gs;
802 s/LHASH_OF\(\)/void/gs;
804 print STDERR "DEBUG: \$_ = \"$_\"\n" if $debug;
805 if (/^\#INFO:([^:]*):(.*)$/) {
808 print STDERR "DEBUG: found info on platforms ($plats) and algorithms ($algs)\n" if $debug;
810 } elsif (/^\s*OPENSSL_EXTERN\s.*?(\w+(\{[0-9]+\})?)(\[[0-9]*\])*\s*$/) {
813 print STDERR "DEBUG: found external variable $s\n" if $debug;
814 } elsif (/TYPEDEF_\w+_OF/s) {
816 } elsif (/(\w+)\s*\(\).*/s) { # first token prior [first] () is
817 $s = $1; # a function name!
818 print STDERR "DEBUG: found function $s\n" if $debug;
819 } elsif (/\(/ and not (/=/)) {
820 print STDERR "File $file: cannot parse: $_;\n";
833 &reduce_platforms((defined($platform{$s})?$platform{$s}.',':"").$p);
834 $algorithm{$s} .= ','.$a;
836 if (defined($variant{$s})) {
837 foreach $v (split /;/,$variant{$s}) {
838 (my $r, my $p, my $k) = split(/:/,$v);
839 my $ip = join ',',map({ /^!(.*)$/ ? $1 : "!".$_ } split /,/, $p);
841 if (!defined($k)) { $k = $kind{$s}; }
842 $kind{$r} = $k."(".$s.")";
843 $algorithm{$r} = $algorithm{$s};
844 $platform{$r} = &reduce_platforms($platform{$s}.",".$p.",".$p);
845 $platform{$s} = &reduce_platforms($platform{$s}.','.$ip.','.$ip);
846 print STDERR "DEBUG: \$variant{\"$s\"} = ",$v,"; \$r = $r; \$p = ",$platform{$r},"; \$a = ",$algorithm{$r},"; \$kind = ",$kind{$r},"\n" if $debug;
849 print STDERR "DEBUG: \$s = $s; \$p = ",$platform{$s},"; \$a = ",$algorithm{$s},"; \$kind = ",$kind{$s},"\n" if $debug;
853 # Prune the returned symbols
855 delete $syms{"bn_dump1"};
856 $platform{"BIO_s_log"} .= ",!WIN32,!macintosh";
858 $platform{"PEM_read_NS_CERT_SEQ"} = "VMS";
859 $platform{"PEM_write_NS_CERT_SEQ"} = "VMS";
860 $platform{"PEM_read_P8_PRIV_KEY_INFO"} = "VMS";
861 $platform{"PEM_write_P8_PRIV_KEY_INFO"} = "VMS";
865 push @ret, map { $_."\\".&info_string($_,"EXIST",
868 $algorithm{$_}) } keys %syms;
870 if (keys %unknown_algorithms) {
871 print STDERR "WARNING: mkdef.pl doesn't know the following algorithms:\n";
872 print STDERR "\t",join("\n\t",keys %unknown_algorithms),"\n";
877 # Param: string of comma-separated platform-specs.
880 my ($platforms) = @_;
881 my $pl = defined($platforms) ? $platforms : "";
882 my %p = map { $_ => 0 } split /,/, $pl;
885 print STDERR "DEBUG: Entered reduce_platforms with \"$platforms\"\n"
887 # We do this, because if there's code like the following, it really
888 # means the function exists in all cases and should therefore be
889 # everywhere. By increasing and decreasing, we may attain 0:
896 foreach $platform (split /,/, $pl) {
897 if ($platform =~ /^!(.*)$/) {
903 foreach $platform (keys %p) {
904 if ($p{$platform} == 0) { delete $p{$platform}; }
909 $ret = join(',',sort(map { $p{$_} < 0 ? "!".$_ : $_ } keys %p));
910 print STDERR "DEBUG: Exiting reduce_platforms with \"$ret\"\n"
917 (my $symbol, my $exist, my $platforms, my $kind, my $algorithms) = @_;
919 my %a = defined($algorithms) ?
920 map { $_ => 1 } split /,/, $algorithms : ();
921 my $k = defined($kind) ? $kind : "FUNCTION";
923 my $p = &reduce_platforms($platforms);
930 $ret .= ":".join(',',sort keys %a);
936 (my $name, *nums, my @symbols) = @_;
941 foreach $sym (@symbols) {
942 (my $s, my $i) = split /\\/, $sym;
943 if (defined($nums{$s})) {
944 $i =~ s/^(.*?:.*?:\w+)(\(\w+\))?/$1/;
945 (my $n, my $vers, my $dummy) = split /\\/, $nums{$s};
946 if (!defined($dummy) || $i ne $dummy) {
947 $nums{$s} = $n."\\".$vers."\\".$i;
949 print STDERR "DEBUG: maybe_add_info for $s: \"$dummy\" => \"$i\"\n" if $debug;
955 my @s=sort { &parse_number($nums{$a},"n") <=> &parse_number($nums{$b},"n") } keys %nums;
957 (my $n, my $vers, my $i) = split /\\/, $nums{$sym};
958 if (!defined($syms{$sym}) && $i !~ /^NOEXIST:/) {
960 print STDERR "DEBUG: maybe_add_info for $sym: -> undefined\n" if $debug;
964 print STDERR "$name: $new_info old symbols have updated info\n";
966 print STDERR "You should do a rewrite to fix this.\n";
972 # Param: string of comma-separated keywords, each possibly prefixed with a "!"
975 my ($keywords_txt,$platforms) = @_;
976 my (@keywords) = split /,/,$keywords_txt;
977 my ($falsesum, $truesum) = (0, 1);
982 my ($keyword,$platforms) = @_;
986 if ($keyword eq "UNIX" && $UNIX) { return 1; }
987 if ($keyword eq "VMS" && $VMS) { return 1; }
988 if ($keyword eq "WIN32" && $W32) { return 1; }
989 if ($keyword eq "_WIN32" && $W32) { return 1; }
990 if ($keyword eq "WINNT" && $NT) { return 1; }
992 # EXPORT_VAR_AS_FUNCTION means that global variables
993 # will be represented as functions.
994 if ($keyword eq "EXPORT_VAR_AS_FUNCTION" && $W32) {
997 if ($keyword eq "ZLIB" && $zlib) { return 1; }
1001 if ($disabled_algorithms{$keyword}) { return 0;}
1003 # Nothing recognise as true
1008 foreach $k (@keywords) {
1009 if ($k =~ /^!(.*)$/) {
1010 $falsesum += &recognise($1,$platforms);
1012 $truesum *= &recognise($k,$platforms);
1015 print STDERR "DEBUG: [",$#keywords,",",$#keywords < 0,"] is_valid($keywords_txt) => (\!$falsesum) && $truesum = ",(!$falsesum) && $truesum,"\n" if $debug;
1016 return (!$falsesum) && $truesum;
1030 my ($baseversion, $currversion) = get_openssl_version();
1032 open(IN,"<$name") || die "unable to open $name:$!\n";
1034 s|\R$||; # Better chomp
1038 if (defined $ret{$a[0]}) {
1039 # This is actually perfectly OK
1040 #print STDERR "Warning: Symbol '",$a[0],"' redefined. old=",$ret{$a[0]},", new=",$a[1],"\n";
1042 if ($max_num > $a[1]) {
1043 print STDERR "Warning: Number decreased from ",$max_num," to ",$a[1],"\n";
1045 elsif ($max_num == $a[1]) {
1046 # This is actually perfectly OK
1047 #print STDERR "Warning: Symbol ",$a[0]," has same number as previous ",$prev,": ",$a[1],"\n";
1048 if ($a[0] eq $prev) {
1050 $a[0] .= "{$prev_cnt}";
1057 # Existence will be proven later, in do_defs
1061 #Sanity check the version number
1062 if (defined $prevversion) {
1063 check_version_lte($prevversion, $a[2]);
1065 check_version_lte($a[2], $currversion);
1066 $prevversion = $a[2];
1067 $ret{$a[0]}=$a[1]."\\".$a[2]."\\".$a[3]; # \\ is a special marker
1069 $max_num = $a[1] if $a[1] > $max_num;
1073 print STDERR "Warning: $num_noinfo symbols were without info." if $verbose || !$do_rewrite;
1075 printf STDERR " The rewrite will fix this.\n" if $verbose;
1077 printf STDERR " You should do a rewrite to fix this.\n";
1086 (my $str, my $what) = @_;
1087 (my $n, my $v, my $i) = split(/\\/,$str);
1097 (*OUT,$name,*nums,@symbols)=@_;
1100 my @r = grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:\w+\(\w+\)/,@symbols);
1101 my $r; my %r; my %rsyms;
1103 (my $s, my $i) = split /\\/, $r;
1104 my $a = $1 if $i =~ /^.*?:.*?:\w+\((\w+)\)/;
1105 $i =~ s/^(.*?:.*?:\w+)\(\w+\)/$1/;
1106 $r{$a} = $s."\\".$i;
1111 foreach $_ (@symbols) {
1112 (my $n, my $i) = split /\\/;
1117 &parse_number($nums{$a},"n") <=> &parse_number($nums{$b},"n")
1121 (my $n, my $vers, my $i) = split /\\/, $nums{$sym};
1122 next if defined($i) && $i =~ /^.*?:.*?:\w+\(\w+\)/;
1123 next if defined($rsyms{$sym});
1124 print STDERR "DEBUG: rewrite_numbers for sym = ",$sym,": i = ",$i,", n = ",$n,", rsym{sym} = ",$rsyms{$sym},"syms{sym} = ",$syms{$sym},"\n" if $debug;
1125 $i="NOEXIST::FUNCTION:"
1126 if !defined($i) || $i eq "" || !defined($syms{$sym});
1128 $s2 =~ s/\{[0-9]+\}$//;
1129 printf OUT "%s%-39s %d\t%s\t%s\n","",$s2,$n,$vers,$i;
1130 if (exists $r{$sym}) {
1131 (my $s, $i) = split /\\/,$r{$sym};
1133 $s2 =~ s/\{[0-9]+\}$//;
1134 printf OUT "%s%-39s %d\t%s\t%s\n","",$s2,$n,$vers,$i;
1141 (*OUT,$name,*nums,my $start_num, my @symbols)=@_;
1146 ($basevers, $vers) = get_openssl_version();
1148 my @r = grep(/^\w+(\{[0-9]+\})?\\.*?:.*?:\w+\(\w+\)/,@symbols);
1149 my $r; my %r; my %rsyms;
1151 (my $s, my $i) = split /\\/, $r;
1152 my $a = $1 if $i =~ /^.*?:.*?:\w+\((\w+)\)/;
1153 $i =~ s/^(.*?:.*?:\w+)\(\w+\)/$1/;
1154 $r{$a} = $s."\\".$i;
1158 foreach $sym (@symbols) {
1159 (my $s, my $i) = $sym =~ /^(.*?)\\(.*)$/;
1160 next if $i =~ /^.*?:.*?:\w+\(\w+\)/;
1161 next if defined($rsyms{$sym});
1162 die "ERROR: Symbol $sym had no info attached to it."
1164 if (!exists $nums{$s}) {
1167 $s2 =~ s/\{[0-9]+\}$//;
1168 printf OUT "%s%-39s %d\t%s\t%s\n","",$s2, ++$start_num,$vers,$i;
1169 if (exists $r{$s}) {
1170 ($s, $i) = split /\\/,$r{$s};
1171 $s =~ s/\{[0-9]+\}$//;
1172 printf OUT "%s%-39s %d\t%s\t%s\n","",$s, $start_num,$vers,$i;
1177 print STDERR "$name: Added $new_syms new symbols\n";
1179 print STDERR "$name: No new symbols added\n";
1185 (*nums, my @symbols)=@_;
1186 my %existing; my @remaining;
1188 foreach $sym (@symbols) {
1189 (my $s, my $i) = $sym =~ /^(.*?)\\(.*)$/;
1192 foreach $sym (keys %nums) {
1193 if (!exists $existing{$sym}) {
1194 push @remaining, $sym;
1198 print STDERR "The following symbols do not seem to exist:\n";
1199 foreach $sym (@remaining) {
1200 print STDERR "\t",$sym,"\n";
1207 my $line = shift(@_);
1209 my $open = $line =~ tr/\(//;
1210 my $close = $line =~ tr/\)//;
1212 return $open - $close;
1215 #Parse opensslv.h to get the current version number. Also work out the base
1216 #version, i.e. the lowest version number that is binary compatible with this
1218 sub get_openssl_version()
1220 my $fn = catfile($config{sourcedir},"include","openssl","opensslv.h");
1221 open (IN, "$fn") || die "Can't open opensslv.h";
1224 if (/OPENSSL_VERSION_TEXT\s+"OpenSSL (\d\.\d\.)(\d[a-z]*)(-| )/) {
1226 (my $baseversion = $1) =~ s/\./_/g;
1228 return ($baseversion."0", $baseversion.$suffix);
1231 die "Can't find OpenSSL version number\n";
1234 #Given an OpenSSL version number, calculate the next version number. If the
1235 #version number gets to a.b.czz then we go to a.b.(c+1)
1236 sub get_next_version()
1238 my $thisversion = shift;
1240 my ($base, $letter) = $thisversion =~ /^(\d_\d_\d)([a-z]{0,2})$/;
1242 if ($letter eq "zz") {
1243 my $lastnum = substr($base, -1);
1244 return substr($base, 0, length($base)-1).(++$lastnum);
1246 return $base.get_next_letter($letter);
1249 #Given the letters off the end of an OpenSSL version string, calculate what
1250 #the letters for the next release would be.
1251 sub get_next_letter()
1253 my $thisletter = shift;
1254 my $baseletter = "";
1257 if ($thisletter eq "") {
1260 if ((length $thisletter) > 1) {
1261 ($baseletter, $endletter) = $thisletter =~ /([a-z]+)([a-z])/;
1263 $endletter = $thisletter;
1266 if ($endletter eq "z") {
1267 return $thisletter."a";
1269 return $baseletter.(++$endletter);
1273 #Check if a version is less than or equal to the current version. Its a fatal
1274 #error if not. They must also only differ in letters, or the last number (i.e.
1275 #the first two numbers must be the same)
1276 sub check_version_lte()
1278 my ($testversion, $currversion) = @_;
1283 my ($cvnums) = $currversion =~ /^(\d_\d_\d)[a-z]*$/;
1284 my ($tvnums) = $testversion =~ /^(\d_\d_\d)[a-z]*$/;
1286 #Die if we can't parse the version numbers or they don't look sane
1287 die "Invalid version number: $testversion and $currversion\n"
1288 if (!defined($cvnums) || !defined($tvnums)
1289 || length($cvnums) != 5
1290 || length($tvnums) != 5);
1292 #If the base versions (without letters) don't match check they only differ
1294 if ($cvnums ne $tvnums) {
1295 die "Invalid version number: $testversion "
1296 ."for current version $currversion\n"
1297 if (substr($cvnums, 0, 4) ne substr($tvnums, 0, 4));
1300 #If we get here then the base version (i.e. the numbers) are the same - they
1301 #only differ in the letters
1303 $lentv = length $testversion;
1304 $lencv = length $currversion;
1306 #If the testversion has more letters than the current version then it must
1307 #be later (or malformed)
1308 if ($lentv > $lencv) {
1309 die "Invalid version number: $testversion "
1310 ."is greater than $currversion\n";
1313 #Get the last letter from the current version
1314 my ($cvletter) = $currversion =~ /([a-z])$/;
1315 if (defined $cvletter) {
1316 ($cvbase) = $currversion =~ /(\d_\d_\d[a-z]*)$cvletter$/;
1318 $cvbase = $currversion;
1320 die "Unable to parse version number $currversion" if (!defined $cvbase);
1322 my ($tvletter) = $testversion =~ /([a-z])$/;
1323 if (defined $tvletter) {
1324 ($tvbase) = $testversion =~ /(\d_\d_\d[a-z]*)$tvletter$/;
1326 $tvbase = $testversion;
1328 die "Unable to parse version number $testversion" if (!defined $tvbase);
1330 if ($lencv > $lentv) {
1331 #If current version has more letters than testversion then testversion
1332 #minus the final letter must be a substring of the current version
1333 die "Invalid version number $testversion "
1334 ."is greater than $currversion or is invalid\n"
1335 if (index($cvbase, $tvbase) != 0);
1337 #If both versions have the same number of letters then they must be
1338 #equal up to the last letter, and the last letter in testversion must
1339 #be less than or equal to the last letter in current version.
1340 die "Invalid version number $testversion "
1341 ."is greater than $currversion\n"
1342 if (($cvbase ne $tvbase) && ($tvletter gt $cvletter));
1348 my ($decl, $plats, $algs) = @_;
1349 $decl =~ /^\s*(DEPRECATEDIN_\d+_\d+_\d+)\s*\((.*)\)\s*$/
1350 or die "Bad DEPRECATEDIN: $decl\n";
1351 my $info1 .= "#INFO:";
1352 $info1 .= join(',', @{$plats}) . ":";
1354 $info1 .= join(',',@{$algs}, $1) . ";";
1355 $info2 .= join(',',@{$algs}) . ";";
1356 return $info1 . $2 . ";" . $info2;