--- /dev/null
+#!/bin/env perl
+#
+# Quick and dirty utility to help assemble the mandated (but otherwise
+# useless) API documentation. We get the list of external function
+# symbols from fipscanister.o, pair those with the source file names
+# (from ./fips/fipssyms.h), and map to the object file name containing
+# them.
+#
+# Requires the "nm" and "find" utilities.
+# Execure from the root of the FIPS module source code workarea
+
+use HTML::Entities;
+use File::Basename;
+
+$here = dirname($0);
+require "$here/api_fns.pm";
+
+$_direction_question = ''; # Set to '?' to show "<-?", "<->?" for uncertain directions
+
+print STDERR "Info: finding FIPS renames and reimplementations of OpenSSL symbols\n";
+# Get mapping of old (source code) to new (live as renamed) symbols
+foreach $file ("./fips/fipssyms.h") {
+ open(IN, $file) || die "Error opening $file";
+ # grab pairs until assembler symbols
+ my $buf = '';
+ my $reimplementations = 1; # When 1, we're looking at reimplementations
+ # (not renames) of OpenSSL functions. They
+ # still have to be saved to get the API.
+ while (<IN>) {
+ $reimplementations = 0 if m|^\s*/\*\sRename\ssymbols\s|;
+
+ if ($buf) {
+ $_ = $buf . $_;
+ $buf = '';
+ }
+ if (s/\\\n$//) {
+ $buf = $_;
+ next;
+ }
+ if (m/\(/) {
+ ($oldname, $newname) = m/#define\s+(\S+)\(.*\)\s+(\S+)\(.*\)/;
+ } else {
+ ($oldname, $newname) = m/#define\s+(\S+)\s+(\S+)/;
+ }
+
+ $oldname || next;
+ if (!$reimplementations) {
+ $oldname{$newname} = $oldname;
+ }
+ $oldimpl{$newname} = $oldname;
+ last if (/assembler/)
+ }
+ close(IN);
+ # %oldname is the mapping of new function names to old
+ print "<!-- Total of ", scalar(keys %oldname), " mapped symbols in $file -->\n";
+}
+
+print STDERR "Info: finding FIPS symbols in object files\n";
+# generate list of external function names in fipscanister.o
+$file = "./fips/fipscanister.o";
+for (`nm -g --defined-only -p -o $file`) {
+ chomp;
+ s/^\S+ T // || next;
+ m/^fips_/ && next;
+ $fipssyms{$_}++;
+ $objname =~ s/\.o$/\.\[o\|c\]/;
+ $objname{$symname} = $objname;
+}
+# keys %fipssyms is the list of module functions
+print "<!-- Total of ", scalar(keys %fipssyms), " functions in $file -->\n";
+
+# grab filename to symbol name mapping, each line is of the format
+# ./fips/sha/fips_sha1_selftest.o:00000000 T FIPS_selftest_sha1
+# discard the offset and type ":00000000 T".
+for (`find . -name '*.o' \\! -name 'fipscanister.o' -exec nm -g --defined-only -p -o {} \\;`) {
+ ($objname, $symname) = m/^(\S+):\S+\s+T+\s+(\S+)/;
+ $objname || next;
+# $fipssyms{$symname} || next;
+ $objname =~ s/\.o$/\.\[o\|c\]/;
+ $objname{$symname} = $objname;
+ }
+# %objname is the mapping of new symbol name to (source/object) file name
+print "<!-- Total of ", scalar(keys %objname), " functions found in files -->\n";
+
+print STDERR "Info: finding declarations in header files\n";
+
+# grab filenames in include/openssl, run each of them through
+# get_function_declarations_from_file (defined in api_fns.pl)
+# and collect the result.
+%declarations = ();
+while (<include/openssl/*.h ./crypto/cryptlib.h>) {
+ my %decls = api_data::get_function_declaration_strings_from_file($_);
+ map { $declarations{$_} = $decls{$_} } keys %decls;
+}
+# %declarations is the mapping of old symbol name to their declaration
+print "<!-- Total of ", scalar(keys %declarations), " declarations found in header files -->\n";
+
+# Add the markers FIPS_text_start and FIPS_text_end
+$declarations{FIPS_text_start} = "void *FIPS_text_start()";
+$declarations{FIPS_text_end} = "void *FIPS_text_end()";
+
+
+# Read list of API names obtained from edited "nm -g fipscanister.o"
+$spill = 0;
+sub printer {
+ foreach (@_) {
+ if ($_->{kind} >= 0) {
+ if ($spill) {
+ print " " x $indent;
+ print "kind: ",$_->{kind} ? "function" : "variable","\n";
+ print " " x $indent;
+ print "sym: ",$_->{sym},"\n";
+ print " " x $indent;
+ print "type: ",$_->{type},"\n";
+ }
+ if ($_->{kind}) {
+ $c = 0;
+ map {
+ if ($spill) {
+ print " " x $indent;
+ printf "param %d:\n", ++$c;
+ }
+ $indent += 2;
+ printer($_);
+ my $direction = $_->{direction};
+ if (!$_direction_question) {
+ $direction =~ s/<-\? <->\?/<->/;
+ $direction =~ s/\?//g;
+ }
+ print " " x $indent,$direction," ",$_->{sym},"\n";
+ $indent -= 2;
+ } @{$_->{params}};
+ if ($_->{type} !~ m/^\s*void\s*$/) {
+ print " " x $indent;
+ print "<- Return\n";
+ }
+ }
+ } else {
+ if ($spill) {
+ print " " x $indent;
+ print "decl: ",$_->{decl},"\n";
+ }
+ }
+ }
+}
+
+sub html_printer {
+ my $print_mode = shift; # 0 = print declaration with symbol in bold,
+ # call recursively with 1 for each parameter,
+ # call recursively with 2 for each parameter
+ # 1 = print declaration with sym grey background,
+ # call recursivelt with 3 for each parameter
+ # 2 = just print declaration
+ my $d = shift; # Parsed declaration
+ my $s = '';
+
+ if ($print_mode == 0) {
+ $d->{sym} || return $s;
+ my $h = "<hr><br />\n";
+ $h .= $d->{sym} . ($d->{symcomment} ? " " . $d->{symcomment} : "");
+ $h .= " in file " . $d->{objfile} . "<br />\n<br />\n";
+
+ $s .= '<b>' . $d->{sym} . '</b>';
+ if ($d->{kind} == 1) {
+ $s .= '(';
+ $s .= join(', ',
+ map {
+ html_printer(1,$_);
+ } @{$d->{params}});
+ $s .= ')';
+ }
+ my $t = $d->{type};
+ $t =~ s/\?/$s/;
+ $s = $t;
+ if ($d->{kind} == 1) {
+ map {
+ my $direction = $_->{direction};
+ if (!$_direction_question) {
+ $direction =~ s/<-\? <->\?/<->/;
+ $direction =~ s/\?//g;
+ }
+ $s .= "<br />\n";
+ $s .= encode_entities($direction
+ . "\xA0" x (9 - length($direction)));
+ $s .= $_->{sym};
+ } @{$d->{params}};
+ }
+ if ($d->{type} !~ m/^\s*void\s*\?$/) {
+ $s .= "<br />\n";
+ $s .= encode_entities('<-'.("\xA0" x 7).'Return');
+ }
+ $s = $h . $s;
+ } elsif ($print_mode == 1) {
+ $s .= '<span style="background: #c0c0c0">' . $d->{sym} . '</span>';
+ if ($d->{kind} == 1) {
+ $s .= '(';
+ $s .= join(', ',
+ map {
+ html_printer(3,$_);
+ } @{$d->{params}});
+ $s .= ')';
+ }
+ my $t = $d->{type};
+ $t =~ s/\?/$s/;
+ $s = $t;
+ } elsif ($print_mode == 2) {
+ $s .= $d->{sym};
+ if ($d->{kind} == 1) {
+ $s .= '(';
+ $s .= join(', ',
+ map {
+ html_printer(2,$_);
+ } @{$d->{params}});
+ $s .= ')';
+ }
+ my $t = $d->{type};
+ $t =~ s/\?/$s/;
+ $s = $t;
+ }
+ return $s;
+}
+
+print STDERR "Info: building/updating symbol information database\n";
+
+$d = api_data->new();
+if (-s "$here/declarations.dat") {
+ $d->read_declaration_db("$here/declarations.dat");
+} else {
+ print STDERR "Warning: there was no file '$here/declarations.dat'. A new one will be created\n";
+}
+
+for (sort keys %fipssyms) {
+ $newname = $_;
+ $namecomment = undef;
+ if ($oldname{$newname}) {
+ $oldname = $oldname{$newname};
+ $objname = $objname{$oldname} ? $objname{$oldname} : $objname{$newname};
+ $namecomment = "(renames $oldname)";
+ } else {
+ $objname = $objname{$newname};
+ }
+ if ($oldimpl{$newname}) {
+ $apisym = $oldimpl{$newname};
+ $namecomment = "(reimplements $apisym)" if !$namecomment;
+ } else {
+ $apisym = $newname;
+ }
+ $declaration = $declarations{$apisym};
+ print "<!--\n";
+ print "$newname\t\t$namecomment\tin file $objname:\n";
+ print " ",$declaration,"\n ";
+ $d->add_declaration($declaration,$newname,$objname,$namecomment);
+ print "-->\n";
+}
+
+$d->complete_directions();
+$d->write_declaration_db("$here/declarations.dat");
+
+print STDERR "Info: printing output\n";
+
+$d->on_all_declarations(
+ sub {
+ my $decl = shift;
+ #$indent = 2;
+ #print printer($decl);
+ print "<p>",html_printer(0,$decl),"</p>\n";
+ });