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