1*62c56f98SSadaf Ebrahimi#!/usr/bin/env perl 2*62c56f98SSadaf Ebrahimi 3*62c56f98SSadaf Ebrahimi# Generate error.c 4*62c56f98SSadaf Ebrahimi# 5*62c56f98SSadaf Ebrahimi# Usage: ./generate_errors.pl or scripts/generate_errors.pl without arguments, 6*62c56f98SSadaf Ebrahimi# or generate_errors.pl include_dir data_dir error_file 7*62c56f98SSadaf Ebrahimi# 8*62c56f98SSadaf Ebrahimi# Copyright The Mbed TLS Contributors 9*62c56f98SSadaf Ebrahimi# SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later 10*62c56f98SSadaf Ebrahimi 11*62c56f98SSadaf Ebrahimiuse strict; 12*62c56f98SSadaf Ebrahimiuse warnings; 13*62c56f98SSadaf Ebrahimi 14*62c56f98SSadaf Ebrahimimy ($include_dir, $data_dir, $error_file); 15*62c56f98SSadaf Ebrahimi 16*62c56f98SSadaf Ebrahimiif( @ARGV ) { 17*62c56f98SSadaf Ebrahimi die "Invalid number of arguments" if scalar @ARGV != 3; 18*62c56f98SSadaf Ebrahimi ($include_dir, $data_dir, $error_file) = @ARGV; 19*62c56f98SSadaf Ebrahimi 20*62c56f98SSadaf Ebrahimi -d $include_dir or die "No such directory: $include_dir\n"; 21*62c56f98SSadaf Ebrahimi -d $data_dir or die "No such directory: $data_dir\n"; 22*62c56f98SSadaf Ebrahimi} else { 23*62c56f98SSadaf Ebrahimi $include_dir = 'include/mbedtls'; 24*62c56f98SSadaf Ebrahimi $data_dir = 'scripts/data_files'; 25*62c56f98SSadaf Ebrahimi $error_file = 'library/error.c'; 26*62c56f98SSadaf Ebrahimi 27*62c56f98SSadaf Ebrahimi unless( -d $include_dir && -d $data_dir ) { 28*62c56f98SSadaf Ebrahimi chdir '..' or die; 29*62c56f98SSadaf Ebrahimi -d $include_dir && -d $data_dir 30*62c56f98SSadaf Ebrahimi or die "Without arguments, must be run from root or scripts\n" 31*62c56f98SSadaf Ebrahimi } 32*62c56f98SSadaf Ebrahimi} 33*62c56f98SSadaf Ebrahimi 34*62c56f98SSadaf Ebrahimimy $error_format_file = $data_dir.'/error.fmt'; 35*62c56f98SSadaf Ebrahimi 36*62c56f98SSadaf Ebrahimimy @low_level_modules = qw( AES ARIA ASN1 BASE64 BIGNUM 37*62c56f98SSadaf Ebrahimi CAMELLIA CCM CHACHA20 CHACHAPOLY CMAC CTR_DRBG DES 38*62c56f98SSadaf Ebrahimi ENTROPY ERROR GCM HKDF HMAC_DRBG LMS MD5 39*62c56f98SSadaf Ebrahimi NET OID PADLOCK PBKDF2 PLATFORM POLY1305 RIPEMD160 40*62c56f98SSadaf Ebrahimi SHA1 SHA256 SHA512 SHA3 THREADING ); 41*62c56f98SSadaf Ebrahimimy @high_level_modules = qw( CIPHER DHM ECP MD 42*62c56f98SSadaf Ebrahimi PEM PK PKCS12 PKCS5 43*62c56f98SSadaf Ebrahimi RSA SSL X509 PKCS7 ); 44*62c56f98SSadaf Ebrahimi 45*62c56f98SSadaf Ebrahimiundef $/; 46*62c56f98SSadaf Ebrahimi 47*62c56f98SSadaf Ebrahimiopen(FORMAT_FILE, '<:crlf', "$error_format_file") or die "Opening error format file '$error_format_file': $!"; 48*62c56f98SSadaf Ebrahimimy $error_format = <FORMAT_FILE>; 49*62c56f98SSadaf Ebrahimiclose(FORMAT_FILE); 50*62c56f98SSadaf Ebrahimi 51*62c56f98SSadaf Ebrahimimy @files = glob qq("$include_dir/*.h"); 52*62c56f98SSadaf Ebrahimimy @necessary_include_files; 53*62c56f98SSadaf Ebrahimimy @matches; 54*62c56f98SSadaf Ebrahimiforeach my $file (@files) { 55*62c56f98SSadaf Ebrahimi open(FILE, '<:crlf', $file) or die("$0: $file: $!"); 56*62c56f98SSadaf Ebrahimi my $content = <FILE>; 57*62c56f98SSadaf Ebrahimi close FILE; 58*62c56f98SSadaf Ebrahimi my $found = 0; 59*62c56f98SSadaf Ebrahimi while ($content =~ m[ 60*62c56f98SSadaf Ebrahimi # Both the before-comment and the after-comment are optional. 61*62c56f98SSadaf Ebrahimi # Only the comment content is a regex capture group. The comment 62*62c56f98SSadaf Ebrahimi # start and end parts are outside the capture group. 63*62c56f98SSadaf Ebrahimi (?:/\*[*!](?!<) # Doxygen before-comment start 64*62c56f98SSadaf Ebrahimi ((?:[^*]|\*+[^*/])*) # $1: Comment content (no */ inside) 65*62c56f98SSadaf Ebrahimi \*/)? # Comment end 66*62c56f98SSadaf Ebrahimi \s*\#\s*define\s+(MBEDTLS_ERR_\w+) # $2: name 67*62c56f98SSadaf Ebrahimi \s+\-(0[Xx][0-9A-Fa-f]+)\s* # $3: value (without the sign) 68*62c56f98SSadaf Ebrahimi (?:/\*[*!]< # Doxygen after-comment start 69*62c56f98SSadaf Ebrahimi ((?:[^*]|\*+[^*/])*) # $4: Comment content (no */ inside) 70*62c56f98SSadaf Ebrahimi \*/)? # Comment end 71*62c56f98SSadaf Ebrahimi ]gsx) { 72*62c56f98SSadaf Ebrahimi my ($before, $name, $value, $after) = ($1, $2, $3, $4); 73*62c56f98SSadaf Ebrahimi # Discard Doxygen comments that are coincidentally present before 74*62c56f98SSadaf Ebrahimi # an error definition but not attached to it. This is ad hoc, based 75*62c56f98SSadaf Ebrahimi # on what actually matters (or mattered at some point). 76*62c56f98SSadaf Ebrahimi undef $before if defined($before) && $before =~ /\s*\\name\s/s; 77*62c56f98SSadaf Ebrahimi die "Description neither before nor after $name in $file\n" 78*62c56f98SSadaf Ebrahimi if !defined($before) && !defined($after); 79*62c56f98SSadaf Ebrahimi die "Description both before and after $name in $file\n" 80*62c56f98SSadaf Ebrahimi if defined($before) && defined($after); 81*62c56f98SSadaf Ebrahimi my $description = (defined($before) ? $before : $after); 82*62c56f98SSadaf Ebrahimi $description =~ s/^\s+//; 83*62c56f98SSadaf Ebrahimi $description =~ s/\n( *\*)? */ /g; 84*62c56f98SSadaf Ebrahimi $description =~ s/\.?\s+$//; 85*62c56f98SSadaf Ebrahimi push @matches, [$name, $value, $description]; 86*62c56f98SSadaf Ebrahimi ++$found; 87*62c56f98SSadaf Ebrahimi } 88*62c56f98SSadaf Ebrahimi if ($found) { 89*62c56f98SSadaf Ebrahimi my $include_name = $file; 90*62c56f98SSadaf Ebrahimi $include_name =~ s!.*/!!; 91*62c56f98SSadaf Ebrahimi push @necessary_include_files, $include_name; 92*62c56f98SSadaf Ebrahimi } 93*62c56f98SSadaf Ebrahimi} 94*62c56f98SSadaf Ebrahimi 95*62c56f98SSadaf Ebrahimimy $ll_old_define = ""; 96*62c56f98SSadaf Ebrahimimy $hl_old_define = ""; 97*62c56f98SSadaf Ebrahimi 98*62c56f98SSadaf Ebrahimimy $ll_code_check = ""; 99*62c56f98SSadaf Ebrahimimy $hl_code_check = ""; 100*62c56f98SSadaf Ebrahimi 101*62c56f98SSadaf Ebrahimimy $headers = ""; 102*62c56f98SSadaf Ebrahimimy %included_headers; 103*62c56f98SSadaf Ebrahimi 104*62c56f98SSadaf Ebrahimimy %error_codes_seen; 105*62c56f98SSadaf Ebrahimi 106*62c56f98SSadaf Ebrahimiforeach my $match (@matches) 107*62c56f98SSadaf Ebrahimi{ 108*62c56f98SSadaf Ebrahimi my ($error_name, $error_code, $description) = @$match; 109*62c56f98SSadaf Ebrahimi 110*62c56f98SSadaf Ebrahimi die "Duplicated error code: $error_code ($error_name)\n" 111*62c56f98SSadaf Ebrahimi if( $error_codes_seen{$error_code}++ ); 112*62c56f98SSadaf Ebrahimi 113*62c56f98SSadaf Ebrahimi $description =~ s/\\/\\\\/g; 114*62c56f98SSadaf Ebrahimi 115*62c56f98SSadaf Ebrahimi my ($module_name) = $error_name =~ /^MBEDTLS_ERR_([^_]+)/; 116*62c56f98SSadaf Ebrahimi 117*62c56f98SSadaf Ebrahimi # Fix faulty ones 118*62c56f98SSadaf Ebrahimi $module_name = "BIGNUM" if ($module_name eq "MPI"); 119*62c56f98SSadaf Ebrahimi $module_name = "CTR_DRBG" if ($module_name eq "CTR"); 120*62c56f98SSadaf Ebrahimi $module_name = "HMAC_DRBG" if ($module_name eq "HMAC"); 121*62c56f98SSadaf Ebrahimi 122*62c56f98SSadaf Ebrahimi my $define_name = $module_name; 123*62c56f98SSadaf Ebrahimi $define_name = "X509_USE,X509_CREATE" if ($define_name eq "X509"); 124*62c56f98SSadaf Ebrahimi $define_name = "ASN1_PARSE" if ($define_name eq "ASN1"); 125*62c56f98SSadaf Ebrahimi $define_name = "SSL_TLS" if ($define_name eq "SSL"); 126*62c56f98SSadaf Ebrahimi $define_name = "PEM_PARSE,PEM_WRITE" if ($define_name eq "PEM"); 127*62c56f98SSadaf Ebrahimi $define_name = "PKCS7" if ($define_name eq "PKCS7"); 128*62c56f98SSadaf Ebrahimi 129*62c56f98SSadaf Ebrahimi my $include_name = $module_name; 130*62c56f98SSadaf Ebrahimi $include_name =~ tr/A-Z/a-z/; 131*62c56f98SSadaf Ebrahimi 132*62c56f98SSadaf Ebrahimi # Fix faulty ones 133*62c56f98SSadaf Ebrahimi $include_name = "net_sockets" if ($module_name eq "NET"); 134*62c56f98SSadaf Ebrahimi 135*62c56f98SSadaf Ebrahimi $included_headers{"${include_name}.h"} = $module_name; 136*62c56f98SSadaf Ebrahimi 137*62c56f98SSadaf Ebrahimi my $found_ll = grep $_ eq $module_name, @low_level_modules; 138*62c56f98SSadaf Ebrahimi my $found_hl = grep $_ eq $module_name, @high_level_modules; 139*62c56f98SSadaf Ebrahimi if (!$found_ll && !$found_hl) 140*62c56f98SSadaf Ebrahimi { 141*62c56f98SSadaf Ebrahimi printf("Error: Do not know how to handle: $module_name\n"); 142*62c56f98SSadaf Ebrahimi exit 1; 143*62c56f98SSadaf Ebrahimi } 144*62c56f98SSadaf Ebrahimi 145*62c56f98SSadaf Ebrahimi my $code_check; 146*62c56f98SSadaf Ebrahimi my $old_define; 147*62c56f98SSadaf Ebrahimi my $white_space; 148*62c56f98SSadaf Ebrahimi my $first; 149*62c56f98SSadaf Ebrahimi 150*62c56f98SSadaf Ebrahimi if ($found_ll) 151*62c56f98SSadaf Ebrahimi { 152*62c56f98SSadaf Ebrahimi $code_check = \$ll_code_check; 153*62c56f98SSadaf Ebrahimi $old_define = \$ll_old_define; 154*62c56f98SSadaf Ebrahimi $white_space = ' '; 155*62c56f98SSadaf Ebrahimi } 156*62c56f98SSadaf Ebrahimi else 157*62c56f98SSadaf Ebrahimi { 158*62c56f98SSadaf Ebrahimi $code_check = \$hl_code_check; 159*62c56f98SSadaf Ebrahimi $old_define = \$hl_old_define; 160*62c56f98SSadaf Ebrahimi $white_space = ' '; 161*62c56f98SSadaf Ebrahimi } 162*62c56f98SSadaf Ebrahimi 163*62c56f98SSadaf Ebrahimi if ($define_name ne ${$old_define}) 164*62c56f98SSadaf Ebrahimi { 165*62c56f98SSadaf Ebrahimi if (${$old_define} ne "") 166*62c56f98SSadaf Ebrahimi { 167*62c56f98SSadaf Ebrahimi ${$code_check} .= "#endif /* "; 168*62c56f98SSadaf Ebrahimi $first = 0; 169*62c56f98SSadaf Ebrahimi foreach my $dep (split(/,/, ${$old_define})) 170*62c56f98SSadaf Ebrahimi { 171*62c56f98SSadaf Ebrahimi ${$code_check} .= " || " if ($first++); 172*62c56f98SSadaf Ebrahimi ${$code_check} .= "MBEDTLS_${dep}_C"; 173*62c56f98SSadaf Ebrahimi } 174*62c56f98SSadaf Ebrahimi ${$code_check} .= " */\n\n"; 175*62c56f98SSadaf Ebrahimi } 176*62c56f98SSadaf Ebrahimi 177*62c56f98SSadaf Ebrahimi ${$code_check} .= "#if "; 178*62c56f98SSadaf Ebrahimi $headers .= "#if " if ($include_name ne ""); 179*62c56f98SSadaf Ebrahimi $first = 0; 180*62c56f98SSadaf Ebrahimi foreach my $dep (split(/,/, ${define_name})) 181*62c56f98SSadaf Ebrahimi { 182*62c56f98SSadaf Ebrahimi ${$code_check} .= " || " if ($first); 183*62c56f98SSadaf Ebrahimi $headers .= " || " if ($first++); 184*62c56f98SSadaf Ebrahimi 185*62c56f98SSadaf Ebrahimi ${$code_check} .= "defined(MBEDTLS_${dep}_C)"; 186*62c56f98SSadaf Ebrahimi $headers .= "defined(MBEDTLS_${dep}_C)" if 187*62c56f98SSadaf Ebrahimi ($include_name ne ""); 188*62c56f98SSadaf Ebrahimi } 189*62c56f98SSadaf Ebrahimi ${$code_check} .= "\n"; 190*62c56f98SSadaf Ebrahimi $headers .= "\n#include \"mbedtls/${include_name}.h\"\n". 191*62c56f98SSadaf Ebrahimi "#endif\n\n" if ($include_name ne ""); 192*62c56f98SSadaf Ebrahimi ${$old_define} = $define_name; 193*62c56f98SSadaf Ebrahimi } 194*62c56f98SSadaf Ebrahimi 195*62c56f98SSadaf Ebrahimi ${$code_check} .= "${white_space}case -($error_name):\n". 196*62c56f98SSadaf Ebrahimi "${white_space} return( \"$module_name - $description\" );\n" 197*62c56f98SSadaf Ebrahimi}; 198*62c56f98SSadaf Ebrahimi 199*62c56f98SSadaf Ebrahimiif ($ll_old_define ne "") 200*62c56f98SSadaf Ebrahimi{ 201*62c56f98SSadaf Ebrahimi $ll_code_check .= "#endif /* "; 202*62c56f98SSadaf Ebrahimi my $first = 0; 203*62c56f98SSadaf Ebrahimi foreach my $dep (split(/,/, $ll_old_define)) 204*62c56f98SSadaf Ebrahimi { 205*62c56f98SSadaf Ebrahimi $ll_code_check .= " || " if ($first++); 206*62c56f98SSadaf Ebrahimi $ll_code_check .= "MBEDTLS_${dep}_C"; 207*62c56f98SSadaf Ebrahimi } 208*62c56f98SSadaf Ebrahimi $ll_code_check .= " */\n"; 209*62c56f98SSadaf Ebrahimi} 210*62c56f98SSadaf Ebrahimiif ($hl_old_define ne "") 211*62c56f98SSadaf Ebrahimi{ 212*62c56f98SSadaf Ebrahimi $hl_code_check .= "#endif /* "; 213*62c56f98SSadaf Ebrahimi my $first = 0; 214*62c56f98SSadaf Ebrahimi foreach my $dep (split(/,/, $hl_old_define)) 215*62c56f98SSadaf Ebrahimi { 216*62c56f98SSadaf Ebrahimi $hl_code_check .= " || " if ($first++); 217*62c56f98SSadaf Ebrahimi $hl_code_check .= "MBEDTLS_${dep}_C"; 218*62c56f98SSadaf Ebrahimi } 219*62c56f98SSadaf Ebrahimi $hl_code_check .= " */\n"; 220*62c56f98SSadaf Ebrahimi} 221*62c56f98SSadaf Ebrahimi 222*62c56f98SSadaf Ebrahimi$error_format =~ s/HEADER_INCLUDED\n/$headers/g; 223*62c56f98SSadaf Ebrahimi$error_format =~ s/LOW_LEVEL_CODE_CHECKS\n/$ll_code_check/g; 224*62c56f98SSadaf Ebrahimi$error_format =~ s/HIGH_LEVEL_CODE_CHECKS\n/$hl_code_check/g; 225*62c56f98SSadaf Ebrahimi 226*62c56f98SSadaf Ebrahimiopen(ERROR_FILE, ">$error_file") or die "Opening destination file '$error_file': $!"; 227*62c56f98SSadaf Ebrahimiprint ERROR_FILE $error_format; 228*62c56f98SSadaf Ebrahimiclose(ERROR_FILE); 229*62c56f98SSadaf Ebrahimi 230*62c56f98SSadaf Ebrahimimy $errors = 0; 231*62c56f98SSadaf Ebrahimifor my $include_name (@necessary_include_files) 232*62c56f98SSadaf Ebrahimi{ 233*62c56f98SSadaf Ebrahimi if (not $included_headers{$include_name}) 234*62c56f98SSadaf Ebrahimi { 235*62c56f98SSadaf Ebrahimi print STDERR "The header file \"$include_name\" defines error codes but has not been included!\n"; 236*62c56f98SSadaf Ebrahimi ++$errors; 237*62c56f98SSadaf Ebrahimi } 238*62c56f98SSadaf Ebrahimi} 239*62c56f98SSadaf Ebrahimi 240*62c56f98SSadaf Ebrahimiexit !!$errors; 241