generator.pl
1 #!/usr/bin/perl 2 # 3 # Copyright (c) 2001-2004,2011-2012,2014 Apple Inc. All Rights Reserved. 4 # 5 # @APPLE_LICENSE_HEADER_START@ 6 # 7 # This file contains Original Code and/or Modifications of Original Code 8 # as defined in and that are subject to the Apple Public Source License 9 # Version 2.0 (the 'License'). You may not use this file except in 10 # compliance with the License. Please obtain a copy of the License at 11 # http://www.opensource.apple.com/apsl/ and read it before using this 12 # file. 13 # 14 # The Original Code and all software distributed under the License are 15 # distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 16 # EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 17 # INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 18 # FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 19 # Please see the License for the specific language governing rights and 20 # limitations under the License. 21 # 22 # @APPLE_LICENSE_HEADER_END@ 23 # 24 # generator.pl - derive various and sundry C++ code from the CDSA header files 25 # 26 # Usage: 27 # perl generator.pl input-directory config-file output-directory 28 # 29 # Perry The Cynic, Fall 1999. 30 # 31 @API_H=("cssmapi.h"); 32 %SPI_H=("AC" => "cssmaci.h", "CSP" => "cssmcspi.h", "DL" => "cssmdli.h", 33 "CL" => "cssmcli.h", "TP" => "cssmtpi.h"); 34 @OIDS_H=("oidscert.h", "oidscrl.h"); 35 @OIDS_H2=("oidsattr.h", "oidsalg.h"); 36 37 $SOURCEDIR=$ARGV[0]; # directory with inputs 38 $APICFG=$ARGV[1]; # configuration file 39 $TARGETDIR=$ARGV[2]; # directory for outputs 40 41 42 $TRANSITION="$TARGETDIR/transition.gen"; # C++ code for transition layer 43 $TABLES="$TARGETDIR/funcnames.gen"; # function name tables 44 $REPORT="$TARGETDIR/generator.rpt"; # report file 45 $EXPORTS="$TARGETDIR/cssmexports.gen"; # Exports file 46 47 $tabs = "\t\t\t"; # argument indentation (noncritical) 48 $warning = "This file was automatically generated. Do not edit on penalty of futility!"; 49 50 51 # 52 # Parse API headers and extract function names and argument lists 53 # 54 # Jim Muprhy I added [^;]* to the end of the %formals variable to 55 # allow for deprecation macros. 56 # 57 $/=undef; # big gulp mode 58 foreach $_ (@API_H) { 59 open(API_H, "$SOURCEDIR/$_") or die "Cannot open $SOURCEDIR/$_: $^E"; 60 $_ = <API_H>; # glglgl... aaaaah 61 %formals = /CSSM_RETURN CSSMAPI\s*([A-Za-z_]+)\s+\(([^)]*)\)[^;]*;/gs; 62 while (($name, $args) = each %formals) { 63 $args =~ s/^.*[ *]([A-Za-z_]+,?)$/$tabs$1/gm; # remove type declarators 64 $args =~ s/^$tabs//o; # chop intial tabs # so now we have... 65 $actuals{$name} = $args; # ...an actual argument list 66 }; 67 }; 68 close(API_H); 69 70 71 # 72 # Slurp SPI headers into memory for future use 73 # 74 $/=undef; # slurp files 75 while (($key, $file) = each %SPI_H) { 76 open(SPI_H, "$SOURCEDIR/$file") or die "Cannot open $SOURCEDIR/$file: $^E"; 77 $spi{$key} = <SPI_H>; 78 }; 79 close(SPI_H); 80 81 82 # 83 # Open and read the configuration file 84 # 85 $/=undef; # gulp yet again 86 open(APICFG, $APICFG) or die "Cannot open $APICFG: $^E"; 87 $_=<APICFG>; 88 close(APICFG); 89 %config = /^\s*(\w+)\s+(.*)$/gm; 90 91 92 # 93 # Now we will generate the API transition layer. 94 # The idea here is that for each function in the API, we try to 95 # figure out what type of plugin it belongs to, and then look up 96 # its evil twin in that type's header. If that works, we generate 97 # a function for the transition, taking care of various oddities 98 # and endities in the process. 99 # 100 open(OUT, ">$TRANSITION") or die "Cannot write $TRANSITION: $^E"; 101 select OUT; 102 open(REPORT, ">$REPORT") or die "Cannot write $REPORT: $^E"; 103 104 sub ignored { 105 my ($reason) = @_; 106 $ignored++; 107 print REPORT "$name $reason\n"; 108 }; 109 110 print "// 111 // $warning 112 //"; 113 114 for $name (sort keys %formals) { 115 $config = $config{$name}; 116 do { ignored "has custom implementation"; next; } if $config =~ /custom/; 117 118 ($barename) = $name =~ /^CSSM.*_([A-Za-z]+$)/; 119 die "Can't fathom SPI name for $name" unless $barename; 120 $actuals = $actuals{$name}; 121 122 # key off the type code in the first argument: CSSM_type_HANDLE 123 ($type, $handle) = $formals{$name} =~ /CSSM_([A-Z_]+)_HANDLE\s+([A-Za-z0-9_]+)/; 124 $type = "CSP" if $type eq "CC"; # CSP methods may have CC (context) handles 125 $type = "DL" if $type eq "DL_DB"; # DL methods may have DL_DB handles 126 $type = "KR" if $type eq "KRSP"; # KR methods have KRSP handles 127 $Type = $type . "Attachment"; 128 do { ignored "has no module type"; next; } unless defined $SPI_H{$type}; 129 130 # $prefix will hold code to be generated before the actual call 131 $prefix = ""; 132 133 # match the SPI; take care of the Privilege variants of some calls 134 ($args) = $spi{$type} =~ /CSSM_RETURN \(CSSM${type}I \*$barename\)\s+\(([^)]*)\)[^;]*;/s 135 or $barename =~ s/P$// && # second chance for FooBarP() API functions 136 (($args) = $spi{$type} =~ /CSSM_RETURN \(CSSM${type}I \*$barename\)\s+\(([^)]*)\)[^;]*;/s) 137 or do { ignored "not in $SPI_H{$type}"; next; }; 138 139 # take care of CSP calls taking context handles 140 $handletype = $type; 141 $type eq "CSP" && $actuals =~ /CCHandle/ && do { 142 $actuals =~ s/CCHandle/context.CSPHandle, CCHandle/; 143 $args =~ /CSSM_CONTEXT/ && 144 $actuals =~ s/CCHandle/CCHandle, &context/; 145 $handletype = "CC"; 146 }; 147 148 # add the default privilege argument to non-P functions taking privileges 149 $args =~ /CSSM_PRIVILEGE/ && ! ($name =~ /P$/) && # add privilege argument (last) 150 ($actuals .= ",\n${tabs}attachment.module.cssm.getPrivilege()"); 151 152 # finally translate DLDBHandles into their DL component 153 $handle =~ s/DLDBHandle/DLDBHandle.DLHandle/; 154 155 # payoff time 156 print " 157 CSSM_RETURN CSSMAPI 158 $name ($formals{$name}) 159 { 160 BEGIN_API"; 161 if ($handletype eq "CC") { 162 print " 163 HandleContext &context = enterContext($handle); 164 CSPAttachment &attachment = context.attachment;"; 165 } else { 166 print " 167 $Type &attachment = enterAttachment<$Type>($handle);"; 168 }; 169 print " 170 TransitLock _(attachment); 171 ${prefix}return attachment.downcalls.$barename($actuals); 172 END_API($type) 173 } 174 "; 175 $written++; 176 }; 177 close(OUT); 178 select(STDOUT); 179 180 181 # 182 # Now peruse the SPI headers for a list of function names 183 # and build in-memory translation tables for runtime. 184 # 185 open(OUT, ">$TABLES") or die "Cannot write $TABLES: $^E"; 186 select OUT; 187 188 print "// 189 // Standard plugin name tables 190 // $warning 191 // 192 "; 193 while (($name, $_) = each %spi) { 194 print "extern const char *const ${name}NameTable[] = {"; 195 s/^.*struct(?: DEPRECATED_IN_MAC_OS_X_VERSION_10_7_AND_LATER)? cssm_spi.*{(.*)} CSSM_SPI.*$/$1/s 196 or die "bad format in $SPI_H{$name}"; 197 s/CSSM_RETURN \(CSSM[A-Z]*I \*([A-Za-z_]+)\)\s+\([^)]+\)[^;]*;/\t"$1",/g; 198 print; 199 print "};\n\n"; 200 }; 201 close(OUT); 202 select(STDOUT); 203 204 # 205 # Finally, generate linker export file to avoid leaking internal symbols 206 # 207 open(OUT, ">$EXPORTS") or die "Cannot write $EXPORTS: $^E"; 208 select(OUT); 209 210 # entry point names (functions) 211 for $name (keys %formals) { 212 $symbols{$name} = 1; 213 }; 214 215 # OID-related data symbols 216 $/=undef; 217 foreach $_ (@OIDS_H) { 218 open(OIDS_H, "$SOURCEDIR/$_") or die "Cannot open $SOURCEDIR/$_: $^E"; 219 $_ = <OIDS_H>; # glglgl... aaaaah 220 s/\/\*.*\*\///gm; # remove comments 221 222 foreach $name (/\s+(CSSMOID_[A-Za-z0-9_]+)/gs) { 223 $symbols{$name} = 1; 224 }; 225 }; 226 close(OIDS_H); 227 228 foreach $_ (@OIDS_H2) { 229 open(OIDS_H2, "$SOURCEDIR/../../libsecurity_asn1/lib/$_") or die "Cannot open $SOURCEDIR/$_: $^E"; 230 $_ = <OIDS_H2>; # glglgl... aaaaah 231 s/\/\*.*\*\///gm; # remove comments 232 233 foreach $name (/\s+(CSSMOID_[A-Za-z0-9_]+)/gs) { 234 $symbols{$name} = 1; 235 }; 236 }; 237 close(OIDS_H2); 238 239 foreach $name (keys %symbols) { 240 print "_$name\n"; 241 }; 242 243 close(OUT); 244 select(STDOUT); 245 246 247 close(EXPORTS); 248 close(REPORT); 249 print "$written API functions generated; $ignored ignored (see $REPORT)\n";