Back to home page

OSCL-LXR

 
 

    


0001 #!/usr/bin/env perl
0002 # SPDX-License-Identifier: GPL-2.0
0003 #
0004 # headers_check.pl execute a number of trivial consistency checks
0005 #
0006 # Usage: headers_check.pl dir arch [files...]
0007 # dir:   dir to look for included files
0008 # arch:  architecture
0009 # files: list of files to check
0010 #
0011 # The script reads the supplied files line by line and:
0012 #
0013 # 1) for each include statement it checks if the
0014 #    included file actually exists.
0015 #    Only include files located in asm* and linux* are checked.
0016 #    The rest are assumed to be system include files.
0017 #
0018 # 2) It is checked that prototypes does not use "extern"
0019 #
0020 # 3) Check for leaked CONFIG_ symbols
0021 
0022 use warnings;
0023 use strict;
0024 use File::Basename;
0025 
0026 my ($dir, $arch, @files) = @ARGV;
0027 
0028 my $ret = 0;
0029 my $line;
0030 my $lineno = 0;
0031 my $filename;
0032 
0033 foreach my $file (@files) {
0034     $filename = $file;
0035 
0036     open(my $fh, '<', $filename)
0037         or die "$filename: $!\n";
0038     $lineno = 0;
0039     while ($line = <$fh>) {
0040         $lineno++;
0041         &check_include();
0042         &check_asm_types();
0043         &check_sizetypes();
0044         &check_declarations();
0045         # Dropped for now. Too much noise &check_config();
0046     }
0047     close $fh;
0048 }
0049 exit $ret;
0050 
0051 sub check_include
0052 {
0053     if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
0054         my $inc = $1;
0055         my $found;
0056         $found = stat($dir . "/" . $inc);
0057         if (!$found) {
0058             $inc =~ s#asm/#asm-$arch/#;
0059             $found = stat($dir . "/" . $inc);
0060         }
0061         if (!$found) {
0062             printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
0063             $ret = 1;
0064         }
0065     }
0066 }
0067 
0068 sub check_declarations
0069 {
0070     # soundcard.h is what it is
0071     if ($line =~ m/^void seqbuf_dump\(void\);/) {
0072         return;
0073     }
0074     # drm headers are being C++ friendly
0075     if ($line =~ m/^extern "C"/) {
0076         return;
0077     }
0078     if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
0079         printf STDERR "$filename:$lineno: " .
0080                   "userspace cannot reference function or " .
0081                   "variable defined in the kernel\n";
0082     }
0083 }
0084 
0085 sub check_config
0086 {
0087     if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
0088         printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
0089     }
0090 }
0091 
0092 my $linux_asm_types;
0093 sub check_asm_types
0094 {
0095     if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
0096         return;
0097     }
0098     if ($lineno == 1) {
0099         $linux_asm_types = 0;
0100     } elsif ($linux_asm_types >= 1) {
0101         return;
0102     }
0103     if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
0104         $linux_asm_types = 1;
0105         printf STDERR "$filename:$lineno: " .
0106         "include of <linux/types.h> is preferred over <asm/types.h>\n"
0107         # Warn until headers are all fixed
0108         #$ret = 1;
0109     }
0110 }
0111 
0112 my $linux_types;
0113 my %import_stack = ();
0114 sub check_include_typesh
0115 {
0116     my $path = $_[0];
0117     my $import_path;
0118 
0119     my $fh;
0120     my @file_paths = ($path, $dir . "/" .  $path, dirname($filename) . "/" . $path);
0121     for my $possible ( @file_paths ) {
0122         if (not $import_stack{$possible} and open($fh, '<', $possible)) {
0123         $import_path = $possible;
0124         $import_stack{$import_path} = 1;
0125         last;
0126         }
0127     }
0128     if (eof $fh) {
0129         return;
0130     }
0131 
0132     my $line;
0133     while ($line = <$fh>) {
0134         if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
0135             $linux_types = 1;
0136             last;
0137         }
0138         if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
0139             check_include_typesh($included);
0140         }
0141     }
0142     close $fh;
0143     delete $import_stack{$import_path};
0144 }
0145 
0146 sub check_sizetypes
0147 {
0148     if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
0149         return;
0150     }
0151     if ($lineno == 1) {
0152         $linux_types = 0;
0153     } elsif ($linux_types >= 1) {
0154         return;
0155     }
0156     if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
0157         $linux_types = 1;
0158         return;
0159     }
0160     if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
0161         check_include_typesh($included);
0162     }
0163     if ($line =~ m/__[us](8|16|32|64)\b/) {
0164         printf STDERR "$filename:$lineno: " .
0165                       "found __[us]{8,16,32,64} type " .
0166                       "without #include <linux/types.h>\n";
0167         $linux_types = 2;
0168         # Warn until headers are all fixed
0169         #$ret = 1;
0170     }
0171 }