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