1*4882a593Smuzhiyun#!/usr/bin/env perl 2*4882a593Smuzhiyun# SPDX-License-Identifier: GPL-2.0 3*4882a593Smuzhiyun# 4*4882a593Smuzhiyun# headers_check.pl execute a number of trivial consistency checks 5*4882a593Smuzhiyun# 6*4882a593Smuzhiyun# Usage: headers_check.pl dir arch [files...] 7*4882a593Smuzhiyun# dir: dir to look for included files 8*4882a593Smuzhiyun# arch: architecture 9*4882a593Smuzhiyun# files: list of files to check 10*4882a593Smuzhiyun# 11*4882a593Smuzhiyun# The script reads the supplied files line by line and: 12*4882a593Smuzhiyun# 13*4882a593Smuzhiyun# 1) for each include statement it checks if the 14*4882a593Smuzhiyun# included file actually exists. 15*4882a593Smuzhiyun# Only include files located in asm* and linux* are checked. 16*4882a593Smuzhiyun# The rest are assumed to be system include files. 17*4882a593Smuzhiyun# 18*4882a593Smuzhiyun# 2) It is checked that prototypes does not use "extern" 19*4882a593Smuzhiyun# 20*4882a593Smuzhiyun# 3) Check for leaked CONFIG_ symbols 21*4882a593Smuzhiyun 22*4882a593Smuzhiyunuse warnings; 23*4882a593Smuzhiyunuse strict; 24*4882a593Smuzhiyunuse File::Basename; 25*4882a593Smuzhiyun 26*4882a593Smuzhiyunmy ($dir, $arch, @files) = @ARGV; 27*4882a593Smuzhiyun 28*4882a593Smuzhiyunmy $ret = 0; 29*4882a593Smuzhiyunmy $line; 30*4882a593Smuzhiyunmy $lineno = 0; 31*4882a593Smuzhiyunmy $filename; 32*4882a593Smuzhiyun 33*4882a593Smuzhiyunforeach my $file (@files) { 34*4882a593Smuzhiyun $filename = $file; 35*4882a593Smuzhiyun 36*4882a593Smuzhiyun open(my $fh, '<', $filename) 37*4882a593Smuzhiyun or die "$filename: $!\n"; 38*4882a593Smuzhiyun $lineno = 0; 39*4882a593Smuzhiyun while ($line = <$fh>) { 40*4882a593Smuzhiyun $lineno++; 41*4882a593Smuzhiyun &check_include(); 42*4882a593Smuzhiyun &check_asm_types(); 43*4882a593Smuzhiyun &check_sizetypes(); 44*4882a593Smuzhiyun &check_declarations(); 45*4882a593Smuzhiyun # Dropped for now. Too much noise &check_config(); 46*4882a593Smuzhiyun } 47*4882a593Smuzhiyun close $fh; 48*4882a593Smuzhiyun} 49*4882a593Smuzhiyunexit $ret; 50*4882a593Smuzhiyun 51*4882a593Smuzhiyunsub check_include 52*4882a593Smuzhiyun{ 53*4882a593Smuzhiyun if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) { 54*4882a593Smuzhiyun my $inc = $1; 55*4882a593Smuzhiyun my $found; 56*4882a593Smuzhiyun $found = stat($dir . "/" . $inc); 57*4882a593Smuzhiyun if (!$found) { 58*4882a593Smuzhiyun $inc =~ s#asm/#asm-$arch/#; 59*4882a593Smuzhiyun $found = stat($dir . "/" . $inc); 60*4882a593Smuzhiyun } 61*4882a593Smuzhiyun if (!$found) { 62*4882a593Smuzhiyun printf STDERR "$filename:$lineno: included file '$inc' is not exported\n"; 63*4882a593Smuzhiyun $ret = 1; 64*4882a593Smuzhiyun } 65*4882a593Smuzhiyun } 66*4882a593Smuzhiyun} 67*4882a593Smuzhiyun 68*4882a593Smuzhiyunsub check_declarations 69*4882a593Smuzhiyun{ 70*4882a593Smuzhiyun # soundcard.h is what it is 71*4882a593Smuzhiyun if ($line =~ m/^void seqbuf_dump\(void\);/) { 72*4882a593Smuzhiyun return; 73*4882a593Smuzhiyun } 74*4882a593Smuzhiyun # drm headers are being C++ friendly 75*4882a593Smuzhiyun if ($line =~ m/^extern "C"/) { 76*4882a593Smuzhiyun return; 77*4882a593Smuzhiyun } 78*4882a593Smuzhiyun if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) { 79*4882a593Smuzhiyun printf STDERR "$filename:$lineno: " . 80*4882a593Smuzhiyun "userspace cannot reference function or " . 81*4882a593Smuzhiyun "variable defined in the kernel\n"; 82*4882a593Smuzhiyun } 83*4882a593Smuzhiyun} 84*4882a593Smuzhiyun 85*4882a593Smuzhiyunsub check_config 86*4882a593Smuzhiyun{ 87*4882a593Smuzhiyun if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) { 88*4882a593Smuzhiyun printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n"; 89*4882a593Smuzhiyun } 90*4882a593Smuzhiyun} 91*4882a593Smuzhiyun 92*4882a593Smuzhiyunmy $linux_asm_types; 93*4882a593Smuzhiyunsub check_asm_types 94*4882a593Smuzhiyun{ 95*4882a593Smuzhiyun if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { 96*4882a593Smuzhiyun return; 97*4882a593Smuzhiyun } 98*4882a593Smuzhiyun if ($lineno == 1) { 99*4882a593Smuzhiyun $linux_asm_types = 0; 100*4882a593Smuzhiyun } elsif ($linux_asm_types >= 1) { 101*4882a593Smuzhiyun return; 102*4882a593Smuzhiyun } 103*4882a593Smuzhiyun if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) { 104*4882a593Smuzhiyun $linux_asm_types = 1; 105*4882a593Smuzhiyun printf STDERR "$filename:$lineno: " . 106*4882a593Smuzhiyun "include of <linux/types.h> is preferred over <asm/types.h>\n" 107*4882a593Smuzhiyun # Warn until headers are all fixed 108*4882a593Smuzhiyun #$ret = 1; 109*4882a593Smuzhiyun } 110*4882a593Smuzhiyun} 111*4882a593Smuzhiyun 112*4882a593Smuzhiyunmy $linux_types; 113*4882a593Smuzhiyunmy %import_stack = (); 114*4882a593Smuzhiyunsub check_include_typesh 115*4882a593Smuzhiyun{ 116*4882a593Smuzhiyun my $path = $_[0]; 117*4882a593Smuzhiyun my $import_path; 118*4882a593Smuzhiyun 119*4882a593Smuzhiyun my $fh; 120*4882a593Smuzhiyun my @file_paths = ($path, $dir . "/" . $path, dirname($filename) . "/" . $path); 121*4882a593Smuzhiyun for my $possible ( @file_paths ) { 122*4882a593Smuzhiyun if (not $import_stack{$possible} and open($fh, '<', $possible)) { 123*4882a593Smuzhiyun $import_path = $possible; 124*4882a593Smuzhiyun $import_stack{$import_path} = 1; 125*4882a593Smuzhiyun last; 126*4882a593Smuzhiyun } 127*4882a593Smuzhiyun } 128*4882a593Smuzhiyun if (eof $fh) { 129*4882a593Smuzhiyun return; 130*4882a593Smuzhiyun } 131*4882a593Smuzhiyun 132*4882a593Smuzhiyun my $line; 133*4882a593Smuzhiyun while ($line = <$fh>) { 134*4882a593Smuzhiyun if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { 135*4882a593Smuzhiyun $linux_types = 1; 136*4882a593Smuzhiyun last; 137*4882a593Smuzhiyun } 138*4882a593Smuzhiyun if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { 139*4882a593Smuzhiyun check_include_typesh($included); 140*4882a593Smuzhiyun } 141*4882a593Smuzhiyun } 142*4882a593Smuzhiyun close $fh; 143*4882a593Smuzhiyun delete $import_stack{$import_path}; 144*4882a593Smuzhiyun} 145*4882a593Smuzhiyun 146*4882a593Smuzhiyunsub check_sizetypes 147*4882a593Smuzhiyun{ 148*4882a593Smuzhiyun if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) { 149*4882a593Smuzhiyun return; 150*4882a593Smuzhiyun } 151*4882a593Smuzhiyun if ($lineno == 1) { 152*4882a593Smuzhiyun $linux_types = 0; 153*4882a593Smuzhiyun } elsif ($linux_types >= 1) { 154*4882a593Smuzhiyun return; 155*4882a593Smuzhiyun } 156*4882a593Smuzhiyun if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) { 157*4882a593Smuzhiyun $linux_types = 1; 158*4882a593Smuzhiyun return; 159*4882a593Smuzhiyun } 160*4882a593Smuzhiyun if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) { 161*4882a593Smuzhiyun check_include_typesh($included); 162*4882a593Smuzhiyun } 163*4882a593Smuzhiyun if ($line =~ m/__[us](8|16|32|64)\b/) { 164*4882a593Smuzhiyun printf STDERR "$filename:$lineno: " . 165*4882a593Smuzhiyun "found __[us]{8,16,32,64} type " . 166*4882a593Smuzhiyun "without #include <linux/types.h>\n"; 167*4882a593Smuzhiyun $linux_types = 2; 168*4882a593Smuzhiyun # Warn until headers are all fixed 169*4882a593Smuzhiyun #$ret = 1; 170*4882a593Smuzhiyun } 171*4882a593Smuzhiyun} 172