1
2
3
4
5
6
7
32 package main
33
34 import (
35 "bufio"
36 "flag"
37 "fmt"
38 "io"
39 "log"
40 "os"
41 "os/exec"
42 "path"
43 "regexp"
44 "runtime"
45 "sort"
46 "strconv"
47 "strings"
48 )
49
50 var (
51 sysnumfile = flag.String("o_sysnum", "zsysnum_zos_s390x.go", "zos LE offsets output file in Go")
52 outputgo = flag.String("o_syscall", "zsyscall_zos_s390x.go", "zos generated syscall output file in Go")
53 inputgo = flag.String("i_syscall", "syscall_zos_s390x.go", "zos input file that contain //sys statements")
54 outasm = flag.String("o_asm", "zsymaddr_zos_s390x.s", "zos output file for function variable addresses")
55 testfile = flag.String("i_testfile", "", "file for local validation")
56 )
57 var copyr = `// %s
58 // Code generated by the command above; see README.md. DO NOT EDIT.
59
60 //go:build zos && s390x
61 `
62 var AsmTemplate = `
63 // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT
64
65 TEXT ·get_%sAddr(SB), NOSPLIT|NOFRAME, $0-8
66 MOVD $·%s(SB), R8
67 MOVD R8, ret+0(FP)
68 RET
69 `
70
71
72 func cmdLine() string {
73 _, fileName, _, _ := runtime.Caller(1)
74 return "go run " + path.Base(fileName) + " -o_sysnum " + *sysnumfile + " -o_syscall " + *outputgo + " -i_syscall " + *inputgo + " -o_asm " + *outasm
75 }
76
77 func out(ch chan string, file io.ReadCloser) {
78 defer file.Close()
79 defer close(ch)
80 rd := bufio.NewReader(file)
81 loop:
82 for {
83 str, err := rd.ReadString('\n')
84 if err != nil {
85 if err != io.EOF {
86 log.Fatal("Read Error:", err)
87 }
88 break loop
89 } else {
90 ch <- str
91 }
92 }
93 }
94
95 type SO struct {
96 Symbol string
97 Offset int64
98 }
99
100 type SOList []SO
101
102 func (s SOList) Len() int { return len(s) }
103 func (s SOList) Swap(i, j int) { s[i], s[j] = s[j], s[i] }
104 func (s SOList) Less(i, j int) bool {
105 if s[i].Offset == s[j].Offset {
106 return s[i].Symbol < s[j].Symbol
107 }
108 return s[i].Offset < s[j].Offset
109 }
110
111
112 type Param struct {
113 Name string
114 Type string
115 }
116
117
118 func parseParamList(list string) []string {
119 list = strings.TrimSpace(list)
120 if list == "" {
121 return []string{}
122 }
123 return regexp.MustCompile(`\s*,\s*`).Split(list, -1)
124 }
125
126
127 func parseParam(p string) Param {
128 ps := regexp.MustCompile(`^(\S*) (\S*)$`).FindStringSubmatch(p)
129 if ps == nil {
130 fmt.Fprintf(os.Stderr, "malformed parameter: %s\n", p)
131 os.Exit(1)
132 }
133 return Param{ps[1], ps[2]}
134 }
135
136 func main() {
137 flag.Parse()
138 sidedeck := "//'CEE.SCEELIB(CELQS003)'"
139 if *testfile != "" {
140 sidedeck = *testfile
141 }
142 args := []string{"-u", sidedeck}
143 cmd := exec.Command("/bin/cat", args...)
144 stdout, err := cmd.StdoutPipe()
145 if err != nil {
146 println("err stdout ")
147 log.Fatal(err)
148 }
149 c1 := make(chan string)
150 go out(c1, stdout)
151 err2 := cmd.Start()
152 if err2 != nil {
153 log.Fatal(err2)
154 }
155 longest := 0
156 outstanding := 1
157
158 r1 := regexp.MustCompile("^ +IMPORT +CODE64,CELQV003,'([A-Za-z_][A-Za-z0-9_]*)',([0-9A-F][0-9A-F][0-9A-F]) *\n$")
159 m := make(map[string]int64)
160 for outstanding > 0 {
161 select {
162 case msg1, ok := <-c1:
163 if ok {
164 result := r1.FindStringSubmatch(msg1)
165 if result != nil {
166 if len(result) > 2 {
167 symbol := "SYS_" + strings.ToUpper(result[1])
168 offset, e1 := strconv.ParseInt(result[2], 16, 64)
169 if e1 == nil {
170 if len(symbol) > longest {
171 longest = len(symbol)
172 }
173 m[symbol] = offset
174 } else {
175 fmt.Printf("ERROR %s\n", msg1)
176 }
177 }
178 }
179 } else {
180 c1 = nil
181 outstanding--
182 }
183
184 }
185 }
186
187 list := make(SOList, len(m))
188
189 i := 0
190 for k, v := range m {
191 list[i] = SO{k, v}
192 i++
193 }
194 sort.Sort(list)
195 fmt.Printf("Writing %s\n", *sysnumfile)
196 err = writesysnum(*sysnumfile, &list)
197 if err != nil {
198 fmt.Fprintf(os.Stderr, "Error writesysnum %s %v\n", *sysnumfile, err)
199 os.Exit(1)
200 }
201 err = gofmt(*sysnumfile)
202 if err != nil {
203 fmt.Fprintf(os.Stderr, "Error gofmt %s %v\n", *sysnumfile, err)
204 os.Exit(1)
205 }
206
207 fmt.Printf("Reading %s\n", *inputgo)
208 f, err := os.Open(*inputgo)
209 if err != nil {
210 fmt.Fprintf(os.Stderr, err.Error())
211 os.Exit(1)
212 }
213
214
215 fmt.Printf("Writing %s\n", *outasm)
216 fasm, asmerr := os.Create(*outasm)
217 if asmerr != nil {
218 fmt.Fprintf(os.Stderr, "Error open %s %s\n", *outasm, asmerr.Error())
219 os.Exit(1)
220 }
221 asm := bufio.NewWriter(fasm)
222 fmt.Fprintf(asm, copyr, cmdLine())
223 fmt.Fprintf(asm, `#include "textflag.h"
224
225 // provide the address of function variable to be fixed up.
226 `)
227
228
229 fmt.Printf("Writing %s\n", *outputgo)
230 fgo, goerr := os.Create(*outputgo)
231 if goerr != nil {
232 fmt.Fprintf(os.Stderr, "Error open %s %s\n", *outputgo, goerr.Error())
233 os.Exit(1)
234 }
235 go1 := bufio.NewWriter(fgo)
236 fmt.Fprintf(go1, copyr, cmdLine())
237 fmt.Fprintf(go1, `
238
239 package unix
240
241 import (
242 "syscall"
243 "unsafe"
244 "runtime"
245 )
246
247 var _ syscall.Errno
248
249 `)
250
251 s := bufio.NewScanner(f)
252 scanErr := processStream(s, asm, go1, &m)
253
254 asm.Flush()
255 fasm.Close()
256
257 go1.Flush()
258 fgo.Close()
259 err = gofmt(*outputgo)
260 if err != nil {
261 fmt.Fprintf(os.Stderr, "Error gofmt %s %v\n", *outputgo, err)
262 os.Exit(1)
263 }
264 if scanErr != nil {
265 fmt.Fprintf(os.Stderr, "%s", scanErr.Error())
266 os.Exit(1)
267 }
268
269 }
270
271 func writesysnum(file string, l *SOList) error {
272 f, err := os.Create(file)
273 if err != nil {
274 return err
275 }
276 w := bufio.NewWriter(f)
277 defer f.Close()
278 defer w.Flush()
279 fmt.Fprintf(w, copyr, cmdLine())
280 fmt.Fprintf(w, `package unix
281 const (
282 `)
283 for _, item := range *l {
284 fmt.Fprintf(w, " %-40s = 0x%X // %d\n", item.Symbol, item.Offset, item.Offset)
285 }
286 fmt.Fprintf(w, `
287 )`)
288 return nil
289 }
290 func gofmt(file string) error {
291 cmd := exec.Command("gofmt", "-w", file)
292 _, err := cmd.Output()
293
294 if err != nil {
295 return err
296 }
297
298 return nil
299 }
300
301 func processStream(s *bufio.Scanner, asm, go1 *bufio.Writer, m *map[string]int64) error {
302 for s.Scan() {
303 t := s.Text()
304 t = strings.TrimSpace(t)
305 t = regexp.MustCompile(`\s+`).ReplaceAllString(t, ` `)
306 nonblock := regexp.MustCompile(`^\/\/sysnb `).FindStringSubmatch(t)
307 if regexp.MustCompile(`^\/\/sys `).FindStringSubmatch(t) == nil && nonblock == nil {
308 continue
309 }
310
311
312
313
314 f := regexp.MustCompile(`^\/\/sys(nb)? (\w+)\(([^()]*)\)\s*(?:\(([^()]+)\))?\s*(?:=\s*((?i)SYS_[A-Z0-9_]+))?$`).FindStringSubmatch(t)
315 if f == nil {
316 return fmt.Errorf("%s:%s\nmalformed //sys declaration\n", *inputgo, t)
317 }
318 funct, inps, outps, sysname := f[2], f[3], f[4], f[5]
319
320 if sysname == "" {
321
322 sysname = "SYS_" + funct
323 sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`)
324 sysname = strings.ToUpper(sysname)
325 }
326
327
328 in := parseParamList(inps)
329 out := parseParamList(outps)
330 val, ok := (*m)[sysname]
331 if !ok {
332 return fmt.Errorf("%s:%s\nsysname %s not found on this system\n", *inputgo, s.Text(), sysname)
333 }
334 var newfunc bool
335 if val > 3488 {
336 fmt.Fprintf(asm, AsmTemplate, funct, funct)
337 newfunc = true
338 } else {
339 newfunc = false
340 }
341
342
343
344 text1 := "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n"
345 text2 := ""
346 text3 := ""
347
348
349 outDecl := ""
350 if len(out) > 0 {
351 outDecl = fmt.Sprintf(" (%s)", strings.Join(out, ", "))
352 }
353 if newfunc {
354 text1 += fmt.Sprintf("func impl_%s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl)
355 text2 += fmt.Sprintf("//go:nosplit\nfunc get_%sAddr() *(func(%s) %s)\nvar %s = enter_%s\n", funct, strings.Join(in, ", "), outDecl, funct, funct)
356 text2 += fmt.Sprintf("func enter_%s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl)
357 text2 += fmt.Sprintf("funcref := get_%sAddr()\n", funct)
358 text2 += fmt.Sprintf("\tif funcptrtest(GetZosLibVec()+%s<<4, \"\") == 0 {\n\t\t*funcref = impl_%s\n", sysname, funct)
359 text2 += fmt.Sprintf("\t} else {\n\t\t*funcref = error_%s\n", funct)
360 text2 += fmt.Sprintf("\t}\n")
361 text3 += fmt.Sprintf("func error_%s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl)
362 } else {
363 text1 += fmt.Sprintf("func %s(%s)%s {\n", funct, strings.Join(in, ", "), outDecl)
364 }
365
366
367 errvar := ""
368 for _, param := range out {
369 p := parseParam(param)
370 if p.Type == "error" {
371 errvar = p.Name
372 break
373 }
374 }
375
376 var args []string
377 var fargs []string
378 n := 0
379 for _, param := range in {
380 p := parseParam(param)
381 fargs = append(fargs, p.Name)
382 if regexp.MustCompile(`^\*`).FindStringSubmatch(p.Type) != nil {
383 args = append(args, "uintptr(unsafe.Pointer("+p.Name+"))")
384 } else if p.Type == "string" && errvar != "" {
385 text1 += fmt.Sprintf("\tvar _p%d *byte\n", n)
386 text1 += fmt.Sprintf("\t_p%d, %s = BytePtrFromString(%s)\n", n, errvar, p.Name)
387 text1 += fmt.Sprintf("\tif %s != nil {\n\t\treturn\n\t}\n", errvar)
388 args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
389 n++
390 } else if p.Type == "string" {
391 fmt.Fprintf(os.Stderr, *inputgo+":"+funct+" uses string arguments, but has no error return\n")
392 text1 += fmt.Sprintf("\tvar _p%d *byte\n", n)
393 text1 += fmt.Sprintf("\t_p%d, _ = BytePtrFromString(%s)\n", n, p.Name)
394 args = append(args, fmt.Sprintf("uintptr(unsafe.Pointer(_p%d))", n))
395 n++
396 } else if regexp.MustCompile(`^\[\](.*)`).FindStringSubmatch(p.Type) != nil {
397
398
399
400
401 text1 += fmt.Sprintf("\tvar _p%d unsafe.Pointer\n", n)
402 text1 += fmt.Sprintf("\tif len(%s) > 0 {\n\t\t_p%d = unsafe.Pointer(&%s[0])\n\t}", p.Name, n, p.Name)
403 text1 += fmt.Sprintf(" else {\n\t\t_p%d = unsafe.Pointer(&_zero)\n\t}\n", n)
404 args = append(args, fmt.Sprintf("uintptr(_p%d)", n), fmt.Sprintf("uintptr(len(%s))", p.Name))
405 n++
406 } else {
407 args = append(args, fmt.Sprintf("uintptr(%s)", p.Name))
408 }
409 }
410
411
412 asmcall := "CallLeFuncWithErr"
413
414
415 arglist := strings.Join(args, ", ")
416 call := fmt.Sprintf("%s(GetZosLibVec()+%s<<4, %s)", asmcall, sysname, arglist)
417
418
419 body := ""
420 ret := []string{"_", "_", "_"}
421 doErrno := false
422 for i := 0; i < len(out); i++ {
423 p := parseParam(out[i])
424 reg := ""
425 if p.Name == "err" {
426 reg = "e1"
427 ret[0] = "r0"
428 ret[1] = "e2"
429 ret[2] = reg
430 doErrno = true
431 } else {
432 reg = fmt.Sprintf("r%d", i)
433 ret[i] = reg
434
435 }
436 if p.Type == "bool" {
437 reg = fmt.Sprintf("%s != 0", reg)
438 }
439 if reg != "e1" {
440 body += fmt.Sprintf("\t%s = %s(%s)\n", p.Name, p.Type, reg)
441 if newfunc {
442 text3 += fmt.Sprintf("\t%s = -1\n", p.Name)
443 }
444 }
445 }
446 if ret[0] == "_" && ret[1] == "_" && ret[2] == "_" {
447 if nonblock == nil {
448 text1 += fmt.Sprintf("\truntime.EnterSyscall()\n")
449 }
450 text1 += fmt.Sprintf("\t%s\n", call)
451 if nonblock == nil {
452 text1 += fmt.Sprintf("\truntime.ExitSyscall()\n")
453 }
454 text2 += fmt.Sprintf("\t(*funcref)(%s)\n", strings.Join(fargs, ", "))
455 text2 += "\treturn\n"
456 } else {
457 if nonblock == nil {
458 text1 += fmt.Sprintf("\truntime.EnterSyscall()\n")
459 }
460 text1 += fmt.Sprintf("\t%s, %s, %s := %s\n", ret[0], ret[1], ret[2], call)
461 if nonblock == nil {
462 text1 += fmt.Sprintf("\truntime.ExitSyscall()\n")
463 }
464 text2 += fmt.Sprintf("\treturn (*funcref)(%s)\n", strings.Join(fargs, ", "))
465 }
466 text1 += body
467
468 if doErrno {
469 if newfunc {
470 text3 += fmt.Sprintf("\terr = ENOSYS\n")
471 }
472 text1 += "\tif int64(r0) == -1 {\n"
473 text1 += "\t\terr = errnoErr2(e1,e2)\n"
474 text1 += "\t}\n"
475 }
476 if newfunc {
477 text2 += "}\n\n"
478 text3 += "\treturn\n"
479 text3 += "}\n\n"
480 }
481 text1 += "\treturn\n"
482 text1 += "}\n\n"
483 fmt.Fprintf(go1, "%s", text1)
484 if newfunc {
485 fmt.Fprintf(go1, "%s", text2)
486 fmt.Fprintf(go1, "%s", text3)
487 }
488
489 }
490 if err := s.Err(); err != nil {
491 return err
492 }
493 return nil
494 }
495
View as plain text