mirror of
https://github.com/golang/sys.git
synced 2026-02-08 03:36:03 +03:00
unix: add support for aix/ppc64, gc implementation
This commit ports unix package for aix/ppc64 with gc implementation. In order to merge as much as possible gc and gccgo implementation, the mksyscall_aix_ppc64.pl creates three files. zsyscall_aix_ppc64.go is common for both implementation. It has the main syscall function and handles the pointer creations, type conversions and the error if needed. It calls a function "call..." which is available for each implementation. zsyscall_aix_ppc64_gc.go is the gc part. It implements "call..." functions using //go:cgo_import_dynamic and //go:linkname. It is based on syscall.syscall6 function. zsyscall_aix_ppc64_gccgo.go is the gccgo part. It implements "call..." functions using cgo and C functions. Some unavailable syscalls were also removed from the previous implementation. For aix/ppc, the script is left unchanged as aix/ppc won't be implemented inside gc. Change-Id: I3701095df31517c66f95874ba8e682967993090b Reviewed-on: https://go-review.googlesource.com/c/143117 Run-TryBot: Tobias Klauser <tobias.klauser@gmail.com> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Tobias Klauser <tobias.klauser@gmail.com>
This commit is contained in:
17
unix/asm_aix_ppc64.s
Normal file
17
unix/asm_aix_ppc64.s
Normal file
@@ -0,0 +1,17 @@
|
||||
// Copyright 2018 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.
|
||||
|
||||
// +build !gccgo
|
||||
|
||||
#include "textflag.h"
|
||||
|
||||
//
|
||||
// System calls for ppc64, AIX are implemented in runtime/syscall_aix.go
|
||||
//
|
||||
|
||||
TEXT ·syscall6(SB),NOSPLIT,$0-88
|
||||
JMP syscall·syscall6(SB)
|
||||
|
||||
TEXT ·rawSyscall6(SB),NOSPLIT,$0-88
|
||||
JMP syscall·rawSyscall6(SB)
|
||||
@@ -61,12 +61,12 @@ _* | *_ | _)
|
||||
;;
|
||||
aix_ppc)
|
||||
mkerrors="$mkerrors -maix32"
|
||||
mksyscall="perl mksyscall_aix.pl -aix"
|
||||
mksyscall="./mksyscall_aix_ppc.pl -aix"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
aix_ppc64)
|
||||
mkerrors="$mkerrors -maix64"
|
||||
mksyscall="perl mksyscall_aix.pl -aix"
|
||||
mksyscall="./mksyscall_aix_ppc64.pl -aix"
|
||||
mktypes="GOARCH=$GOARCH go tool cgo -godefs"
|
||||
;;
|
||||
darwin_386)
|
||||
@@ -187,8 +187,14 @@ esac
|
||||
syscall_goos="syscall_bsd.go $syscall_goos"
|
||||
;;
|
||||
esac
|
||||
if [ -n "$mksyscall" ]; then echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go"; fi
|
||||
;;
|
||||
if [ -n "$mksyscall" ]; then
|
||||
if [ "$GOOSARCH" == "aix_ppc64" ]; then
|
||||
# aix/ppc64 script generates files instead of writing to stdin.
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in && gofmt -w zsyscall_$GOOSARCH.go && gofmt -w zsyscall_"$GOOSARCH"_gccgo.go && gofmt -w zsyscall_"$GOOSARCH"_gc.go " ;
|
||||
else
|
||||
echo "$mksyscall -tags $GOOS,$GOARCH $syscall_goos $GOOSARCH_in |gofmt >zsyscall_$GOOSARCH.go";
|
||||
fi
|
||||
fi
|
||||
esac
|
||||
if [ -n "$mksysctl" ]; then echo "$mksysctl |gofmt >$zsysctl"; fi
|
||||
if [ -n "$mksysnum" ]; then echo "$mksysnum |gofmt >zsysnum_$GOOSARCH.go"; fi
|
||||
|
||||
5
unix/mksyscall_aix.pl → unix/mksyscall_aix_ppc.pl
Normal file → Executable file
5
unix/mksyscall_aix.pl → unix/mksyscall_aix_ppc.pl
Normal file → Executable file
@@ -19,7 +19,7 @@
|
||||
|
||||
use strict;
|
||||
|
||||
my $cmdline = "mksyscall_aix.pl " . join(' ', @ARGV);
|
||||
my $cmdline = "mksyscall_aix_ppc.pl " . join(' ', @ARGV);
|
||||
my $errors = 0;
|
||||
my $_32bit = "";
|
||||
my $tags = ""; # build tags
|
||||
@@ -72,7 +72,7 @@ sub parseparam($) {
|
||||
|
||||
my $package = "";
|
||||
my $text = "";
|
||||
my $c_extern = "/*\n#include <stdint.h>\n";
|
||||
my $c_extern = "/*\n#include <stdint.h>\n#include <stddef.h>\n";
|
||||
my @vars = ();
|
||||
while(<>) {
|
||||
chomp;
|
||||
@@ -369,7 +369,6 @@ $c_extern
|
||||
import "C"
|
||||
import (
|
||||
"unsafe"
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
||||
579
unix/mksyscall_aix_ppc64.pl
Executable file
579
unix/mksyscall_aix_ppc64.pl
Executable file
@@ -0,0 +1,579 @@
|
||||
#!/usr/bin/env perl
|
||||
# Copyright 2018 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_aix.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 than its libc name,
|
||||
# * or the function is not in libc, name could be specified
|
||||
# * at the end, after "=" sign, like
|
||||
# //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt
|
||||
|
||||
# This program will generate three files and handle both gc and gccgo implementation:
|
||||
# - zsyscall_aix_ppc64.go: the common part of each implementation (error handler, pointer creation)
|
||||
# - zsyscall_aix_ppc64_gc.go: gc part with //go_cgo_import_dynamic and a call to syscall6
|
||||
# - zsyscall_aix_ppc64_gccgo.go: gccgo part with C function and conversion to C type.
|
||||
|
||||
# The generated code looks like this
|
||||
#
|
||||
# zsyscall_aix_ppc64.go
|
||||
# func asyscall(...) (n int, err error) {
|
||||
# // Pointer Creation
|
||||
# r1, e1 := callasyscall(...)
|
||||
# // Type Conversion
|
||||
# // Error Handler
|
||||
# return
|
||||
# }
|
||||
#
|
||||
# zsyscall_aix_ppc64_gc.go
|
||||
# //go:cgo_import_dynamic libc_asyscall asyscall "libc.a/shr_64.o"
|
||||
# //go:linkname libc_asyscall libc_asyscall
|
||||
# var asyscall syscallFunc
|
||||
#
|
||||
# func callasyscall(...) (r1 uintptr, e1 Errno) {
|
||||
# r1, _, e1 = syscall6(uintptr(unsafe.Pointer(&libc_asyscall)), "nb_args", ... )
|
||||
# return
|
||||
# }
|
||||
#
|
||||
# zsyscall_aix_ppc64_ggcgo.go
|
||||
# /*
|
||||
# int asyscall(...)
|
||||
#
|
||||
# */
|
||||
# import "C"
|
||||
#
|
||||
# func callasyscall(...) (r1 uintptr, e1 Errno) {
|
||||
# r1 = uintptr(C.asyscall(...))
|
||||
# e1 = syscall.GetErrno()
|
||||
# return
|
||||
# }
|
||||
|
||||
|
||||
|
||||
use strict;
|
||||
|
||||
my $cmdline = "mksyscall_aix_ppc64.pl " . join(' ', @ARGV);
|
||||
my $errors = 0;
|
||||
my $_32bit = "";
|
||||
my $tags = ""; # build tags
|
||||
my $aix = 0;
|
||||
my $solaris = 0;
|
||||
|
||||
binmode STDOUT;
|
||||
|
||||
if($ARGV[0] eq "-b32") {
|
||||
$_32bit = "big-endian";
|
||||
shift;
|
||||
} elsif($ARGV[0] eq "-l32") {
|
||||
$_32bit = "little-endian";
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-aix") {
|
||||
$aix = 1;
|
||||
shift;
|
||||
}
|
||||
if($ARGV[0] eq "-tags") {
|
||||
shift;
|
||||
$tags = $ARGV[0];
|
||||
shift;
|
||||
}
|
||||
|
||||
if($ARGV[0] =~ /^-/) {
|
||||
print STDERR "usage: mksyscall_aix.pl [-b32 | -l32] [-tags x,y] [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 = "";
|
||||
# GCCGO
|
||||
my $textgccgo = "";
|
||||
my $c_extern = "/*\n#include <stdint.h>\n";
|
||||
# GC
|
||||
my $textgc = "";
|
||||
my $dynimports = "";
|
||||
my $linknames = "";
|
||||
my @vars = ();
|
||||
# COMMUN
|
||||
my $textcommon = "";
|
||||
|
||||
while(<>) {
|
||||
chomp;
|
||||
s/\s+/ /g;
|
||||
s/^\s+//;
|
||||
s/\s+$//;
|
||||
$package = $1 if !$package && /^package (\S+)$/;
|
||||
my $nonblock = /^\/\/sysnb /;
|
||||
next if !/^\/\/sys / && !$nonblock;
|
||||
|
||||
# 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(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) {
|
||||
print STDERR "$ARGV:$.: malformed //sys declaration\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6);
|
||||
|
||||
# Split argument lists on comma.
|
||||
my @in = parseparamlist($in);
|
||||
my @out = parseparamlist($out);
|
||||
|
||||
$in = join(', ', @in);
|
||||
$out = join(', ', @out);
|
||||
|
||||
if($sysname eq "") {
|
||||
$sysname = "$func";
|
||||
}
|
||||
|
||||
my $onlyCommon = 0;
|
||||
if ($func eq "readlen" || $func eq "writelen" || $func eq "FcntlInt" || $func eq "FcntlFlock") {
|
||||
# This function call another syscall which is already implemented.
|
||||
# Therefore, the gc and gccgo part must not be generated.
|
||||
$onlyCommon = 1
|
||||
}
|
||||
|
||||
# Try in vain to keep people from editing this file.
|
||||
# The theory is that they jump into the middle of the file
|
||||
# without reading the header.
|
||||
|
||||
$textcommon .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
||||
if (!$onlyCommon) {
|
||||
$textgccgo .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
||||
$textgc .= "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n";
|
||||
}
|
||||
|
||||
|
||||
# Check if value return, err return available
|
||||
my $errvar = "";
|
||||
my $retvar = "";
|
||||
my $rettype = "";
|
||||
foreach my $p (@out) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type eq "error") {
|
||||
$errvar = $name;
|
||||
} else {
|
||||
$retvar = $name;
|
||||
$rettype = $type;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$sysname =~ s/([a-z])([A-Z])/${1}_$2/g;
|
||||
$sysname =~ y/A-Z/a-z/; # All libc functions are lowercase.
|
||||
|
||||
# GCCGO Prototype return type
|
||||
my $C_rettype = "";
|
||||
if($rettype eq "unsafe.Pointer") {
|
||||
$C_rettype = "uintptr_t";
|
||||
} elsif($rettype eq "uintptr") {
|
||||
$C_rettype = "uintptr_t";
|
||||
} elsif($rettype =~ /^_/) {
|
||||
$C_rettype = "uintptr_t";
|
||||
} elsif($rettype eq "int") {
|
||||
$C_rettype = "int";
|
||||
} elsif($rettype eq "int32") {
|
||||
$C_rettype = "int";
|
||||
} elsif($rettype eq "int64") {
|
||||
$C_rettype = "long long";
|
||||
} elsif($rettype eq "uint32") {
|
||||
$C_rettype = "unsigned int";
|
||||
} elsif($rettype eq "uint64") {
|
||||
$C_rettype = "unsigned long long";
|
||||
} else {
|
||||
$C_rettype = "int";
|
||||
}
|
||||
if($sysname eq "exit") {
|
||||
$C_rettype = "void";
|
||||
}
|
||||
|
||||
# GCCGO Prototype arguments type
|
||||
my @c_in = ();
|
||||
foreach my $i (0 .. $#in) {
|
||||
my ($name, $type) = parseparam($in[$i]);
|
||||
if($type =~ /^\*/) {
|
||||
push @c_in, "uintptr_t";
|
||||
} elsif($type eq "string") {
|
||||
push @c_in, "uintptr_t";
|
||||
} elsif($type =~ /^\[\](.*)/) {
|
||||
push @c_in, "uintptr_t", "size_t";
|
||||
} elsif($type eq "unsafe.Pointer") {
|
||||
push @c_in, "uintptr_t";
|
||||
} elsif($type eq "uintptr") {
|
||||
push @c_in, "uintptr_t";
|
||||
} elsif($type =~ /^_/) {
|
||||
push @c_in, "uintptr_t";
|
||||
} elsif($type eq "int") {
|
||||
if (($i == 0 || $i == 2) && $func eq "fcntl"){
|
||||
# These fcntl arguments needs to be uintptr to be able to call FcntlInt and FcntlFlock
|
||||
push @c_in, "uintptr_t";
|
||||
} else {
|
||||
push @c_in, "int";
|
||||
}
|
||||
} elsif($type eq "int32") {
|
||||
push @c_in, "int";
|
||||
} elsif($type eq "int64") {
|
||||
push @c_in, "long long";
|
||||
} elsif($type eq "uint32") {
|
||||
push @c_in, "unsigned int";
|
||||
} elsif($type eq "uint64") {
|
||||
push @c_in, "unsigned long long";
|
||||
} else {
|
||||
push @c_in, "int";
|
||||
}
|
||||
}
|
||||
|
||||
if (!$onlyCommon){
|
||||
# GCCGO Prototype Generation
|
||||
# Imports of system calls from libc
|
||||
$c_extern .= "$C_rettype $sysname";
|
||||
my $c_in = join(', ', @c_in);
|
||||
$c_extern .= "($c_in);\n";
|
||||
}
|
||||
|
||||
# GC Library name
|
||||
if($modname eq "") {
|
||||
$modname = "libc.a/shr_64.o";
|
||||
} else {
|
||||
print STDERR "$func: only syscall using libc are available\n";
|
||||
$errors = 1;
|
||||
next;
|
||||
}
|
||||
my $sysvarname = "libc_${sysname}";
|
||||
|
||||
if (!$onlyCommon){
|
||||
# GC Runtime import of function to allow cross-platform builds.
|
||||
$dynimports .= "//go:cgo_import_dynamic ${sysvarname} ${sysname} \"$modname\"\n";
|
||||
# GC Link symbol to proc address variable.
|
||||
$linknames .= "//go:linkname ${sysvarname} ${sysvarname}\n";
|
||||
# GC Library proc address variable.
|
||||
push @vars, $sysvarname;
|
||||
}
|
||||
|
||||
my $strconvfunc ="BytePtrFromString";
|
||||
my $strconvtype = "*byte";
|
||||
|
||||
# Go function header.
|
||||
if($out ne "") {
|
||||
$out = " ($out)";
|
||||
}
|
||||
if($textcommon ne "") {
|
||||
$textcommon .= "\n"
|
||||
}
|
||||
|
||||
$textcommon .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out ;
|
||||
|
||||
# Prepare arguments to call.
|
||||
my @argscommun = (); # Arguments in the commun part
|
||||
my @argscall = (); # Arguments for call prototype
|
||||
my @argsgc = (); # Arguments for gc call (with syscall6)
|
||||
my @argsgccgo = (); # Arguments for gccgo call (with C.name_of_syscall)
|
||||
my $n = 0;
|
||||
my $arg_n = 0;
|
||||
foreach my $p (@in) {
|
||||
my ($name, $type) = parseparam($p);
|
||||
if($type =~ /^\*/) {
|
||||
push @argscommun, "uintptr(unsafe.Pointer($name))";
|
||||
push @argscall, "$name uintptr";
|
||||
push @argsgc, "$name";
|
||||
push @argsgccgo, "C.uintptr_t($name)";
|
||||
} elsif($type eq "string" && $errvar ne "") {
|
||||
$textcommon .= "\tvar _p$n $strconvtype\n";
|
||||
$textcommon .= "\t_p$n, $errvar = $strconvfunc($name)\n";
|
||||
$textcommon .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
||||
|
||||
push @argscommun, "uintptr(unsafe.Pointer(_p$n))";
|
||||
push @argscall, "_p$n uintptr ";
|
||||
push @argsgc, "_p$n";
|
||||
push @argsgccgo, "C.uintptr_t(_p$n)";
|
||||
$n++;
|
||||
} elsif($type eq "string") {
|
||||
print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n";
|
||||
$textcommon .= "\tvar _p$n $strconvtype\n";
|
||||
$textcommon .= "\t_p$n, $errvar = $strconvfunc($name)\n";
|
||||
$textcommon .= "\tif $errvar != nil {\n\t\treturn\n\t}\n";
|
||||
|
||||
push @argscommun, "uintptr(unsafe.Pointer(_p$n))";
|
||||
push @argscall, "_p$n uintptr";
|
||||
push @argsgc, "_p$n";
|
||||
push @argsgccgo, "C.uintptr_t(_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.
|
||||
$textcommon .= "\tvar _p$n *$1\n";
|
||||
$textcommon .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n";
|
||||
push @argscommun, "uintptr(unsafe.Pointer(_p$n))", "len($name)";
|
||||
push @argscall, "_p$n uintptr", "_lenp$n int";
|
||||
push @argsgc, "_p$n", "uintptr(_lenp$n)";
|
||||
push @argsgccgo, "C.uintptr_t(_p$n)", "C.size_t(_lenp$n)";
|
||||
$n++;
|
||||
} elsif($type eq "int64" && $_32bit ne "") {
|
||||
print STDERR "$ARGV:$.: $func uses int64 with 32 bits mode. Case not yet implemented\n";
|
||||
# if($_32bit eq "big-endian") {
|
||||
# push @args, "uintptr($name >> 32)", "uintptr($name)";
|
||||
# } else {
|
||||
# push @args, "uintptr($name)", "uintptr($name >> 32)";
|
||||
# }
|
||||
# $n++;
|
||||
} elsif($type eq "bool") {
|
||||
print STDERR "$ARGV:$.: $func uses bool. Case not yet implemented\n";
|
||||
# $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, "_p$n";
|
||||
# $n++;
|
||||
} elsif($type =~ /^_/ ||$type eq "unsafe.Pointer") {
|
||||
push @argscommun, "uintptr($name)";
|
||||
push @argscall, "$name uintptr";
|
||||
push @argsgc, "$name";
|
||||
push @argsgccgo, "C.uintptr_t($name)";
|
||||
} elsif($type eq "int") {
|
||||
if (($arg_n == 0 || $arg_n == 2) && ($func eq "fcntl" || $func eq "FcntlInt" || $func eq "FcntlFlock")) {
|
||||
# These fcntl arguments need to be uintptr to be able to call FcntlInt and FcntlFlock
|
||||
push @argscommun, "uintptr($name)";
|
||||
push @argscall, "$name uintptr";
|
||||
push @argsgc, "$name";
|
||||
push @argsgccgo, "C.uintptr_t($name)";
|
||||
} else {
|
||||
push @argscommun, "$name";
|
||||
push @argscall, "$name int";
|
||||
push @argsgc, "uintptr($name)";
|
||||
push @argsgccgo, "C.int($name)";
|
||||
}
|
||||
} elsif($type eq "int32") {
|
||||
push @argscommun, "$name";
|
||||
push @argscall, "$name int32";
|
||||
push @argsgc, "uintptr($name)";
|
||||
push @argsgccgo, "C.int($name)";
|
||||
} elsif($type eq "int64") {
|
||||
push @argscommun, "$name";
|
||||
push @argscall, "$name int64";
|
||||
push @argsgc, "uintptr($name)";
|
||||
push @argsgccgo, "C.longlong($name)";
|
||||
} elsif($type eq "uint32") {
|
||||
push @argscommun, "$name";
|
||||
push @argscall, "$name uint32";
|
||||
push @argsgc, "uintptr($name)";
|
||||
push @argsgccgo, "C.uint($name)";
|
||||
} elsif($type eq "uint64") {
|
||||
push @argscommun, "$name";
|
||||
push @argscall, "$name uint64";
|
||||
push @argsgc, "uintptr($name)";
|
||||
push @argsgccgo, "C.ulonglong($name)";
|
||||
} elsif($type eq "uintptr") {
|
||||
push @argscommun, "$name";
|
||||
push @argscall, "$name uintptr";
|
||||
push @argsgc, "$name";
|
||||
push @argsgccgo, "C.uintptr_t($name)";
|
||||
} else {
|
||||
push @argscommun, "int($name)";
|
||||
push @argscall, "$name int";
|
||||
push @argsgc, "uintptr($name)";
|
||||
push @argsgccgo, "C.int($name)";
|
||||
}
|
||||
$arg_n++;
|
||||
}
|
||||
my $nargs = @argsgc;
|
||||
|
||||
# COMMUN function generation
|
||||
my $argscommun = join(', ', @argscommun);
|
||||
my $callcommun = "call$sysname($argscommun)";
|
||||
my @ret = ("_", "_");
|
||||
my $body = "";
|
||||
my $do_errno = 0;
|
||||
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[1] = $reg;
|
||||
$do_errno = 1;
|
||||
} else {
|
||||
$reg = "r0";
|
||||
$ret[0] = $reg;
|
||||
}
|
||||
if($type eq "bool") {
|
||||
$reg = "$reg != 0";
|
||||
}
|
||||
if($reg ne "e1") {
|
||||
$body .= "\t$name = $type($reg)\n";
|
||||
}
|
||||
}
|
||||
if ($ret[0] eq "_" && $ret[1] eq "_") {
|
||||
$textcommon .= "\t$callcommun\n";
|
||||
} else {
|
||||
$textcommon .= "\t$ret[0], $ret[1] := $callcommun\n";
|
||||
}
|
||||
$textcommon .= $body;
|
||||
|
||||
if ($do_errno) {
|
||||
$textcommon .= "\tif e1 != 0 {\n";
|
||||
$textcommon .= "\t\terr = errnoErr(e1)\n";
|
||||
$textcommon .= "\t}\n";
|
||||
}
|
||||
$textcommon .= "\treturn\n";
|
||||
$textcommon .= "}\n";
|
||||
|
||||
if ($onlyCommon){
|
||||
next
|
||||
}
|
||||
# CALL Prototype
|
||||
my $callProto = sprintf "func call%s(%s) (r1 uintptr, e1 Errno) {\n", $sysname, join(', ', @argscall);
|
||||
|
||||
# GC function generation
|
||||
my $asm = "syscall6";
|
||||
if ($nonblock) {
|
||||
$asm = "rawSyscall6";
|
||||
}
|
||||
|
||||
if(@argsgc <= 6) {
|
||||
while(@argsgc < 6) {
|
||||
push @argsgc, "0";
|
||||
}
|
||||
} else {
|
||||
print STDERR "$ARGV:$.: too many arguments to system call\n";
|
||||
}
|
||||
my $argsgc = join(', ', @argsgc);
|
||||
my $callgc = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $argsgc)";
|
||||
|
||||
$textgc .= $callProto;
|
||||
$textgc .= "\tr1, _, e1 = $callgc\n";
|
||||
$textgc .= "\treturn\n}\n";
|
||||
|
||||
# GCCGO function generation
|
||||
my $argsgccgo = join(', ', @argsgccgo);
|
||||
my $callgccgo = "C.$sysname($argsgccgo)";
|
||||
$textgccgo .= $callProto;
|
||||
$textgccgo .= "\tr1 = uintptr($callgccgo)\n";
|
||||
$textgccgo .= "\te1 = syscall.GetErrno()\n";
|
||||
$textgccgo .= "\treturn\n}\n";
|
||||
}
|
||||
|
||||
if($errors) {
|
||||
exit 1;
|
||||
}
|
||||
|
||||
# Print zsyscall_aix_ppc64.go
|
||||
open(my $fcommun, '>', 'zsyscall_aix_ppc64.go');
|
||||
my $tofcommun = <<EOF;
|
||||
// $cmdline
|
||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||
|
||||
// +build $tags
|
||||
|
||||
package $package
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
EOF
|
||||
|
||||
$tofcommun .= "import \"golang.org/x/sys/unix\"\n" if $package ne "unix";
|
||||
|
||||
$tofcommun .=<<EOF;
|
||||
|
||||
$textcommon
|
||||
EOF
|
||||
print $fcommun $tofcommun;
|
||||
|
||||
|
||||
# Print zsyscall_aix_ppc64_gc.go
|
||||
open(my $fgc, '>', 'zsyscall_aix_ppc64_gc.go');
|
||||
my $tofgc = <<EOF;
|
||||
// $cmdline
|
||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||
|
||||
// +build $tags
|
||||
// +build !gccgo
|
||||
|
||||
package $package
|
||||
|
||||
import (
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
$tofgc .= "import \"golang.org/x/sys/unix\"\n" if $package ne "unix";
|
||||
|
||||
my $vardecls = "\t" . join(",\n\t", @vars);
|
||||
$vardecls .= " syscallFunc";
|
||||
|
||||
$tofgc .=<<EOF;
|
||||
$dynimports
|
||||
$linknames
|
||||
type syscallFunc uintptr
|
||||
|
||||
var (
|
||||
$vardecls
|
||||
)
|
||||
|
||||
// Implemented in runtime/syscall_aix.go.
|
||||
func rawSyscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||
func syscall6(trap, nargs, a1, a2, a3, a4, a5, a6 uintptr) (r1, r2 uintptr, err Errno)
|
||||
|
||||
$textgc
|
||||
EOF
|
||||
print $fgc $tofgc;
|
||||
|
||||
# Print zsyscall_aix_ppc64_gc.go
|
||||
open(my $fgccgo, '>', 'zsyscall_aix_ppc64_gccgo.go');
|
||||
my $tofgccgo = <<EOF;
|
||||
// $cmdline
|
||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||
|
||||
// +build $tags
|
||||
// +build gccgo
|
||||
|
||||
package $package
|
||||
|
||||
|
||||
$c_extern
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"syscall"
|
||||
)
|
||||
|
||||
|
||||
EOF
|
||||
|
||||
$tofgccgo .= "import \"golang.org/x/sys/unix\"\n" if $package ne "unix";
|
||||
|
||||
$tofgccgo .=<<EOF;
|
||||
|
||||
$textgccgo
|
||||
EOF
|
||||
print $fgccgo $tofgccgo;
|
||||
exit 0;
|
||||
@@ -305,11 +305,11 @@ func Wait4(pid int, wstatus *WaitStatus, options int, rusage *Rusage) (wpid int,
|
||||
type WaitStatus uint32
|
||||
|
||||
func (w WaitStatus) Stopped() bool { return w&0x40 != 0 }
|
||||
func (w WaitStatus) StopSignal() syscall.Signal {
|
||||
func (w WaitStatus) StopSignal() Signal {
|
||||
if !w.Stopped() {
|
||||
return -1
|
||||
}
|
||||
return syscall.Signal(w>>8) & 0xFF
|
||||
return Signal(w>>8) & 0xFF
|
||||
}
|
||||
|
||||
func (w WaitStatus) Exited() bool { return w&0xFF == 0 }
|
||||
@@ -321,11 +321,11 @@ func (w WaitStatus) ExitStatus() int {
|
||||
}
|
||||
|
||||
func (w WaitStatus) Signaled() bool { return w&0x40 == 0 && w&0xFF != 0 }
|
||||
func (w WaitStatus) Signal() syscall.Signal {
|
||||
func (w WaitStatus) Signal() Signal {
|
||||
if !w.Signaled() {
|
||||
return -1
|
||||
}
|
||||
return syscall.Signal(w>>16) & 0xFF
|
||||
return Signal(w>>16) & 0xFF
|
||||
}
|
||||
|
||||
func (w WaitStatus) Continued() bool { return w&0x01000000 != 0 }
|
||||
@@ -383,6 +383,8 @@ func IoctlGetTermios(fd int, req uint) (*Termios, error) {
|
||||
// FcntlFlock performs a fcntl syscall for the F_GETLK, F_SETLK or F_SETLKW command.
|
||||
//sys FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) = fcntl
|
||||
|
||||
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
||||
|
||||
func Flock(fd int, how int) (err error) {
|
||||
return syscall.Flock(fd, how)
|
||||
}
|
||||
@@ -396,15 +398,12 @@ func Flock(fd int, how int) (err error) {
|
||||
//sys Chroot(path string) (err error)
|
||||
//sys Close(fd int) (err error)
|
||||
//sys Dup(oldfd int) (fd int, err error)
|
||||
//sys Dup3(oldfd int, newfd int, flags int) (err error)
|
||||
//sys Exit(code int)
|
||||
//sys Faccessat(dirfd int, path string, mode uint32, flags int) (err error)
|
||||
//sys Fallocate(fd int, mode uint32, off int64, len int64) (err error)
|
||||
//sys Fchdir(fd int) (err error)
|
||||
//sys Fchmod(fd int, mode uint32) (err error)
|
||||
//sys Fchmodat(dirfd int, path string, mode uint32, flags int) (err error)
|
||||
//sys Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error)
|
||||
//sys fcntl(fd int, cmd int, arg int) (val int, err error)
|
||||
//sys Fdatasync(fd int) (err error)
|
||||
//sys Fsync(fd int) (err error)
|
||||
// readdir_r
|
||||
@@ -417,7 +416,7 @@ func Flock(fd int, how int) (err error) {
|
||||
//sys Getpriority(which int, who int) (prio int, err error)
|
||||
//sysnb Getrusage(who int, rusage *Rusage) (err error)
|
||||
//sysnb Getsid(pid int) (sid int, err error)
|
||||
//sysnb Kill(pid int, sig syscall.Signal) (err error)
|
||||
//sysnb Kill(pid int, sig Signal) (err error)
|
||||
//sys Klogctl(typ int, buf []byte) (n int, err error) = syslog
|
||||
//sys Mkdir(dirfd int, path string, mode uint32) (err error)
|
||||
//sys Mkdirat(dirfd int, path string, mode uint32) (err error)
|
||||
@@ -429,7 +428,6 @@ func Flock(fd int, how int) (err error) {
|
||||
//sys Openat(dirfd int, path string, flags int, mode uint32) (fd int, err error)
|
||||
//sys read(fd int, p []byte) (n int, err error)
|
||||
//sys Readlink(path string, buf []byte) (n int, err error)
|
||||
//sys Removexattr(path string, attr string) (err error)
|
||||
//sys Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error)
|
||||
//sys Setdomainname(p []byte) (err error)
|
||||
//sys Sethostname(p []byte) (err error)
|
||||
@@ -443,7 +441,6 @@ func Flock(fd int, how int) (err error) {
|
||||
//sys Setpriority(which int, who int, prio int) (err error)
|
||||
//sys Statx(dirfd int, path string, flags int, mask int, stat *Statx_t) (err error)
|
||||
//sys Sync()
|
||||
//sys Tee(rfd int, wfd int, len int, flags int) (n int64, err error)
|
||||
//sysnb Times(tms *Tms) (ticks uintptr, err error)
|
||||
//sysnb Umask(mask int) (oldmask int)
|
||||
//sysnb Uname(buf *Utsname) (err error)
|
||||
@@ -451,7 +448,6 @@ func Flock(fd int, how int) (err error) {
|
||||
// //sys Unmount(target string, flags int) (err error) = umount
|
||||
//sys Unlink(path string) (err error)
|
||||
//sys Unlinkat(dirfd int, path string, flags int) (err error)
|
||||
//sys Unshare(flags int) (err error)
|
||||
//sys Ustat(dev int, ubuf *Ustat_t) (err error)
|
||||
//sys write(fd int, p []byte) (n int, err error)
|
||||
//sys readlen(fd int, p *byte, np int) (n int, err error) = read
|
||||
@@ -537,19 +533,6 @@ func Pipe(p []int) (err error) {
|
||||
return
|
||||
}
|
||||
|
||||
//sysnb pipe2(p *[2]_C_int, flags int) (err error)
|
||||
|
||||
func Pipe2(p []int, flags int) (err error) {
|
||||
if len(p) != 2 {
|
||||
return EINVAL
|
||||
}
|
||||
var pp [2]_C_int
|
||||
err = pipe2(&pp, flags)
|
||||
p[0] = int(pp[0])
|
||||
p[1] = int(pp[1])
|
||||
return
|
||||
}
|
||||
|
||||
//sys poll(fds *PollFd, nfds int, timeout int) (n int, err error)
|
||||
|
||||
func Poll(fds []PollFd, timeout int) (n int, err error) {
|
||||
|
||||
@@ -86,7 +86,7 @@ func TestUtimesNanoAt(t *testing.T) {
|
||||
defer chtmpdir(t)()
|
||||
|
||||
symlink := "symlink1"
|
||||
os.Remove(symlink)
|
||||
defer os.Remove(symlink)
|
||||
err := os.Symlink("nonexisting", symlink)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// mksyscall_aix.pl -aix -tags aix,ppc syscall_aix.go syscall_aix_ppc.go
|
||||
// mksyscall_aix_ppc.pl -aix -tags aix,ppc syscall_aix.go syscall_aix_ppc.go
|
||||
// Code generated by the command above; see README.md. DO NOT EDIT.
|
||||
|
||||
// +build aix,ppc
|
||||
@@ -7,6 +7,7 @@ package unix
|
||||
|
||||
/*
|
||||
#include <stdint.h>
|
||||
#include <stddef.h>
|
||||
int utimes(uintptr_t, uintptr_t);
|
||||
int utimensat(int, uintptr_t, uintptr_t, int);
|
||||
int getcwd(uintptr_t, size_t);
|
||||
@@ -20,10 +21,8 @@ int chdir(uintptr_t);
|
||||
int chroot(uintptr_t);
|
||||
int close(int);
|
||||
int dup(int);
|
||||
int dup3(int, int, int);
|
||||
void exit(int);
|
||||
int faccessat(int, uintptr_t, unsigned int, int);
|
||||
int fallocate(int, unsigned int, long long, long long);
|
||||
int fchdir(int);
|
||||
int fchmod(int, unsigned int);
|
||||
int fchmodat(int, uintptr_t, unsigned int, int);
|
||||
@@ -49,7 +48,6 @@ int open64(uintptr_t, int, unsigned int);
|
||||
int openat(int, uintptr_t, int, unsigned int);
|
||||
int read(int, uintptr_t, size_t);
|
||||
int readlink(uintptr_t, uintptr_t, size_t);
|
||||
int removexattr(uintptr_t, uintptr_t);
|
||||
int renameat(int, uintptr_t, int, uintptr_t);
|
||||
int setdomainname(uintptr_t, size_t);
|
||||
int sethostname(uintptr_t, size_t);
|
||||
@@ -61,13 +59,11 @@ int setgid(int);
|
||||
int setpriority(int, int, int);
|
||||
int statx(int, uintptr_t, int, int, uintptr_t);
|
||||
int sync();
|
||||
long long tee(int, int, int, int);
|
||||
uintptr_t times(uintptr_t);
|
||||
int umask(int);
|
||||
int uname(uintptr_t);
|
||||
int unlink(uintptr_t);
|
||||
int unlinkat(int, uintptr_t, int);
|
||||
int unshare(int);
|
||||
int ustat(int, uintptr_t);
|
||||
int write(int, uintptr_t, size_t);
|
||||
int dup2(int, int);
|
||||
@@ -118,7 +114,6 @@ int msync(uintptr_t, size_t, int);
|
||||
int munlock(uintptr_t, size_t);
|
||||
int munlockall();
|
||||
int pipe(uintptr_t);
|
||||
int pipe2(uintptr_t, int);
|
||||
int poll(uintptr_t, int, int);
|
||||
int gettimeofday(uintptr_t, uintptr_t);
|
||||
int time(uintptr_t);
|
||||
@@ -131,7 +126,6 @@ uintptr_t mmap(uintptr_t, uintptr_t, int, int, int, long long);
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"syscall"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
@@ -245,6 +239,17 @@ func FcntlFlock(fd uintptr, cmd int, lk *Flock_t) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fcntl(fd int, cmd int, arg int) (val int, err error) {
|
||||
r0, er := C.fcntl(C.uintptr_t(fd), C.int(cmd), C.uintptr_t(arg))
|
||||
val = int(r0)
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Acct(path string) (err error) {
|
||||
_p0 := uintptr(unsafe.Pointer(C.CString(path)))
|
||||
r0, er := C.acct(C.uintptr_t(_p0))
|
||||
@@ -299,16 +304,6 @@ func Dup(oldfd int) (fd int, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Dup3(oldfd int, newfd int, flags int) (err error) {
|
||||
r0, er := C.dup3(C.int(oldfd), C.int(newfd), C.int(flags))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Exit(code int) {
|
||||
C.exit(C.int(code))
|
||||
return
|
||||
@@ -327,16 +322,6 @@ func Faccessat(dirfd int, path string, mode uint32, flags int) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fallocate(fd int, mode uint32, off int64, len int64) (err error) {
|
||||
r0, er := C.fallocate(C.int(fd), C.uint(mode), C.longlong(off), C.longlong(len))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fchdir(fd int) (err error) {
|
||||
r0, er := C.fchdir(C.int(fd))
|
||||
if r0 == -1 && er != nil {
|
||||
@@ -379,17 +364,6 @@ func Fchownat(dirfd int, path string, uid int, gid int, flags int) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func fcntl(fd int, cmd int, arg int) (val int, err error) {
|
||||
r0, er := C.fcntl(C.uintptr_t(fd), C.int(cmd), C.uintptr_t(arg))
|
||||
val = int(r0)
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Fdatasync(fd int) (err error) {
|
||||
r0, er := C.fdatasync(C.int(fd))
|
||||
if r0 == -1 && er != nil {
|
||||
@@ -477,7 +451,7 @@ func Getsid(pid int) (sid int, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Kill(pid int, sig syscall.Signal) (err error) {
|
||||
func Kill(pid int, sig Signal) (err error) {
|
||||
r0, er := C.kill(C.int(pid), C.int(sig))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
@@ -628,18 +602,6 @@ func Readlink(path string, buf []byte) (n int, err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Removexattr(path string, attr string) (err error) {
|
||||
_p0 := uintptr(unsafe.Pointer(C.CString(path)))
|
||||
_p1 := uintptr(unsafe.Pointer(C.CString(attr)))
|
||||
r0, er := C.removexattr(C.uintptr_t(_p0), C.uintptr_t(_p1))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Renameat(olddirfd int, oldpath string, newdirfd int, newpath string) (err error) {
|
||||
_p0 := uintptr(unsafe.Pointer(C.CString(oldpath)))
|
||||
_p1 := uintptr(unsafe.Pointer(C.CString(newpath)))
|
||||
@@ -763,17 +725,6 @@ func Sync() {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Tee(rfd int, wfd int, len int, flags int) (n int64, err error) {
|
||||
r0, er := C.tee(C.int(rfd), C.int(wfd), C.int(len), C.int(flags))
|
||||
n = int64(r0)
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Times(tms *Tms) (ticks uintptr, err error) {
|
||||
r0, er := C.times(C.uintptr_t(uintptr(unsafe.Pointer(tms))))
|
||||
ticks = uintptr(r0)
|
||||
@@ -825,16 +776,6 @@ func Unlinkat(dirfd int, path string, flags int) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Unshare(flags int) (err error) {
|
||||
r0, er := C.unshare(C.int(flags))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func Ustat(dev int, ubuf *Ustat_t) (err error) {
|
||||
r0, er := C.ustat(C.int(dev), C.uintptr_t(uintptr(unsafe.Pointer(ubuf))))
|
||||
if r0 == -1 && er != nil {
|
||||
@@ -1425,16 +1366,6 @@ func pipe(p *[2]_C_int) (err error) {
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func pipe2(p *[2]_C_int, flags int) (err error) {
|
||||
r0, er := C.pipe2(C.uintptr_t(uintptr(unsafe.Pointer(p))), C.int(flags))
|
||||
if r0 == -1 && er != nil {
|
||||
err = er
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
|
||||
|
||||
func poll(fds *PollFd, nfds int, timeout int) (n int, err error) {
|
||||
r0, er := C.poll(C.uintptr_t(uintptr(unsafe.Pointer(fds))), C.int(nfds), C.int(timeout))
|
||||
n = int(r0)
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
1162
unix/zsyscall_aix_ppc64_gc.go
Normal file
1162
unix/zsyscall_aix_ppc64_gc.go
Normal file
File diff suppressed because it is too large
Load Diff
1042
unix/zsyscall_aix_ppc64_gccgo.go
Normal file
1042
unix/zsyscall_aix_ppc64_gccgo.go
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user