blob: ea9e149501a2ac8950613f991cc0fa110351005f [file] [log] [blame]
#!/usr/bin/perl
#
# Script to parse the SYSCALLS file and generate appropriate
# stubs.
#
# Pass 1: generate the C array of sizes
# Pass 2: generate the syscall stubs and other output
#
#
# Convert a string to a C array of characters,
# e.g. foo -> 'f','o','o','\0',
#
sub chararray($) {
use bytes;
my($s) = @_;
my($i, $c);
my($a) = '';
for ($i = 0; $i < length($s); $i++) {
$c = substr($s, $i, 1);
if (ord($c) < 32 || ord($c) > 126) {
$a .= sprintf("0x%02x,", ord($c));
} elsif ($c eq "\\" || $c eq "\'") {
$a .= "\'\\$c\',";
} else {
$a .= "\'$c\',";
}
}
return $a;
}
$v = $ENV{'KBUILD_VERBOSE'};
$quiet = defined($v) && ($v == 0) ? 1 : undef;
@args = ();
undef $pass;
for $arg ( @ARGV ) {
if ( $arg =~ /^-/ ) {
if ( $arg eq '-q' ) {
$quiet = 1;
} elsif ( $arg eq '-v' ) {
$quiet = 0;
} elsif ( $arg =~ /\-([0-9]+)$/ ) {
$pass = $1+0;
} else {
die "$0: Unknown option: $arg\n";
}
} else {
push(@args, $arg);
}
}
($file, $sysstub, $arch, $bits, $unistd, $outputdir,
$havesyscall, $typesize) = @args;
if (!$pass) {
die "$0: Need to specify pass\n";
}
$quiet = ($pass != 2) unless defined($quiet);
require "$sysstub";
if (!open(UNISTD, '<', $unistd)) {
die "$0: $unistd: $!\n";
}
while ( defined($line = <UNISTD>) ) {
chomp $line;
if ( $line =~ /^\#\s*define\s+__NR_([A-Za-z0-9_]+)\s+(.*\S)\s*$/ ) {
$syscalls{$1} = $2;
print STDERR "SYSCALL FOUND: $1\n" unless ( $quiet );
}
}
close(UNISTD);
if ($pass == 2) {
use bytes;
if (!open(TYPESIZE, '<', $typesize)) {
die "$0: $typesize: $!\n";
}
binmode TYPESIZE;
$len = -s TYPESIZE;
if (read(TYPESIZE, $typebin, $len) != $len) {
die "$0: $typesize: short read: $!\n";
}
close(TYPESIZE);
$ix = index($typebin, "\x7a\xc8\xdb\x4e\x97\xb4\xc9\x19");
if ($ix < 0) {
die "$0: $typesize: magic number not found\n";
}
# Remove magic number and bytes before it
$typebin = substr($typebin, $ix+8);
# Expand the types until a terminating null
%typesize = ();
while (1) {
my $n, $s, $rem;
($n, $s, $rem) = unpack("Z*Ca*", $typebin);
$typebin = $rem;
last if (length($n) == 0);
$typesize{$n} = $s;
print STDERR "sizeof($n) = $s\n" unless ($quiet);
}
} else {
# List here any types which should be sized even if they never occur
# in any system calls at all.
%type_list = ('int' => 1, 'long' => 1, 'long long' => 1,
'void *' => 1,
'intptr_t' => 1, 'uintptr_t' => 1,
'intmax_t' => 1, 'uintmax_t' => 1);
}
if ($pass == 2) {
if (!open(HAVESYS, '>', $havesyscall)) {
die "$0: $havesyscall: $!\n";
}
print HAVESYS "#ifndef _KLIBC_HAVESYSCALL_H\n";
print HAVESYS "#define _KLIBC_HAVESYSCALL_H 1\n\n";
}
if (!open(FILE, '<', $file)) {
die "$0: $file: $!\n";
}
if ($pass == 2) {
print "syscall-objs := ";
}
while ( defined($line = <FILE>) ) {
chomp $line;
$line =~ s/\s*(|\#.*|\/\/.*)$//; # Strip comments and trailing blanks
next unless $line;
if ( $line =~ /^\s*(\<[^\>]+\>\s+|)([A-Za-z0-9_\*\s]+)\s+([A-Za-z0-9_,]+)(|\@[A-Za-z0-9_]+)(|\:\:[A-Za-z0-9_]+)\s*\(([^\:\)]*)\)\s*\;$/ ) {
$archs = $1;
$type = $2;
$snames = $3;
$stype = $4;
$fname = $5;
$argv = $6;
$doit = 1;
$maybe = 0;
if ( $archs ne '' ) {
die "$file:$.: Invalid architecture spec: <$archs>\n"
unless ( $archs =~ /^\<(|\?)(|\!)([^\>\!\?]*)\>/ );
$maybe = $1 ne '';
$not = $2 ne '';
$list = $3;
$doit = $not || ($list eq '');
@list = split(/,/, $list);
foreach $a ( @list ) {
if ( $a eq $arch || $a eq $bits ) {
$doit = !$not;
last;
}
}
}
next if ( ! $doit );
undef $sname;
foreach $sn ( split(/,/, $snames) ) {
if ( defined $syscalls{$sn} ) {
$sname = $sn;
last;
}
}
if ( !defined($sname) ) {
next if ( $maybe );
die "$file:$.: Undefined system call: $snames\n";
}
$type =~ s/\s*$//;
$stype =~ s/^\@//;
if ( $fname eq '' ) {
$fname = $sname;
} else {
$fname =~ s/^\:\://;
}
$argv =~ s/^\s+//;
$argv =~ s/\s+$//;
if ($argv eq 'void') {
@args = ();
} else {
@args = split(/\s*\,\s*/, $argv);
}
if ($pass == 1) {
# Pass 1: Add the types to the type list
foreach $a (@args) {
$type_list{$a}++;
}
} else {
# Pass 2: make sure all types defined, and actually generate stubs
foreach $a (@args) {
if (!defined($typesize{$a})) {
die "$0: $typesize: type name missing: $a\n";
}
}
print HAVESYS "#define _KLIBC_HAVE_SYSCALL_${fname} ${sname}\n";
print " \\\n\t${fname}.o";
make_sysstub($outputdir, $fname, $type, $sname, $stype, @args);
}
} else {
die "$file:$.: Could not parse input: \"$line\"\n";
}
}
if ($pass == 1) {
# Pass 1: generate typesize.c
if (!open(TYPESIZE, '>', $typesize)) {
die "$0: cannot create file: $typesize: $!\n";
}
print TYPESIZE "#include \"syscommon.h\"\n";
print TYPESIZE "\n";
print TYPESIZE "const unsigned char type_sizes[] = {\n";
print TYPESIZE "\t0x7a,0xc8,0xdb,0x4e,0x97,0xb4,0xc9,0x19, /* magic */\n";
foreach $t (sort(keys(%type_list))) {
print TYPESIZE "\t", chararray($t), "0, sizeof($t),\n";
}
print TYPESIZE "\t0, 0,\n"; # End sentinel
print TYPESIZE "};\n";
close(TYPESIZE);
} else {
# Pass 2: finalize output files
print "\n";
print HAVESYS "\n#endif\n";
close(HAVESYS);
}