Commit c07ca774 authored by Alex Brainman's avatar Alex Brainman

syscall: replace mksyscall_windows.pl with mksyscall_windows.go

Not many windows users have perl installed. They can just use
standard go tools instead. Also mkerrors_windows.sh script
removed - we don't add any new "unix" errors to windows
syscall package anymore.

LGTM=rsc
R=golang-codereviews, rsc
CC=golang-codereviews
https://golang.org/cl/41060044
parent 6431be3f
...@@ -81,6 +81,8 @@ mkerrors="./mkerrors.sh" ...@@ -81,6 +81,8 @@ mkerrors="./mkerrors.sh"
zerrors="zerrors_$GOOSARCH.go" zerrors="zerrors_$GOOSARCH.go"
mksysctl="" mksysctl=""
zsysctl="zsysctl_$GOOSARCH.go" zsysctl="zsysctl_$GOOSARCH.go"
mksysnum=
mktypes=
run="sh" run="sh"
case "$1" in case "$1" in
...@@ -226,19 +228,10 @@ solaris_amd64) ...@@ -226,19 +228,10 @@ solaris_amd64)
mksysnum= mksysnum=
mktypes="GOARCH=$GOARCH go tool cgo -godefs" mktypes="GOARCH=$GOARCH go tool cgo -godefs"
;; ;;
windows_386) windows_*)
mksyscall="./mksyscall_windows.pl -l32" mksyscall=
mksysnum= mkerrors=
mktypes= zerrors=
mkerrors="./mkerrors_windows.sh -m32"
zerrors="zerrors_windows.go"
;;
windows_amd64)
mksyscall="./mksyscall_windows.pl"
mksysnum=
mktypes=
mkerrors="./mkerrors_windows.sh -m32"
zerrors="zerrors_windows.go"
;; ;;
*) *)
echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2 echo 'unrecognized $GOOS_$GOARCH: ' "$GOOSARCH" 1>&2
...@@ -248,17 +241,23 @@ esac ...@@ -248,17 +241,23 @@ esac
( (
if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi if [ -n "$mkerrors" ]; then echo "$mkerrors |gofmt >$zerrors"; fi
syscall_goos="syscall_$GOOS.go"
case "$GOOS" in case "$GOOS" in
darwin | dragonfly | freebsd | netbsd | openbsd)
syscall_goos="syscall_bsd.go $syscall_goos"
;;
windows) windows)
syscall_goos="$syscall_goos security_windows.go" echo "GOOS= GOARCH= go build mksyscall_windows.go"
echo "./mksyscall_windows syscall_windows.go security_windows.go syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"
echo "rm -f ./mksyscall_windows"
;;
*)
syscall_goos="syscall_$GOOS.go"
case "$GOOS" in
darwin | dragonfly | freebsd | netbsd | openbsd)
syscall_goos="syscall_bsd.go $syscall_goos"
;;
esac
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
;; ;;
esac esac
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
if [ -n "$mksyscall" ]; then echo "$mksyscall $syscall_goos syscall_$GOOSARCH.go |gofmt >zsyscall_$GOOSARCH.go"; fi
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi if [ -n "$mktypes" ]; then echo "$mktypes types_$GOOS.go |gofmt >ztypes_$GOOSARCH.go"; fi
) | $run ) | $run
:: Copyright 2013 The Go Authors. All rights reserved.
:: Use of this source code is governed by a BSD-style
:: license that can be found in the LICENSE file.
@echo off
if exist mkall.sh goto dirok
echo mkall_windows.bat must be run from src\pkg\syscall directory
goto :end
:dirok
if "%1"=="386" goto :paramok
if "%1"=="amd64" goto :paramok
echo parameters must be 386 or amd64
goto :end
:paramok
go build mksyscall_windows.go
.\mksyscall_windows syscall_windows.go security_windows.go syscall_windows_%1.go |gofmt >zsyscall_windows_%1.go
del mksyscall_windows.exe
:end
\ No newline at end of file
#!/usr/bin/env bash
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# Generate Go code listing errors and other #defined constant
# values (ENAMETOOLONG etc.), by asking the preprocessor
# about the definitions.
unset LANG
export LC_ALL=C
export LC_CTYPE=C
case "$GOARCH" in
arm)
GCC=arm-gcc
;;
*)
GCC=gcc
;;
esac
uname=$(uname)
includes_Linux='
#define _LARGEFILE_SOURCE
#define _LARGEFILE64_SOURCE
#define _FILE_OFFSET_BITS 64
#define _GNU_SOURCE
#include <sys/types.h>
#include <sys/epoll.h>
#include <linux/ptrace.h>
#include <linux/wait.h>
'
includes_Darwin='
#define __DARWIN_UNIX03 0
#define KERNEL
#define _DARWIN_USE_64_BIT_INODE
#include <sys/wait.h>
#include <sys/event.h>
'
includes_FreeBSD='
#include <sys/wait.h>
#include <sys/event.h>
'
includes='
#include <sys/types.h>
#include <fcntl.h>
#include <dirent.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#include <netinet/ip6.h>
#include <netinet/tcp.h>
#include <errno.h>
#include <sys/signal.h>
#include <signal.h>
'
ccflags=""
next=false
for i
do
if $next; then
ccflags="$ccflags $i"
next=false
elif [ "$i" = "-f" ]; then
next=true
fi
done
# These are go errors that will be mapped directly to windows errors
goerrors='
ENOENT:ERROR_FILE_NOT_FOUND
ENOTDIR:ERROR_PATH_NOT_FOUND
'
# Pull out just the error names for later.
i=$(
for j in "$goerrors"
do
echo "$j"
done |
awk -F: '
{ if (NR > 1) printf("|") }
{ printf("%s", $1) }
'
)
errors=$(
echo '#include <errno.h>' | $GCC -x c - -E -dM $ccflags |
awk '
$1 != "#define" || $2 ~ /\(/ {next}
$2 ~ /^('$i')$/ {next}
$2 ~ /^E[A-Z0-9_]+$/ { print $2 }
{next}
' | sort
)
echo '// mkerrors_windows.sh' "$@"
echo '// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT'
echo
echo 'package syscall'
# Run C program to print error strings.
(
/bin/echo "
#include <stdio.h>
#include <errno.h>
#include <ctype.h>
#include <string.h>
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
enum { A = 'A', Z = 'Z', a = 'a', z = 'z' }; // avoid need for single quotes below
struct {
char *goname;
char *winname;
} goerrors[] = {
"
for i in $goerrors
do
j=`echo $i | cut -d: -f1`
k=`echo $i | cut -d: -f2`
echo ' {"'$j'", "'$k'"},'
done
# Use /bin/echo to avoid builtin echo,
# which interprets \n itself
/bin/echo '
};
struct {
char *name;
int value;
} errors[] = {
'
for i in $errors
do
echo ' {"'$i'",' $i'},'
done
# Use /bin/echo to avoid builtin echo,
# which interprets \n itself
/bin/echo '
};
int
main(void)
{
int i, e, iota = 1;
char buf[1024];
printf("\n// Go names for Windows errors.\n");
printf("const (\n");
for(i=0; i<nelem(goerrors); i++) {
printf("\t%s Errno = %s\n", goerrors[i].goname, goerrors[i].winname);
}
printf(")\n");
printf("\n// Windows reserves errors >= 1<<29 for application use.\n");
printf("const APPLICATION_ERROR = 1 << 29\n");
printf("\n// Invented values to support what package os and others expects.\n");
printf("const (\n");
for(i=0; i<nelem(errors); i++) {
printf("\t%s", errors[i].name);
if(iota) {
printf(" Errno = APPLICATION_ERROR + iota");
iota = !iota;
}
printf("\n");
}
printf("\tEWINDOWS\n");
printf(")\n");
printf("\n// Error strings for invented errors\n");
printf("var errors = [...]string {\n");
for(i=0; i<nelem(errors); i++) {
e = errors[i].value;
strcpy(buf, strerror(e));
// lowercase first letter: Bad -> bad, but STREAM -> STREAM.
if(A <= buf[0] && buf[0] <= Z && a <= buf[1] && buf[1] <= z)
buf[0] += a - A;
printf("\t%s - APPLICATION_ERROR: \"%s\",\n", errors[i].name, buf);
next:;
}
printf("\tEWINDOWS - APPLICATION_ERROR: \"not supported by windows\",\n");
printf("}\n\n");
return 0;
}
'
) >_errors.c
$GCC $ccflags -static -o _errors _errors.c && $GORUN ./_errors && rm -f _errors.c _errors
This diff is collapsed.
#!/usr/bin/env perl
# Copyright 2009 The Go Authors. All rights reserved.
# Use of this source code is governed by a BSD-style
# license that can be found in the LICENSE file.
# This program reads a file containing function prototypes
# (like syscall_darwin.go) and generates system call bodies.
# The prototypes are marked by lines beginning with "//sys"
# and read like func declarations if //sys is replaced by func, but:
# * The parameter lists must give a name for each argument.
# This includes return parameters.
# * The parameter lists must give a type for each argument:
# the (x, y, z int) shorthand is not allowed.
# * If the return parameter is an error number, it must be named err.
# * If go func name needs to be different from it's winapi dll name,
# the winapi name could be specified at the end, after "=" sign, like
# //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA
# * Each function that returns err needs to supply a condition,
# that return value of winapi will be tested against to
# detect failure. This would set err to windows "last-error",
# otherwise it will be nil. The value can be provided
# at end of //sys declaration, like
# //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA
# and is [failretval==0] by default.
use strict;
my $cmdline = "mksyscall_windows.pl " . join(' ', @ARGV);
my $errors = 0;
my $_32bit = "";
binmode STDOUT;
if($ARGV[0] eq "-b32") {
$_32bit = "big-endian";
shift;
} elsif($ARGV[0] eq "-l32") {
$_32bit = "little-endian";
shift;
}
if($ARGV[0] =~ /^-/) {
print STDERR "usage: mksyscall_windows.pl [-b32 | -l32] [file ...]\n";
exit 1;
}
sub parseparamlist($) {
my ($list) = @_;
$list =~ s/^\s*//;
$list =~ s/\s*$//;
if($list eq "") {
return ();
}
return split(/\s*,\s*/, $list);
}
sub parseparam($) {
my ($p) = @_;
if($p !~ /^(\S*) (\S*)$/) {
print STDERR "$ARGV:$.: malformed parameter: $p\n";
$errors = 1;
return ("xx", "int");
}
return ($1, $2);
}
my $package = "";
my $text = "";
my $vars = "";
my $mods = "";
my $modnames = "";
while(<>) {
chomp;
s/\s+/ /g;
s/^\s+//;
s/\s+$//;
$package = $1 if !$package && /^package (\S+)$/;
next if !/^\/\/sys /;
my $syscalldot = "";
$syscalldot = "syscall." if $package ne "syscall";
# Line must be of the form
# func Open(path string, mode int, perm int) (fd int, err error)
# Split into name, in params, out params.
if(!/^\/\/sys (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:\[failretval(.*)\])?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
print STDERR "$ARGV:$.: malformed //sys declaration\n";
$errors = 1;
next;
}
my ($func, $in, $out, $failcond, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
# Split argument lists on comma.
my @in = parseparamlist($in);
my @out = parseparamlist($out);
# Dll file name.
if($modname eq "") {
$modname = "kernel32";
}
my $modvname = "mod$modname";
if($modnames !~ /$modname/) {
$modnames .= ".$modname";
$mods .= "\t$modvname = ${syscalldot}NewLazyDLL(\"$modname.dll\")\n";
}
# System call name.
if($sysname eq "") {
$sysname = "$func";
}
# System call pointer variable name.
my $sysvarname = "proc$sysname";
# Returned value when failed
if($failcond eq "") {
$failcond = "== 0";
}
# Decide which version of api is used: ascii or unicode.
my $strconvfunc = $sysname !~ /W$/ ? "BytePtrFromString" : "UTF16PtrFromString";
my $strconvtype = $sysname !~ /W$/ ? "*byte" : "*uint16";
# Winapi proc address variable.
$vars .= "\t$sysvarname = $modvname.NewProc(\"$sysname\")\n";
# Go function header.
$out = join(', ', @out);
if($out ne "") {
$out = " ($out)";
}
if($text ne "") {
$text .= "\n"
}
$text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out;
# Check if err return available
my $errvar = "";
foreach my $p (@out) {
my ($name, $type) = parseparam($p);
if($type eq "error") {
$errvar = $name;
last;
}
}
# Prepare arguments to Syscall.
my @args = ();
my $n = 0;
my @pin= ();
foreach my $p (@in) {
my ($name, $type) = parseparam($p);
if($type =~ /^\*/) {
push @args, "uintptr(unsafe.Pointer($name))";
} elsif($type eq "string" && $errvar ne "") {
$text .= "\tvar _p$n $strconvtype\n";
$text .= "\t_p$n, $errvar = $strconvfunc($name)\n";
$text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type eq "string") {
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
$text .= "\tvar _p$n $strconvtype\n";
$text .= "\t_p$n, _ = $strconvfunc($name)\n";
push @args, "uintptr(unsafe.Pointer(_p$n))";
$n++;
} elsif($type =~ /^\[\](.*)/) {
# Convert slice into pointer, length.
# Have to be careful not to take address of &a[0] if len == 0:
# pass nil in that case.
$text .= "\tvar _p$n *$1\n";
$text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))";
$n++;
} elsif($type eq "int64" && $_32bit ne "") {
if($_32bit eq "big-endian") {
push @args, "uintptr($name >> 32)", "uintptr($name)";
} else {
push @args, "uintptr($name)", "uintptr($name >> 32)";
}
} elsif($type eq "bool") {
$text .= "\tvar _p$n uint32\n";
$text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n";
push @args, "uintptr(_p$n)";
$n++;
} else {
push @args, "uintptr($name)";
}
push @pin, sprintf "\"%s=\", %s, ", $name, $name;
}
my $nargs = @args;
# Determine which form to use; pad args with zeros.
my $asm = "${syscalldot}Syscall";
if(@args <= 3) {
while(@args < 3) {
push @args, "0";
}
} elsif(@args <= 6) {
$asm = "${syscalldot}Syscall6";
while(@args < 6) {
push @args, "0";
}
} elsif(@args <= 9) {
$asm = "${syscalldot}Syscall9";
while(@args < 9) {
push @args, "0";
}
} elsif(@args <= 12) {
$asm = "${syscalldot}Syscall12";
while(@args < 12) {
push @args, "0";
}
} elsif(@args <= 15) {
$asm = "${syscalldot}Syscall15";
while(@args < 15) {
push @args, "0";
}
} else {
print STDERR "$ARGV:$.: too many arguments to system call\n";
}
# Actual call.
my $args = join(', ', @args);
my $call = "$asm($sysvarname.Addr(), $nargs, $args)";
# Assign return values.
my $body = "";
my $failexpr = "";
my @ret = ("_", "_", "_");
my @pout= ();
for(my $i=0; $i<@out; $i++) {
my $p = $out[$i];
my ($name, $type) = parseparam($p);
my $reg = "";
if($name eq "err") {
$reg = "e1";
$ret[2] = $reg;
} else {
$reg = sprintf("r%d", $i);
$ret[$i] = $reg;
}
if($type eq "bool") {
$reg = "$reg != 0";
}
if($type eq "int64" && $_32bit ne "") {
# 64-bit number in r1:r0 or r0:r1.
if($i+2 > @out) {
print STDERR "$ARGV:$.: not enough registers for int64 return\n";
}
if($_32bit eq "big-endian") {
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1);
} else {
$reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i);
}
$ret[$i] = sprintf("r%d", $i);
$ret[$i+1] = sprintf("r%d", $i+1);
}
my $rettype = $type;
if($type =~ /^\*/) {
$reg = "unsafe.Pointer($reg)";
$rettype = "($rettype)";
}
if($i == 0) {
if($type eq "bool") {
$failexpr = "!$name";
} elsif($name eq "err") {
$ret[$i] = "r1";
$failexpr = "r1 $failcond";
} else {
$failexpr = "$name $failcond";
}
}
$failexpr =~ s/(=)([0-9A-Za-z\-+])/$1 $2/; # gofmt compatible
if($name eq "err") {
# Set err to "last error" only if returned value indicate failure
$body .= "\tif $failexpr {\n";
$body .= "\t\tif $reg != 0 {\n";
$body .= "\t\t\t$name = $type($reg)\n";
$body .= "\t\t} else {\n";
$body .= "\t\t\t$name = ${syscalldot}EINVAL\n";
$body .= "\t\t}\n";
$body .= "\t}\n";
} elsif($rettype eq "error") {
# Set $reg to "error" only if returned value indicate failure
$body .= "\tif $reg != 0 {\n";
$body .= "\t\t$name = ${syscalldot}Errno($reg)\n";
$body .= "\t}\n";
} else {
$body .= "\t$name = $rettype($reg)\n";
}
push @pout, sprintf "\"%s=\", %s, ", $name, $name;
}
if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") {
$text .= "\t$call\n";
} else {
$text .= "\t$ret[0], $ret[1], $ret[2] := $call\n";
}
$text .= $body;
if(0) {
$text .= sprintf 'print("SYSCALL: %s(", %s") (", %s")\n")%s', $func, join('", ", ', @pin), join('", ", ', @pout), "\n";
}
$text .= "\treturn\n";
$text .= "}\n";
}
if($errors) {
exit 1;
}
print <<EOF;
// $cmdline
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package $package
import "unsafe"
EOF
print "import \"syscall\"\n" if $package ne "syscall";
print <<EOF;
var (
$mods
$vars
)
$text
EOF
exit 0;
// mksyscall_windows.pl -l32 syscall_windows.go security_windows.go syscall_windows_386.go // go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_386.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall package syscall
......
// mksyscall_windows.pl syscall_windows.go security_windows.go syscall_windows_amd64.go // go build mksyscall_windows.go && ./mksyscall_windows syscall_windows.go security_windows.go syscall_windows_amd64.go
// MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT
package syscall package syscall
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment