github.com/epfl-dcsl/gotee@v0.0.0-20200909122901-014b35f5e5e9/src/syscall/mksyscall_solaris.pl (about) 1 #!/usr/bin/env perl 2 # Copyright 2009 The Go Authors. All rights reserved. 3 # Use of this source code is governed by a BSD-style 4 # license that can be found in the LICENSE file. 5 6 # This program reads a file containing function prototypes 7 # (like syscall_solaris.go) and generates system call bodies. 8 # The prototypes are marked by lines beginning with "//sys" 9 # and read like func declarations if //sys is replaced by func, but: 10 # * The parameter lists must give a name for each argument. 11 # This includes return parameters. 12 # * The parameter lists must give a type for each argument: 13 # the (x, y, z int) shorthand is not allowed. 14 # * If the return parameter is an error number, it must be named err. 15 # * If go func name needs to be different than its libc name, 16 # * or the function is not in libc, name could be specified 17 # * at the end, after "=" sign, like 18 # //sys getsockopt(s int, level int, name int, val uintptr, vallen *_Socklen) (err error) = libsocket.getsockopt 19 20 use strict; 21 22 my $cmdline = "mksyscall_solaris.pl " . join(' ', @ARGV); 23 my $errors = 0; 24 my $_32bit = ""; 25 my $tags = ""; # build tags 26 27 binmode STDOUT; 28 29 if($ARGV[0] eq "-b32") { 30 $_32bit = "big-endian"; 31 shift; 32 } elsif($ARGV[0] eq "-l32") { 33 $_32bit = "little-endian"; 34 shift; 35 } 36 if($ARGV[0] eq "-tags") { 37 shift; 38 $tags = $ARGV[0]; 39 shift; 40 } 41 42 if($ARGV[0] =~ /^-/) { 43 print STDERR "usage: mksyscall_solaris.pl [-b32 | -l32] [-tags x,y] [file ...]\n"; 44 exit 1; 45 } 46 47 sub parseparamlist($) { 48 my ($list) = @_; 49 $list =~ s/^\s*//; 50 $list =~ s/\s*$//; 51 if($list eq "") { 52 return (); 53 } 54 return split(/\s*,\s*/, $list); 55 } 56 57 sub parseparam($) { 58 my ($p) = @_; 59 if($p !~ /^(\S*) (\S*)$/) { 60 print STDERR "$ARGV:$.: malformed parameter: $p\n"; 61 $errors = 1; 62 return ("xx", "int"); 63 } 64 return ($1, $2); 65 } 66 67 my $package = ""; 68 my $text = ""; 69 my $dynimports = ""; 70 my $linknames = ""; 71 my @vars = (); 72 while(<>) { 73 chomp; 74 s/\s+/ /g; 75 s/^\s+//; 76 s/\s+$//; 77 $package = $1 if !$package && /^package (\S+)$/; 78 my $nonblock = /^\/\/sysnb /; 79 next if !/^\/\/sys / && !$nonblock; 80 81 my $syscalldot = ""; 82 $syscalldot = "syscall." if $package ne "syscall"; 83 84 # Line must be of the form 85 # func Open(path string, mode int, perm int) (fd int, err error) 86 # Split into name, in params, out params. 87 if(!/^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*(?:(\w*)\.)?(\w*))?$/) { 88 print STDERR "$ARGV:$.: malformed //sys declaration\n"; 89 $errors = 1; 90 next; 91 } 92 my ($nb, $func, $in, $out, $modname, $sysname) = ($1, $2, $3, $4, $5, $6); 93 94 # Split argument lists on comma. 95 my @in = parseparamlist($in); 96 my @out = parseparamlist($out); 97 98 # So file name. 99 if($modname eq "") { 100 $modname = "libc"; 101 } 102 103 # System call name. 104 if($sysname eq "") { 105 $sysname = "$func"; 106 } 107 108 # System call pointer variable name. 109 my $sysvarname = "libc_${sysname}"; 110 111 my $strconvfunc = "BytePtrFromString"; 112 my $strconvtype = "*byte"; 113 114 $sysname =~ y/A-Z/a-z/; # All libc functions are lowercase. 115 116 # Runtime import of function to allow cross-platform builds. 117 $dynimports .= "//go:cgo_import_dynamic ${sysvarname} ${sysname} \"$modname.so\"\n"; 118 # Link symbol to proc address variable. 119 $linknames .= "//go:linkname ${sysvarname} ${sysvarname}\n"; 120 # Library proc address variable. 121 push @vars, $sysvarname; 122 123 # Go function header. 124 $out = join(', ', @out); 125 if($out ne "") { 126 $out = " ($out)"; 127 } 128 if($text ne "") { 129 $text .= "\n" 130 } 131 $text .= sprintf "func %s(%s)%s {\n", $func, join(', ', @in), $out; 132 133 # Check if err return available 134 my $errvar = ""; 135 foreach my $p (@out) { 136 my ($name, $type) = parseparam($p); 137 if($type eq "error") { 138 $errvar = $name; 139 last; 140 } 141 } 142 143 # Prepare arguments to Syscall. 144 my @args = (); 145 my $n = 0; 146 foreach my $p (@in) { 147 my ($name, $type) = parseparam($p); 148 if($type =~ /^\*/) { 149 push @args, "uintptr(unsafe.Pointer($name))"; 150 } elsif($type eq "string" && $errvar ne "") { 151 $text .= "\tvar _p$n $strconvtype\n"; 152 $text .= "\t_p$n, $errvar = $strconvfunc($name)\n"; 153 $text .= "\tif $errvar != nil {\n\t\treturn\n\t}\n"; 154 push @args, "uintptr(unsafe.Pointer(_p$n))"; 155 $n++; 156 } elsif($type eq "string") { 157 print STDERR "$ARGV:$.: $func uses string arguments, but has no error return\n"; 158 $text .= "\tvar _p$n $strconvtype\n"; 159 $text .= "\t_p$n, _ = $strconvfunc($name)\n"; 160 push @args, "uintptr(unsafe.Pointer(_p$n))"; 161 $n++; 162 } elsif($type =~ /^\[\](.*)/) { 163 # Convert slice into pointer, length. 164 # Have to be careful not to take address of &a[0] if len == 0: 165 # pass nil in that case. 166 $text .= "\tvar _p$n *$1\n"; 167 $text .= "\tif len($name) > 0 {\n\t\t_p$n = \&$name\[0]\n\t}\n"; 168 push @args, "uintptr(unsafe.Pointer(_p$n))", "uintptr(len($name))"; 169 $n++; 170 } elsif($type eq "int64" && $_32bit ne "") { 171 if($_32bit eq "big-endian") { 172 push @args, "uintptr($name >> 32)", "uintptr($name)"; 173 } else { 174 push @args, "uintptr($name)", "uintptr($name >> 32)"; 175 } 176 } elsif($type eq "bool") { 177 $text .= "\tvar _p$n uint32\n"; 178 $text .= "\tif $name {\n\t\t_p$n = 1\n\t} else {\n\t\t_p$n = 0\n\t}\n"; 179 push @args, "uintptr(_p$n)"; 180 $n++; 181 } else { 182 push @args, "uintptr($name)"; 183 } 184 } 185 my $nargs = @args; 186 187 # Determine which form to use; pad args with zeros. 188 my $asm = "${syscalldot}sysvicall6"; 189 if ($nonblock) { 190 $asm = "${syscalldot}rawSysvicall6"; 191 } 192 if(@args <= 6) { 193 while(@args < 6) { 194 push @args, "0"; 195 } 196 } else { 197 print STDERR "$ARGV:$.: too many arguments to system call\n"; 198 } 199 200 # Actual call. 201 my $args = join(', ', @args); 202 my $call = "$asm(uintptr(unsafe.Pointer(&$sysvarname)), $nargs, $args)"; 203 204 # Assign return values. 205 my $body = ""; 206 my $failexpr = ""; 207 my @ret = ("_", "_", "_"); 208 my @pout= (); 209 my $do_errno = 0; 210 for(my $i=0; $i<@out; $i++) { 211 my $p = $out[$i]; 212 my ($name, $type) = parseparam($p); 213 my $reg = ""; 214 if($name eq "err") { 215 $reg = "e1"; 216 $ret[2] = $reg; 217 $do_errno = 1; 218 } else { 219 $reg = sprintf("r%d", $i); 220 $ret[$i] = $reg; 221 } 222 if($type eq "bool") { 223 $reg = "$reg != 0"; 224 } 225 if($type eq "int64" && $_32bit ne "") { 226 # 64-bit number in r1:r0 or r0:r1. 227 if($i+2 > @out) { 228 print STDERR "$ARGV:$.: not enough registers for int64 return\n"; 229 } 230 if($_32bit eq "big-endian") { 231 $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i, $i+1); 232 } else { 233 $reg = sprintf("int64(r%d)<<32 | int64(r%d)", $i+1, $i); 234 } 235 $ret[$i] = sprintf("r%d", $i); 236 $ret[$i+1] = sprintf("r%d", $i+1); 237 } 238 if($reg ne "e1") { 239 $body .= "\t$name = $type($reg)\n"; 240 } 241 } 242 if ($ret[0] eq "_" && $ret[1] eq "_" && $ret[2] eq "_") { 243 $text .= "\t$call\n"; 244 } else { 245 $text .= "\t$ret[0], $ret[1], $ret[2] := $call\n"; 246 } 247 $text .= $body; 248 249 if ($do_errno) { 250 $text .= "\tif e1 != 0 {\n"; 251 $text .= "\t\terr = errnoErr(e1)\n"; 252 $text .= "\t}\n"; 253 } 254 $text .= "\treturn\n"; 255 $text .= "}\n"; 256 } 257 258 if($errors) { 259 exit 1; 260 } 261 262 print <<EOF; 263 // $cmdline 264 // MACHINE GENERATED BY THE COMMAND ABOVE; DO NOT EDIT 265 266 // +build $tags 267 268 package $package 269 270 import "unsafe" 271 EOF 272 273 print "import \"syscall\"\n" if $package ne "syscall"; 274 275 my $vardecls = "\t" . join(",\n\t", @vars); 276 $vardecls .= " libcFunc"; 277 278 chomp($_=<<EOF); 279 280 $dynimports 281 $linknames 282 type libcFunc uintptr 283 284 var ( 285 $vardecls 286 ) 287 288 $text 289 EOF 290 print $_; 291 exit 0;