github.com/miolini/go@v0.0.0-20160405192216-fca68c8cb408/src/syscall/mksyscall_windows.go (about) 1 // Copyright 2013 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 // +build ignore 6 7 /* 8 mksyscall_windows generates windows system call bodies 9 10 It parses all files specified on command line containing function 11 prototypes (like syscall_windows.go) and prints system call bodies 12 to standard output. 13 14 The prototypes are marked by lines beginning with "//sys" and read 15 like func declarations if //sys is replaced by func, but: 16 17 * The parameter lists must give a name for each argument. This 18 includes return parameters. 19 20 * The parameter lists must give a type for each argument: 21 the (x, y, z int) shorthand is not allowed. 22 23 * If the return parameter is an error number, it must be named err. 24 25 * If go func name needs to be different from it's winapi dll name, 26 the winapi name could be specified at the end, after "=" sign, like 27 //sys LoadLibrary(libname string) (handle uint32, err error) = LoadLibraryA 28 29 * Each function that returns err needs to supply a condition, that 30 return value of winapi will be tested against to detect failure. 31 This would set err to windows "last-error", otherwise it will be nil. 32 The value can be provided at end of //sys declaration, like 33 //sys LoadLibrary(libname string) (handle uint32, err error) [failretval==-1] = LoadLibraryA 34 and is [failretval==0] by default. 35 36 Usage: 37 mksyscall_windows [flags] [path ...] 38 39 The flags are: 40 -output 41 Specify output file name (outputs to console if blank). 42 -trace 43 Generate print statement after every syscall. 44 */ 45 package main 46 47 import ( 48 "bufio" 49 "bytes" 50 "errors" 51 "flag" 52 "fmt" 53 "go/format" 54 "go/parser" 55 "go/token" 56 "io" 57 "io/ioutil" 58 "log" 59 "os" 60 "sort" 61 "strconv" 62 "strings" 63 "text/template" 64 ) 65 66 var ( 67 filename = flag.String("output", "", "output file name (standard output if omitted)") 68 printTraceFlag = flag.Bool("trace", false, "generate print statement after every syscall") 69 systemDLL = flag.Bool("systemdll", false, "whether all DLLs should be loaded from the Windows system directory") 70 sysRepo = flag.Bool("xsys", false, "whether this code is for the x/sys subrepo") 71 ) 72 73 func trim(s string) string { 74 return strings.Trim(s, " \t") 75 } 76 77 var packageName string 78 79 func packagename() string { 80 return packageName 81 } 82 83 func syscalldot() string { 84 if packageName == "syscall" { 85 return "" 86 } 87 return "syscall." 88 } 89 90 // Param is function parameter 91 type Param struct { 92 Name string 93 Type string 94 fn *Fn 95 tmpVarIdx int 96 } 97 98 // tmpVar returns temp variable name that will be used to represent p during syscall. 99 func (p *Param) tmpVar() string { 100 if p.tmpVarIdx < 0 { 101 p.tmpVarIdx = p.fn.curTmpVarIdx 102 p.fn.curTmpVarIdx++ 103 } 104 return fmt.Sprintf("_p%d", p.tmpVarIdx) 105 } 106 107 // BoolTmpVarCode returns source code for bool temp variable. 108 func (p *Param) BoolTmpVarCode() string { 109 const code = `var %s uint32 110 if %s { 111 %s = 1 112 } else { 113 %s = 0 114 }` 115 tmp := p.tmpVar() 116 return fmt.Sprintf(code, tmp, p.Name, tmp, tmp) 117 } 118 119 // SliceTmpVarCode returns source code for slice temp variable. 120 func (p *Param) SliceTmpVarCode() string { 121 const code = `var %s *%s 122 if len(%s) > 0 { 123 %s = &%s[0] 124 }` 125 tmp := p.tmpVar() 126 return fmt.Sprintf(code, tmp, p.Type[2:], p.Name, tmp, p.Name) 127 } 128 129 // StringTmpVarCode returns source code for string temp variable. 130 func (p *Param) StringTmpVarCode() string { 131 errvar := p.fn.Rets.ErrorVarName() 132 if errvar == "" { 133 errvar = "_" 134 } 135 tmp := p.tmpVar() 136 const code = `var %s %s 137 %s, %s = %s(%s)` 138 s := fmt.Sprintf(code, tmp, p.fn.StrconvType(), tmp, errvar, p.fn.StrconvFunc(), p.Name) 139 if errvar == "-" { 140 return s 141 } 142 const morecode = ` 143 if %s != nil { 144 return 145 }` 146 return s + fmt.Sprintf(morecode, errvar) 147 } 148 149 // TmpVarCode returns source code for temp variable. 150 func (p *Param) TmpVarCode() string { 151 switch { 152 case p.Type == "bool": 153 return p.BoolTmpVarCode() 154 case strings.HasPrefix(p.Type, "[]"): 155 return p.SliceTmpVarCode() 156 default: 157 return "" 158 } 159 } 160 161 // TmpVarHelperCode returns source code for helper's temp variable. 162 func (p *Param) TmpVarHelperCode() string { 163 if p.Type != "string" { 164 return "" 165 } 166 return p.StringTmpVarCode() 167 } 168 169 // SyscallArgList returns source code fragments representing p parameter 170 // in syscall. Slices are translated into 2 syscall parameters: pointer to 171 // the first element and length. 172 func (p *Param) SyscallArgList() []string { 173 t := p.HelperType() 174 var s string 175 switch { 176 case t[0] == '*': 177 s = fmt.Sprintf("unsafe.Pointer(%s)", p.Name) 178 case t == "bool": 179 s = p.tmpVar() 180 case strings.HasPrefix(t, "[]"): 181 return []string{ 182 fmt.Sprintf("uintptr(unsafe.Pointer(%s))", p.tmpVar()), 183 fmt.Sprintf("uintptr(len(%s))", p.Name), 184 } 185 default: 186 s = p.Name 187 } 188 return []string{fmt.Sprintf("uintptr(%s)", s)} 189 } 190 191 // IsError determines if p parameter is used to return error. 192 func (p *Param) IsError() bool { 193 return p.Name == "err" && p.Type == "error" 194 } 195 196 // HelperType returns type of parameter p used in helper function. 197 func (p *Param) HelperType() string { 198 if p.Type == "string" { 199 return p.fn.StrconvType() 200 } 201 return p.Type 202 } 203 204 // join concatenates parameters ps into a string with sep separator. 205 // Each parameter is converted into string by applying fn to it 206 // before conversion. 207 func join(ps []*Param, fn func(*Param) string, sep string) string { 208 if len(ps) == 0 { 209 return "" 210 } 211 a := make([]string, 0) 212 for _, p := range ps { 213 a = append(a, fn(p)) 214 } 215 return strings.Join(a, sep) 216 } 217 218 // Rets describes function return parameters. 219 type Rets struct { 220 Name string 221 Type string 222 ReturnsError bool 223 FailCond string 224 } 225 226 // ErrorVarName returns error variable name for r. 227 func (r *Rets) ErrorVarName() string { 228 if r.ReturnsError { 229 return "err" 230 } 231 if r.Type == "error" { 232 return r.Name 233 } 234 return "" 235 } 236 237 // ToParams converts r into slice of *Param. 238 func (r *Rets) ToParams() []*Param { 239 ps := make([]*Param, 0) 240 if len(r.Name) > 0 { 241 ps = append(ps, &Param{Name: r.Name, Type: r.Type}) 242 } 243 if r.ReturnsError { 244 ps = append(ps, &Param{Name: "err", Type: "error"}) 245 } 246 return ps 247 } 248 249 // List returns source code of syscall return parameters. 250 func (r *Rets) List() string { 251 s := join(r.ToParams(), func(p *Param) string { return p.Name + " " + p.Type }, ", ") 252 if len(s) > 0 { 253 s = "(" + s + ")" 254 } 255 return s 256 } 257 258 // PrintList returns source code of trace printing part correspondent 259 // to syscall return values. 260 func (r *Rets) PrintList() string { 261 return join(r.ToParams(), func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `) 262 } 263 264 // SetReturnValuesCode returns source code that accepts syscall return values. 265 func (r *Rets) SetReturnValuesCode() string { 266 if r.Name == "" && !r.ReturnsError { 267 return "" 268 } 269 retvar := "r0" 270 if r.Name == "" { 271 retvar = "r1" 272 } 273 errvar := "_" 274 if r.ReturnsError { 275 errvar = "e1" 276 } 277 return fmt.Sprintf("%s, _, %s := ", retvar, errvar) 278 } 279 280 func (r *Rets) useLongHandleErrorCode(retvar string) string { 281 const code = `if %s { 282 if e1 != 0 { 283 err = error(e1) 284 } else { 285 err = %sEINVAL 286 } 287 }` 288 cond := retvar + " == 0" 289 if r.FailCond != "" { 290 cond = strings.Replace(r.FailCond, "failretval", retvar, 1) 291 } 292 return fmt.Sprintf(code, cond, syscalldot()) 293 } 294 295 // SetErrorCode returns source code that sets return parameters. 296 func (r *Rets) SetErrorCode() string { 297 const code = `if r0 != 0 { 298 %s = %sErrno(r0) 299 }` 300 if r.Name == "" && !r.ReturnsError { 301 return "" 302 } 303 if r.Name == "" { 304 return r.useLongHandleErrorCode("r1") 305 } 306 if r.Type == "error" { 307 return fmt.Sprintf(code, r.Name, syscalldot()) 308 } 309 s := "" 310 switch { 311 case r.Type[0] == '*': 312 s = fmt.Sprintf("%s = (%s)(unsafe.Pointer(r0))", r.Name, r.Type) 313 case r.Type == "bool": 314 s = fmt.Sprintf("%s = r0 != 0", r.Name) 315 default: 316 s = fmt.Sprintf("%s = %s(r0)", r.Name, r.Type) 317 } 318 if !r.ReturnsError { 319 return s 320 } 321 return s + "\n\t" + r.useLongHandleErrorCode(r.Name) 322 } 323 324 // Fn describes syscall function. 325 type Fn struct { 326 Name string 327 Params []*Param 328 Rets *Rets 329 PrintTrace bool 330 dllname string 331 dllfuncname string 332 src string 333 // TODO: get rid of this field and just use parameter index instead 334 curTmpVarIdx int // insure tmp variables have uniq names 335 } 336 337 // extractParams parses s to extract function parameters. 338 func extractParams(s string, f *Fn) ([]*Param, error) { 339 s = trim(s) 340 if s == "" { 341 return nil, nil 342 } 343 a := strings.Split(s, ",") 344 ps := make([]*Param, len(a)) 345 for i := range ps { 346 s2 := trim(a[i]) 347 b := strings.Split(s2, " ") 348 if len(b) != 2 { 349 b = strings.Split(s2, "\t") 350 if len(b) != 2 { 351 return nil, errors.New("Could not extract function parameter from \"" + s2 + "\"") 352 } 353 } 354 ps[i] = &Param{ 355 Name: trim(b[0]), 356 Type: trim(b[1]), 357 fn: f, 358 tmpVarIdx: -1, 359 } 360 } 361 return ps, nil 362 } 363 364 // extractSection extracts text out of string s starting after start 365 // and ending just before end. found return value will indicate success, 366 // and prefix, body and suffix will contain correspondent parts of string s. 367 func extractSection(s string, start, end rune) (prefix, body, suffix string, found bool) { 368 s = trim(s) 369 if strings.HasPrefix(s, string(start)) { 370 // no prefix 371 body = s[1:] 372 } else { 373 a := strings.SplitN(s, string(start), 2) 374 if len(a) != 2 { 375 return "", "", s, false 376 } 377 prefix = a[0] 378 body = a[1] 379 } 380 a := strings.SplitN(body, string(end), 2) 381 if len(a) != 2 { 382 return "", "", "", false 383 } 384 return prefix, a[0], a[1], true 385 } 386 387 // newFn parses string s and return created function Fn. 388 func newFn(s string) (*Fn, error) { 389 s = trim(s) 390 f := &Fn{ 391 Rets: &Rets{}, 392 src: s, 393 PrintTrace: *printTraceFlag, 394 } 395 // function name and args 396 prefix, body, s, found := extractSection(s, '(', ')') 397 if !found || prefix == "" { 398 return nil, errors.New("Could not extract function name and parameters from \"" + f.src + "\"") 399 } 400 f.Name = prefix 401 var err error 402 f.Params, err = extractParams(body, f) 403 if err != nil { 404 return nil, err 405 } 406 // return values 407 _, body, s, found = extractSection(s, '(', ')') 408 if found { 409 r, err := extractParams(body, f) 410 if err != nil { 411 return nil, err 412 } 413 switch len(r) { 414 case 0: 415 case 1: 416 if r[0].IsError() { 417 f.Rets.ReturnsError = true 418 } else { 419 f.Rets.Name = r[0].Name 420 f.Rets.Type = r[0].Type 421 } 422 case 2: 423 if !r[1].IsError() { 424 return nil, errors.New("Only last windows error is allowed as second return value in \"" + f.src + "\"") 425 } 426 f.Rets.ReturnsError = true 427 f.Rets.Name = r[0].Name 428 f.Rets.Type = r[0].Type 429 default: 430 return nil, errors.New("Too many return values in \"" + f.src + "\"") 431 } 432 } 433 // fail condition 434 _, body, s, found = extractSection(s, '[', ']') 435 if found { 436 f.Rets.FailCond = body 437 } 438 // dll and dll function names 439 s = trim(s) 440 if s == "" { 441 return f, nil 442 } 443 if !strings.HasPrefix(s, "=") { 444 return nil, errors.New("Could not extract dll name from \"" + f.src + "\"") 445 } 446 s = trim(s[1:]) 447 a := strings.Split(s, ".") 448 switch len(a) { 449 case 1: 450 f.dllfuncname = a[0] 451 case 2: 452 f.dllname = a[0] 453 f.dllfuncname = a[1] 454 default: 455 return nil, errors.New("Could not extract dll name from \"" + f.src + "\"") 456 } 457 return f, nil 458 } 459 460 // DLLName returns DLL name for function f. 461 func (f *Fn) DLLName() string { 462 if f.dllname == "" { 463 return "kernel32" 464 } 465 return f.dllname 466 } 467 468 // DLLName returns DLL function name for function f. 469 func (f *Fn) DLLFuncName() string { 470 if f.dllfuncname == "" { 471 return f.Name 472 } 473 return f.dllfuncname 474 } 475 476 // ParamList returns source code for function f parameters. 477 func (f *Fn) ParamList() string { 478 return join(f.Params, func(p *Param) string { return p.Name + " " + p.Type }, ", ") 479 } 480 481 // HelperParamList returns source code for helper function f parameters. 482 func (f *Fn) HelperParamList() string { 483 return join(f.Params, func(p *Param) string { return p.Name + " " + p.HelperType() }, ", ") 484 } 485 486 // ParamPrintList returns source code of trace printing part correspondent 487 // to syscall input parameters. 488 func (f *Fn) ParamPrintList() string { 489 return join(f.Params, func(p *Param) string { return fmt.Sprintf(`"%s=", %s, `, p.Name, p.Name) }, `", ", `) 490 } 491 492 // ParamCount return number of syscall parameters for function f. 493 func (f *Fn) ParamCount() int { 494 n := 0 495 for _, p := range f.Params { 496 n += len(p.SyscallArgList()) 497 } 498 return n 499 } 500 501 // SyscallParamCount determines which version of Syscall/Syscall6/Syscall9/... 502 // to use. It returns parameter count for correspondent SyscallX function. 503 func (f *Fn) SyscallParamCount() int { 504 n := f.ParamCount() 505 switch { 506 case n <= 3: 507 return 3 508 case n <= 6: 509 return 6 510 case n <= 9: 511 return 9 512 case n <= 12: 513 return 12 514 case n <= 15: 515 return 15 516 default: 517 panic("too many arguments to system call") 518 } 519 } 520 521 // Syscall determines which SyscallX function to use for function f. 522 func (f *Fn) Syscall() string { 523 c := f.SyscallParamCount() 524 if c == 3 { 525 return syscalldot() + "Syscall" 526 } 527 return syscalldot() + "Syscall" + strconv.Itoa(c) 528 } 529 530 // SyscallParamList returns source code for SyscallX parameters for function f. 531 func (f *Fn) SyscallParamList() string { 532 a := make([]string, 0) 533 for _, p := range f.Params { 534 a = append(a, p.SyscallArgList()...) 535 } 536 for len(a) < f.SyscallParamCount() { 537 a = append(a, "0") 538 } 539 return strings.Join(a, ", ") 540 } 541 542 // HelperCallParamList returns source code of call into function f helper. 543 func (f *Fn) HelperCallParamList() string { 544 a := make([]string, 0, len(f.Params)) 545 for _, p := range f.Params { 546 s := p.Name 547 if p.Type == "string" { 548 s = p.tmpVar() 549 } 550 a = append(a, s) 551 } 552 return strings.Join(a, ", ") 553 } 554 555 // IsUTF16 is true, if f is W (utf16) function. It is false 556 // for all A (ascii) functions. 557 func (f *Fn) IsUTF16() bool { 558 s := f.DLLFuncName() 559 return s[len(s)-1] == 'W' 560 } 561 562 // StrconvFunc returns name of Go string to OS string function for f. 563 func (f *Fn) StrconvFunc() string { 564 if f.IsUTF16() { 565 return syscalldot() + "UTF16PtrFromString" 566 } 567 return syscalldot() + "BytePtrFromString" 568 } 569 570 // StrconvType returns Go type name used for OS string for f. 571 func (f *Fn) StrconvType() string { 572 if f.IsUTF16() { 573 return "*uint16" 574 } 575 return "*byte" 576 } 577 578 // HasStringParam is true, if f has at least one string parameter. 579 // Otherwise it is false. 580 func (f *Fn) HasStringParam() bool { 581 for _, p := range f.Params { 582 if p.Type == "string" { 583 return true 584 } 585 } 586 return false 587 } 588 589 // HelperName returns name of function f helper. 590 func (f *Fn) HelperName() string { 591 if !f.HasStringParam() { 592 return f.Name 593 } 594 return "_" + f.Name 595 } 596 597 // Source files and functions. 598 type Source struct { 599 Funcs []*Fn 600 Files []string 601 Imports []string 602 } 603 604 func (src *Source) Import(pkg string) { 605 src.Imports = append(src.Imports, pkg) 606 sort.Strings(src.Imports) 607 } 608 609 // ParseFiles parses files listed in fs and extracts all syscall 610 // functions listed in sys comments. It returns source files 611 // and functions collection *Source if successful. 612 func ParseFiles(fs []string) (*Source, error) { 613 src := &Source{ 614 Funcs: make([]*Fn, 0), 615 Files: make([]string, 0), 616 Imports: []string{ 617 "unsafe", 618 }, 619 } 620 if *systemDLL { 621 src.Import("internal/syscall/windows/sysdll") 622 } 623 for _, file := range fs { 624 if err := src.ParseFile(file); err != nil { 625 return nil, err 626 } 627 } 628 return src, nil 629 } 630 631 // DLLs return dll names for a source set src. 632 func (src *Source) DLLs() []string { 633 uniq := make(map[string]bool) 634 r := make([]string, 0) 635 for _, f := range src.Funcs { 636 name := f.DLLName() 637 if _, found := uniq[name]; !found { 638 uniq[name] = true 639 r = append(r, name) 640 } 641 } 642 return r 643 } 644 645 // ParseFile adds additional file path to a source set src. 646 func (src *Source) ParseFile(path string) error { 647 file, err := os.Open(path) 648 if err != nil { 649 return err 650 } 651 defer file.Close() 652 653 s := bufio.NewScanner(file) 654 for s.Scan() { 655 t := trim(s.Text()) 656 if len(t) < 7 { 657 continue 658 } 659 if !strings.HasPrefix(t, "//sys") { 660 continue 661 } 662 t = t[5:] 663 if !(t[0] == ' ' || t[0] == '\t') { 664 continue 665 } 666 f, err := newFn(t[1:]) 667 if err != nil { 668 return err 669 } 670 src.Funcs = append(src.Funcs, f) 671 } 672 if err := s.Err(); err != nil { 673 return err 674 } 675 src.Files = append(src.Files, path) 676 677 // get package name 678 fset := token.NewFileSet() 679 _, err = file.Seek(0, 0) 680 if err != nil { 681 return err 682 } 683 pkg, err := parser.ParseFile(fset, "", file, parser.PackageClauseOnly) 684 if err != nil { 685 return err 686 } 687 packageName = pkg.Name.Name 688 689 return nil 690 } 691 692 // Generate output source file from a source set src. 693 func (src *Source) Generate(w io.Writer) error { 694 if *sysRepo && packageName != "windows" { 695 src.Import("golang.org/x/sys/windows") 696 } 697 if packageName != "syscall" { 698 src.Import("syscall") 699 } 700 funcMap := template.FuncMap{ 701 "packagename": packagename, 702 "syscalldot": syscalldot, 703 "newlazydll": func(dll string) string { 704 arg := "\"" + dll + ".dll\"" 705 if *systemDLL { 706 arg = "sysdll.Add(" + arg + ")" 707 } 708 if *sysRepo { 709 if packageName == "windows" { 710 return "&LazyDLL{Name: " + arg + ", System: true}" 711 } else { 712 return "&windows.LazyDLL{Name: " + arg + ", System: true}" 713 } 714 } else { 715 return syscalldot() + "NewLazyDLL(" + arg + ")" 716 } 717 }, 718 } 719 t := template.Must(template.New("main").Funcs(funcMap).Parse(srcTemplate)) 720 err := t.Execute(w, src) 721 if err != nil { 722 return errors.New("Failed to execute template: " + err.Error()) 723 } 724 return nil 725 } 726 727 func usage() { 728 fmt.Fprintf(os.Stderr, "usage: mksyscall_windows [flags] [path ...]\n") 729 flag.PrintDefaults() 730 os.Exit(1) 731 } 732 733 func main() { 734 flag.Usage = usage 735 flag.Parse() 736 if len(flag.Args()) <= 0 { 737 fmt.Fprintf(os.Stderr, "no files to parse provided\n") 738 usage() 739 } 740 741 src, err := ParseFiles(flag.Args()) 742 if err != nil { 743 log.Fatal(err) 744 } 745 746 var buf bytes.Buffer 747 if err := src.Generate(&buf); err != nil { 748 log.Fatal(err) 749 } 750 751 data, err := format.Source(buf.Bytes()) 752 if err != nil { 753 log.Fatal(err) 754 } 755 if *filename == "" { 756 _, err = os.Stdout.Write(data) 757 } else { 758 err = ioutil.WriteFile(*filename, data, 0644) 759 } 760 if err != nil { 761 log.Fatal(err) 762 } 763 } 764 765 // TODO: use println instead to print in the following template 766 const srcTemplate = ` 767 768 {{define "main"}}// MACHINE GENERATED BY 'go generate' COMMAND; DO NOT EDIT 769 770 package {{packagename}} 771 772 import ( 773 {{range .Imports}}"{{.}}" 774 {{end}} 775 ) 776 777 var _ unsafe.Pointer 778 779 var ( 780 {{template "dlls" .}} 781 {{template "funcnames" .}}) 782 {{range .Funcs}}{{if .HasStringParam}}{{template "helperbody" .}}{{end}}{{template "funcbody" .}}{{end}} 783 {{end}} 784 785 {{/* help functions */}} 786 787 {{define "dlls"}}{{range .DLLs}} mod{{.}} = {{newlazydll .}} 788 {{end}}{{end}} 789 790 {{define "funcnames"}}{{range .Funcs}} proc{{.DLLFuncName}} = mod{{.DLLName}}.NewProc("{{.DLLFuncName}}") 791 {{end}}{{end}} 792 793 {{define "helperbody"}} 794 func {{.Name}}({{.ParamList}}) {{template "results" .}}{ 795 {{template "helpertmpvars" .}} return {{.HelperName}}({{.HelperCallParamList}}) 796 } 797 {{end}} 798 799 {{define "funcbody"}} 800 func {{.HelperName}}({{.HelperParamList}}) {{template "results" .}}{ 801 {{template "tmpvars" .}} {{template "syscall" .}} 802 {{template "seterror" .}}{{template "printtrace" .}} return 803 } 804 {{end}} 805 806 {{define "helpertmpvars"}}{{range .Params}}{{if .TmpVarHelperCode}} {{.TmpVarHelperCode}} 807 {{end}}{{end}}{{end}} 808 809 {{define "tmpvars"}}{{range .Params}}{{if .TmpVarCode}} {{.TmpVarCode}} 810 {{end}}{{end}}{{end}} 811 812 {{define "results"}}{{if .Rets.List}}{{.Rets.List}} {{end}}{{end}} 813 814 {{define "syscall"}}{{.Rets.SetReturnValuesCode}}{{.Syscall}}(proc{{.DLLFuncName}}.Addr(), {{.ParamCount}}, {{.SyscallParamList}}){{end}} 815 816 {{define "seterror"}}{{if .Rets.SetErrorCode}} {{.Rets.SetErrorCode}} 817 {{end}}{{end}} 818 819 {{define "printtrace"}}{{if .PrintTrace}} print("SYSCALL: {{.Name}}(", {{.ParamPrintList}}") (", {{.Rets.PrintList}}")\n") 820 {{end}}{{end}} 821 822 `