18c2ecf20Sopenharmony_ci#!/usr/bin/env perl
28c2ecf20Sopenharmony_ci# SPDX-License-Identifier: GPL-2.0
38c2ecf20Sopenharmony_ci#
48c2ecf20Sopenharmony_ci# headers_check.pl execute a number of trivial consistency checks
58c2ecf20Sopenharmony_ci#
68c2ecf20Sopenharmony_ci# Usage: headers_check.pl dir arch [files...]
78c2ecf20Sopenharmony_ci# dir:   dir to look for included files
88c2ecf20Sopenharmony_ci# arch:  architecture
98c2ecf20Sopenharmony_ci# files: list of files to check
108c2ecf20Sopenharmony_ci#
118c2ecf20Sopenharmony_ci# The script reads the supplied files line by line and:
128c2ecf20Sopenharmony_ci#
138c2ecf20Sopenharmony_ci# 1) for each include statement it checks if the
148c2ecf20Sopenharmony_ci#    included file actually exists.
158c2ecf20Sopenharmony_ci#    Only include files located in asm* and linux* are checked.
168c2ecf20Sopenharmony_ci#    The rest are assumed to be system include files.
178c2ecf20Sopenharmony_ci#
188c2ecf20Sopenharmony_ci# 2) It is checked that prototypes does not use "extern"
198c2ecf20Sopenharmony_ci#
208c2ecf20Sopenharmony_ci# 3) Check for leaked CONFIG_ symbols
218c2ecf20Sopenharmony_ci
228c2ecf20Sopenharmony_ciuse warnings;
238c2ecf20Sopenharmony_ciuse strict;
248c2ecf20Sopenharmony_ciuse File::Basename;
258c2ecf20Sopenharmony_ci
268c2ecf20Sopenharmony_cimy ($dir, $arch, @files) = @ARGV;
278c2ecf20Sopenharmony_ci
288c2ecf20Sopenharmony_cimy $ret = 0;
298c2ecf20Sopenharmony_cimy $line;
308c2ecf20Sopenharmony_cimy $lineno = 0;
318c2ecf20Sopenharmony_cimy $filename;
328c2ecf20Sopenharmony_ci
338c2ecf20Sopenharmony_ciforeach my $file (@files) {
348c2ecf20Sopenharmony_ci	$filename = $file;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci	open(my $fh, '<', $filename)
378c2ecf20Sopenharmony_ci		or die "$filename: $!\n";
388c2ecf20Sopenharmony_ci	$lineno = 0;
398c2ecf20Sopenharmony_ci	while ($line = <$fh>) {
408c2ecf20Sopenharmony_ci		$lineno++;
418c2ecf20Sopenharmony_ci		&check_include();
428c2ecf20Sopenharmony_ci		&check_asm_types();
438c2ecf20Sopenharmony_ci		&check_sizetypes();
448c2ecf20Sopenharmony_ci		&check_declarations();
458c2ecf20Sopenharmony_ci		# Dropped for now. Too much noise &check_config();
468c2ecf20Sopenharmony_ci	}
478c2ecf20Sopenharmony_ci	close $fh;
488c2ecf20Sopenharmony_ci}
498c2ecf20Sopenharmony_ciexit $ret;
508c2ecf20Sopenharmony_ci
518c2ecf20Sopenharmony_cisub check_include
528c2ecf20Sopenharmony_ci{
538c2ecf20Sopenharmony_ci	if ($line =~ m/^\s*#\s*include\s+<((asm|linux).*)>/) {
548c2ecf20Sopenharmony_ci		my $inc = $1;
558c2ecf20Sopenharmony_ci		my $found;
568c2ecf20Sopenharmony_ci		$found = stat($dir . "/" . $inc);
578c2ecf20Sopenharmony_ci		if (!$found) {
588c2ecf20Sopenharmony_ci			$inc =~ s#asm/#asm-$arch/#;
598c2ecf20Sopenharmony_ci			$found = stat($dir . "/" . $inc);
608c2ecf20Sopenharmony_ci		}
618c2ecf20Sopenharmony_ci		if (!$found) {
628c2ecf20Sopenharmony_ci			printf STDERR "$filename:$lineno: included file '$inc' is not exported\n";
638c2ecf20Sopenharmony_ci			$ret = 1;
648c2ecf20Sopenharmony_ci		}
658c2ecf20Sopenharmony_ci	}
668c2ecf20Sopenharmony_ci}
678c2ecf20Sopenharmony_ci
688c2ecf20Sopenharmony_cisub check_declarations
698c2ecf20Sopenharmony_ci{
708c2ecf20Sopenharmony_ci	# soundcard.h is what it is
718c2ecf20Sopenharmony_ci	if ($line =~ m/^void seqbuf_dump\(void\);/) {
728c2ecf20Sopenharmony_ci		return;
738c2ecf20Sopenharmony_ci	}
748c2ecf20Sopenharmony_ci	# drm headers are being C++ friendly
758c2ecf20Sopenharmony_ci	if ($line =~ m/^extern "C"/) {
768c2ecf20Sopenharmony_ci		return;
778c2ecf20Sopenharmony_ci	}
788c2ecf20Sopenharmony_ci	if ($line =~ m/^(\s*extern|unsigned|char|short|int|long|void)\b/) {
798c2ecf20Sopenharmony_ci		printf STDERR "$filename:$lineno: " .
808c2ecf20Sopenharmony_ci			      "userspace cannot reference function or " .
818c2ecf20Sopenharmony_ci			      "variable defined in the kernel\n";
828c2ecf20Sopenharmony_ci	}
838c2ecf20Sopenharmony_ci}
848c2ecf20Sopenharmony_ci
858c2ecf20Sopenharmony_cisub check_config
868c2ecf20Sopenharmony_ci{
878c2ecf20Sopenharmony_ci	if ($line =~ m/[^a-zA-Z0-9_]+CONFIG_([a-zA-Z0-9_]+)[^a-zA-Z0-9_]/) {
888c2ecf20Sopenharmony_ci		printf STDERR "$filename:$lineno: leaks CONFIG_$1 to userspace where it is not valid\n";
898c2ecf20Sopenharmony_ci	}
908c2ecf20Sopenharmony_ci}
918c2ecf20Sopenharmony_ci
928c2ecf20Sopenharmony_cimy $linux_asm_types;
938c2ecf20Sopenharmony_cisub check_asm_types
948c2ecf20Sopenharmony_ci{
958c2ecf20Sopenharmony_ci	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
968c2ecf20Sopenharmony_ci		return;
978c2ecf20Sopenharmony_ci	}
988c2ecf20Sopenharmony_ci	if ($lineno == 1) {
998c2ecf20Sopenharmony_ci		$linux_asm_types = 0;
1008c2ecf20Sopenharmony_ci	} elsif ($linux_asm_types >= 1) {
1018c2ecf20Sopenharmony_ci		return;
1028c2ecf20Sopenharmony_ci	}
1038c2ecf20Sopenharmony_ci	if ($line =~ m/^\s*#\s*include\s+<asm\/types.h>/) {
1048c2ecf20Sopenharmony_ci		$linux_asm_types = 1;
1058c2ecf20Sopenharmony_ci		printf STDERR "$filename:$lineno: " .
1068c2ecf20Sopenharmony_ci		"include of <linux/types.h> is preferred over <asm/types.h>\n"
1078c2ecf20Sopenharmony_ci		# Warn until headers are all fixed
1088c2ecf20Sopenharmony_ci		#$ret = 1;
1098c2ecf20Sopenharmony_ci	}
1108c2ecf20Sopenharmony_ci}
1118c2ecf20Sopenharmony_ci
1128c2ecf20Sopenharmony_cimy $linux_types;
1138c2ecf20Sopenharmony_cimy %import_stack = ();
1148c2ecf20Sopenharmony_cisub check_include_typesh
1158c2ecf20Sopenharmony_ci{
1168c2ecf20Sopenharmony_ci	my $path = $_[0];
1178c2ecf20Sopenharmony_ci	my $import_path;
1188c2ecf20Sopenharmony_ci
1198c2ecf20Sopenharmony_ci	my $fh;
1208c2ecf20Sopenharmony_ci	my @file_paths = ($path, $dir . "/" .  $path, dirname($filename) . "/" . $path);
1218c2ecf20Sopenharmony_ci	for my $possible ( @file_paths ) {
1228c2ecf20Sopenharmony_ci	    if (not $import_stack{$possible} and open($fh, '<', $possible)) {
1238c2ecf20Sopenharmony_ci		$import_path = $possible;
1248c2ecf20Sopenharmony_ci		$import_stack{$import_path} = 1;
1258c2ecf20Sopenharmony_ci		last;
1268c2ecf20Sopenharmony_ci	    }
1278c2ecf20Sopenharmony_ci	}
1288c2ecf20Sopenharmony_ci	if (eof $fh) {
1298c2ecf20Sopenharmony_ci	    return;
1308c2ecf20Sopenharmony_ci	}
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_ci	my $line;
1338c2ecf20Sopenharmony_ci	while ($line = <$fh>) {
1348c2ecf20Sopenharmony_ci		if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
1358c2ecf20Sopenharmony_ci			$linux_types = 1;
1368c2ecf20Sopenharmony_ci			last;
1378c2ecf20Sopenharmony_ci		}
1388c2ecf20Sopenharmony_ci		if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
1398c2ecf20Sopenharmony_ci			check_include_typesh($included);
1408c2ecf20Sopenharmony_ci		}
1418c2ecf20Sopenharmony_ci	}
1428c2ecf20Sopenharmony_ci	close $fh;
1438c2ecf20Sopenharmony_ci	delete $import_stack{$import_path};
1448c2ecf20Sopenharmony_ci}
1458c2ecf20Sopenharmony_ci
1468c2ecf20Sopenharmony_cisub check_sizetypes
1478c2ecf20Sopenharmony_ci{
1488c2ecf20Sopenharmony_ci	if ($filename =~ /types.h|int-l64.h|int-ll64.h/o) {
1498c2ecf20Sopenharmony_ci		return;
1508c2ecf20Sopenharmony_ci	}
1518c2ecf20Sopenharmony_ci	if ($lineno == 1) {
1528c2ecf20Sopenharmony_ci		$linux_types = 0;
1538c2ecf20Sopenharmony_ci	} elsif ($linux_types >= 1) {
1548c2ecf20Sopenharmony_ci		return;
1558c2ecf20Sopenharmony_ci	}
1568c2ecf20Sopenharmony_ci	if ($line =~ m/^\s*#\s*include\s+<linux\/types.h>/) {
1578c2ecf20Sopenharmony_ci		$linux_types = 1;
1588c2ecf20Sopenharmony_ci		return;
1598c2ecf20Sopenharmony_ci	}
1608c2ecf20Sopenharmony_ci	if (my $included = ($line =~ /^\s*#\s*include\s+[<"](\S+)[>"]/)[0]) {
1618c2ecf20Sopenharmony_ci		check_include_typesh($included);
1628c2ecf20Sopenharmony_ci	}
1638c2ecf20Sopenharmony_ci	if ($line =~ m/__[us](8|16|32|64)\b/) {
1648c2ecf20Sopenharmony_ci		printf STDERR "$filename:$lineno: " .
1658c2ecf20Sopenharmony_ci		              "found __[us]{8,16,32,64} type " .
1668c2ecf20Sopenharmony_ci		              "without #include <linux/types.h>\n";
1678c2ecf20Sopenharmony_ci		$linux_types = 2;
1688c2ecf20Sopenharmony_ci		# Warn until headers are all fixed
1698c2ecf20Sopenharmony_ci		#$ret = 1;
1708c2ecf20Sopenharmony_ci	}
1718c2ecf20Sopenharmony_ci}
172