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