golang.org/x/sys@v0.20.1-0.20240517151509-673e0f94c16d/unix/mksyscall_zos_s390x.go (about) 1 // Copyright 2024 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 //go:build ignore 6 7 /* 8 This program must be on the most current zos release. 9 10 This program generates with data from 11 12 //\'CEE.SCEELIB\(CELQS003\)\' 13 syscall_zos_s390x.go 14 15 to output files: 16 17 zsyscall_zos_s390x.go (generated syscall) 18 zsymaddr_zos_s390x.s (access to the function variable for functions that may not exist) 19 zsysnum_zos_s390x.go (offset from libvec) 20 21 synopsis: 22 23 go run ./mksyscall_zos_s390x.go 24 25 or (with default flags) 26 go run mksyscall_zos_s390x.go -o_sysnum zsysnum_zos_s390x.go -o_syscall zsyscall_zos_s390x.go -i_syscall syscall_zos_s390x.go -o_asm zsymaddr_zos_s390x.s 27 28 or if processed on a different platform 29 go run ./mksyscall_zos_s390x.go -i_testfile CELQS003.txt 30 where CELQS003.txt is a text file copy of //\'CEE.SCEELIB\(CELQS003\)\' 31 */ 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 // cmdLine returns this programs's commandline arguments 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 // Param is function parameter 112 type Param struct { 113 Name string 114 Type string 115 } 116 117 // parseParamList parses parameter list and returns a slice of parameters 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 // parseParam splits a parameter into name and type 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 // IMPORT DATA64,CELQV003,'environ',001 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 // open and setup the asm output file 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 // open and setup the Go output file 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 // Line must be of the form 312 // func Open(path string, mode int, perm int) (fd int, errno error) 313 // Split into name, in params, out params. 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 // if it is empty, it is derived from the function name 322 sysname = "SYS_" + funct 323 sysname = regexp.MustCompile(`([a-z])([A-Z])`).ReplaceAllString(sysname, `${1}_$2`) 324 sysname = strings.ToUpper(sysname) 325 } 326 327 // Split argument lists on comma. 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 // Try in vain to keep people from editing this file. 342 // The theory is that they jump into the middle of the file 343 // without reading the header. 344 text1 := "// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n\n" 345 text2 := "" 346 text3 := "" 347 348 // Go function header. 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 // Check if err return available 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 // Prepare arguments to Syscall. 376 var args []string 377 var fargs []string // for call fowarding 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 // Convert slice into pointer, length. 398 // Have to be careful not to take address of &a[0] if len == 0: 399 // pass dummy pointer in that case. 400 // Used to pass nil, but some OSes or simulators reject write(fd, nil, 0). 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 // Determine which form to use; pad args with zeros. 412 asmcall := "CallLeFuncWithErr" 413 414 // Actual call. 415 arglist := strings.Join(args, ", ") 416 call := fmt.Sprintf("%s(GetZosLibVec()+%s<<4, %s)", asmcall, sysname, arglist) 417 418 // Assign return values. 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 }