mksyscall_windows.go 22 KB

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