1#!/usr/bin/perl 2# 3# Copyright (c) 2021 Ingo Schwarze <schwarze@openbsd.org> 4# 5# Permission to use, copy, modify, and distribute this software for any 6# purpose with or without fee is hereby granted, provided that the above 7# copyright notice and this permission notice appear in all copies. 8# 9# THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 17use strict; 18use warnings; 19 20my %internal = ( 21 asn1 => [qw( 22 ASN1_ENCODING 23 ASN1_OBJECT_FLAG_CRITICAL ASN1_OBJECT_FLAG_DYNAMIC 24 ASN1_OBJECT_FLAG_DYNAMIC_DATA ASN1_OBJECT_FLAG_DYNAMIC_STRINGS 25 ASN1_STRING_FLAG_BITS_LEFT ASN1_STRING_FLAG_CONT 26 ASN1_STRING_FLAG_MSTRING ASN1_STRING_FLAG_NDEF 27 CHARTYPE_FIRST_ESC_2253 CHARTYPE_LAST_ESC_2253 CHARTYPE_PRINTABLESTRING 28 )], 29 bn => [qw( 30 BN_MUL_COMBA BN_RECURSION BN_SQR_COMBA 31 )], 32 objects => [qw( 33 OBJ_bsearch OBJ_bsearch_ OBJ_bsearch_ex OBJ_bsearch_ex_ 34 USE_OBJ_MAC 35 )], 36 x509_vfy => [qw( 37 X509_VERIFY_PARAM_ID 38 )] 39); 40 41my %obsolete = ( 42 asn1 => [qw( 43 ASN1_const_CTX ASN1_CTX 44 ASN1_dup ASN1_d2i_bio ASN1_d2i_bio_of ASN1_d2i_fp ASN1_d2i_fp_of 45 ASN1_i2d_bio ASN1_i2d_bio_of ASN1_i2d_bio_of_const 46 ASN1_i2d_fp ASN1_i2d_fp_of ASN1_i2d_fp_of_const 47 ASN1_LONG_UNDEF 48 d2i_NETSCAPE_X509 i2d_NETSCAPE_X509 49 NETSCAPE_X509 NETSCAPE_X509_free NETSCAPE_X509_new 50 ub_title 51 V_ASN1_PRIMATIVE_TAG 52 X509_algor_st 53 )], 54 objects => [qw( 55 _DECLARE_OBJ_BSEARCH_CMP_FN 56 DECLARE_OBJ_BSEARCH_CMP_FN DECLARE_OBJ_BSEARCH_GLOBAL_CMP_FN 57 IMPLEMENT_OBJ_BSEARCH_CMP_FN IMPLEMENT_OBJ_BSEARCH_GLOBAL_CMP_FN 58 )], 59 x509 => [qw( 60 X509_EX_V_INIT X509_EX_V_NETSCAPE_HACK 61 X509_EXT_PACK_STRING X509_EXT_PACK_UNKNOWN 62 )] 63); 64 65my %postponed = ( 66 asn1 => [qw( 67 ASN1_ITEM_EXP ASN1_ITEM_ptr ASN1_ITEM_ref ASN1_ITEM_rptr 68 ASN1_TEMPLATE ASN1_TLC 69 CHECKED_D2I_OF CHECKED_I2D_OF CHECKED_NEW_OF 70 CHECKED_PPTR_OF CHECKED_PTR_OF 71 DECLARE_ASN1_ALLOC_FUNCTIONS DECLARE_ASN1_ALLOC_FUNCTIONS_name 72 DECLARE_ASN1_ENCODE_FUNCTIONS DECLARE_ASN1_ENCODE_FUNCTIONS_const 73 DECLARE_ASN1_FUNCTIONS DECLARE_ASN1_FUNCTIONS_const 74 DECLARE_ASN1_FUNCTIONS_fname DECLARE_ASN1_FUNCTIONS_name 75 DECLARE_ASN1_ITEM 76 DECLARE_ASN1_NDEF_FUNCTION 77 DECLARE_ASN1_PRINT_FUNCTION DECLARE_ASN1_PRINT_FUNCTION_fname 78 DECLARE_ASN1_SET_OF 79 D2I_OF 80 IMPLEMENT_ASN1_SET_OF 81 I2D_OF I2D_OF_const 82 TYPEDEF_D2I_OF TYPEDEF_D2I2D_OF TYPEDEF_I2D_OF 83 )], 84 x509 => [qw( 85 d2i_PBEPARAM d2i_PBE2PARAM d2i_PBKDF2PARAM 86 i2d_PBEPARAM i2d_PBE2PARAM i2d_PBKDF2PARAM 87 NETSCAPE_SPKAC NETSCAPE_SPKI 88 PBEPARAM PBEPARAM_free PBEPARAM_new 89 PBE2PARAM PBE2PARAM_free PBE2PARAM_new 90 PBKDF2PARAM PBKDF2PARAM_free PBKDF2PARAM_new 91 PKCS5_pbe_set PKCS5_pbe_set0_algor 92 PKCS5_pbe2_set PKCS5_pbe2_set_iv 93 PKCS5_pbkdf2_set 94 )] 95); 96 97my $MANW = 'man -M /usr/share/man -w'; 98my $srcdir = '/usr/src/lib/libcrypto/man'; 99my $hfile = '/usr/include/openssl'; 100 101my $in_cplusplus = 0; 102my $in_comment = 0; 103my $in_define = 0; 104my $in_function = 0; 105my $in_struct = 0; 106my $in_typedef_struct = 0; 107my %undoc = (); 108my $verbose = 0; 109 110if (defined $ARGV[0] && $ARGV[0] eq '-v') { 111 $verbose = 1; 112 shift @ARGV; 113} 114$#ARGV == 0 or die "usage: $0 [-v] headername"; 115$hfile .= "/$ARGV[0].h"; 116open my $in_fh, '<', $hfile or die "$hfile: $!"; 117 118$undoc{$_} = 1 foreach @{$internal{$ARGV[0]}}; 119$undoc{$_} = 1 foreach @{$obsolete{$ARGV[0]}}; 120$undoc{$_} = 1 foreach @{$postponed{$ARGV[0]}}; 121 122while (<$in_fh>) { 123try_again: 124 chomp; 125 my $line = $_; 126 127 # C language comments. 128 129 if ($in_comment) { 130 unless (s/.*?\*\///) { 131 print "-- $line\n" if $verbose; 132 next; 133 } 134 $in_comment = 0; 135 } 136 while (/\/\*/) { 137 s/\s*\/\*.*?\*\/// and next; 138 s/\s*\/\*.*// and $in_comment = 1; 139 } 140 141 # End C++ stuff. 142 143 if ($in_cplusplus) { 144 /^#endif$/ and $in_cplusplus = 0; 145 print "-- $line\n" if $verbose; 146 next; 147 } 148 149 # End declarations of structs. 150 151 if ($in_struct) { 152 if (/^\s*union\s+{$/) { 153 print "-s $line\n" if $verbose; 154 $in_struct++; 155 next; 156 } 157 unless (s/^\s*\}//) { 158 print "-s $line\n" if $verbose; 159 next; 160 } 161 if (--$in_struct && /^\s+\w+;$/) { 162 print "-s $line\n" if $verbose; 163 next; 164 } 165 unless ($in_typedef_struct) { 166 /^\s*;$/ or die "at end of struct: $_"; 167 print "-s $line\n" if $verbose; 168 next; 169 } 170 $in_typedef_struct = 0; 171 my ($id) = /^\s*(\w+);$/ 172 or die "at end of typedef struct: $_"; 173 unless (system "$MANW -k Vt=$id > /dev/null 2>&1") { 174 print "Vt $line\n" if $verbose; 175 next; 176 } 177 if ($undoc{$id}) { 178 print "V- $line\n" if $verbose; 179 delete $undoc{$id}; 180 next; 181 } 182 if ($verbose) { 183 print "XX $line\n"; 184 } else { 185 warn "not found: typedef struct $id"; 186 } 187 next; 188 } 189 190 # End macro definitions. 191 192 if ($in_define) { 193 /\\$/ or $in_define = 0; 194 print "-d $line\n" if $verbose; 195 next; 196 } 197 198 # End function declarations. 199 200 if ($in_function) { 201 /^\s/ or die "function arguments not indented: $_"; 202 /\);$/ and $in_function = 0; 203 print "-f $line\n" if $verbose; 204 next; 205 } 206 207 # Begin C++ stuff. 208 209 if (/^#ifdef\s+__cplusplus$/) { 210 $in_cplusplus = 1; 211 print "-- $line\n" if $verbose; 212 next; 213 } 214 215 # Uninteresting lines. 216 217 if (/^\s*$/ || 218 /^DECLARE_STACK_OF\(\w+\)$/ || 219 /^TYPEDEF_D2I2D_OF\(\w+\);$/ || 220 /^#define HEADER_\w+_H$/ || 221 /^#endif$/ || 222 /^#else$/ || 223 /^extern\s+const\s+ASN1_ITEM\s+\w+_it;$/ || 224 /^#include\s/ || 225 /^#ifn?def\s/ || 226 /^#if !?defined/ || 227 /^#undef\s+BN_LLONG$/) { 228 print "-- $line\n" if $verbose; 229 next; 230 } 231 232 # Begin declarations of structs. 233 234 if (/^(typedef )?(?:struct|enum)(?: \w+)? \{$/) { 235 $in_struct = 1; 236 $1 and $in_typedef_struct = 1; 237 print "-s $line\n" if $verbose; 238 next; 239 } 240 241 # Handle macros. 242 243 if (my ($id) = /^#\s*define\s+(\w+)\s+\S/) { 244 /\\$/ and $in_define = 1; 245 unless (system "$MANW -k Dv=$id > /dev/null 2>&1") { 246 print "Dv $line\n" if $verbose; 247 next; 248 } 249 unless (system "$MANW $id > /dev/null 2>&1") { 250 print "Fn $line\n" if $verbose; 251 next; 252 } 253 unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>', 254 "$srcdir/") { 255 print "D- $line\n" if $verbose; 256 next; 257 } 258 if ($id =~ /^ASN1_PCTX_FLAGS_\w+$/) { 259 print "D- $line\n" if $verbose; 260 next; 261 } 262 if ($id =~ /^(?:ASN1|BN|X509(?:V3)?)_[FR]_\w+$/) { 263 print "D- $line\n" if $verbose; 264 next; 265 } 266 if ($id =~ /^X509_V_ERR_\w+$/) { 267 print "D- $line\n" if $verbose; 268 next; 269 } 270 if ($id =~ /^(?:SN|LN|NID|OBJ)_\w+$/) { 271 print "D- $line\n" if $verbose; 272 next; 273 } 274 if ($undoc{$id}) { 275 print "D- $line\n" if $verbose; 276 delete $undoc{$id}; 277 next; 278 } 279 if ($verbose) { 280 print "XX $line\n"; 281 } else { 282 warn "not found: #define $id"; 283 } 284 next; 285 } 286 if (my ($id) = /^#\s*define\s+(\w+)\(/) { 287 /\\$/ and $in_define = 1; 288 unless (system "$MANW $id > /dev/null 2>&1") { 289 print "Fn $line\n" if $verbose; 290 next; 291 } 292 unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>', 293 "$srcdir/") { 294 print "F- $line\n" if $verbose; 295 next; 296 } 297 if ($undoc{$id}) { 298 print "F- $line\n" if $verbose; 299 delete $undoc{$id}; 300 next; 301 } 302 if ($verbose) { 303 print "XX $line\n"; 304 } else { 305 warn "not found: #define $id()"; 306 } 307 next; 308 } 309 if (my ($id) = /^#\s*define\s+(\w+)$/) { 310 if ($undoc{$id}) { 311 print "-- $line\n" if $verbose; 312 delete $undoc{$id}; 313 next; 314 } 315 if ($verbose) { 316 print "XX $line\n"; 317 } else { 318 warn "not found: #define $id"; 319 } 320 next; 321 } 322 323 # Handle global variables. 324 325 if (my ($id) = /^extern\s+int\s+(\w+);$/) { 326 unless (system "$MANW -k Va=$id > /dev/null 2>&1") { 327 print "Va $line\n" if $verbose; 328 next; 329 } 330 if ($verbose) { 331 print "XX $line\n"; 332 } else { 333 warn "not found: extern int $id"; 334 } 335 next; 336 } 337 338 # Handle variable type declarations. 339 340 if (my ($id) = /^struct\s+(\w+);$/) { 341 unless (system "$MANW -k Vt=$id > /dev/null 2>&1") { 342 print "Vt $line\n" if $verbose; 343 next; 344 } 345 if ($undoc{$id}) { 346 print "V- $line\n" if $verbose; 347 delete $undoc{$id}; 348 next; 349 } 350 if ($verbose) { 351 print "XX $line\n"; 352 } else { 353 warn "not found: struct $id"; 354 } 355 next; 356 } 357 358 if (my ($id) = /^typedef\s+(?:const\s+)?(?:struct\s+)?\S+\s+(\w+);$/) { 359 unless (system "$MANW -k Vt=$id > /dev/null 2>&1") { 360 print "Vt $line\n" if $verbose; 361 next; 362 } 363 if ($undoc{$id}) { 364 print "V- $line\n" if $verbose; 365 delete $undoc{$id}; 366 next; 367 } 368 if ($verbose) { 369 print "XX $line\n"; 370 } else { 371 warn "not found: typedef $id"; 372 } 373 next; 374 } 375 376 if (my ($id) =/^typedef\s+\w+(?:\s+\*)?\s+\(\*(\w+)\)\(/) { 377 /\);$/ or $in_function = 1; 378 unless (system "$MANW $id > /dev/null 2>&1") { 379 print "Fn $line\n" if $verbose; 380 next; 381 } 382 if ($verbose) { 383 print "XX $line\n"; 384 } else { 385 warn "not found: function type (*$id)()"; 386 } 387 next; 388 } 389 390 # Handle function declarations. 391 392 if (/^\w+(?:\(\w+\))?(?:\s+\w+)*\s+(?:\(?\*\s*)?(\w+)\(/) { 393 my $id = $1; 394 /\);$/ or $in_function = 1; 395 unless (system "$MANW $id > /dev/null 2>&1") { 396 print "Fn $line\n" if $verbose; 397 next; 398 } 399 # These functions are still provided by OpenSSL 400 # and still used by the Python test suite, 401 # but intentionally undocumented because nothing 402 # else uses them according to tb@, Dec 3, 2021. 403 if ($id =~ /NETSCAPE_(?:CERT_SEQUENCE|SPKAC|SPKI)/) { 404 print "F- $line\n" if $verbose; 405 next; 406 } 407 unless (system qw/grep -qR/, '^\.\\\\" .*\<' . $id . '\>', 408 "$srcdir/") { 409 print "F- $line\n" if $verbose; 410 next; 411 } 412 if ($undoc{$id}) { 413 print "F- $line\n" if $verbose; 414 delete $undoc{$id}; 415 next; 416 } 417 if ($id =~ /^ASN1_PCTX_\w+$/) { 418 print "F- $line\n" if $verbose; 419 next; 420 } 421 if ($verbose) { 422 print "XX $line\n"; 423 } else { 424 warn "not found: function $id()"; 425 } 426 next; 427 } 428 if (/^int$/) { 429 $_ .= ' ' . <$in_fh>; 430 goto try_again; 431 } 432 if (/ \*$/) { 433 $_ .= <$in_fh>; 434 goto try_again; 435 } 436 die "parse error: $_"; 437} 438close $in_fh; 439warn "expected as undocumented but not found: $_" foreach keys %undoc; 440exit 0; 441