diff options
-rw-r--r-- | cmd/parse-syscall-annotations/.gitignore | 1 | ||||
-rw-r--r-- | cmd/parse-syscall-annotations/main.go | 346 | ||||
-rw-r--r-- | cmd/parse-syscall-annotations/syscall.go | 359 |
3 files changed, 0 insertions, 706 deletions
diff --git a/cmd/parse-syscall-annotations/.gitignore b/cmd/parse-syscall-annotations/.gitignore deleted file mode 100644 index ecfe5c996..000000000 --- a/cmd/parse-syscall-annotations/.gitignore +++ /dev/null @@ -1 +0,0 @@ -parse-syscall-annotations diff --git a/cmd/parse-syscall-annotations/main.go b/cmd/parse-syscall-annotations/main.go deleted file mode 100644 index 3f8a85ae5..000000000 --- a/cmd/parse-syscall-annotations/main.go +++ /dev/null @@ -1,346 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This program will take a single golang source file, or a directory containing -// many source files and produce a JSON output which represent any comments -// containing compatibility metadata. - -// Command parse-syscall-annotations parses syscall annotations from Godoc and -// generates a JSON file with the parsed syscall info. -// -// Annotations take the form: -// @Syscall(<name>, <arg>:<value>, ...) -// -// Supported args and values are: -// - arg: A syscall option. This entry only applies to the syscall when given this option. -// - support: Indicates support level -// - FULL: Full support -// - PARTIAL: Partial support. Details should be provided in note. -// - UNIMPLEMENTED: Unimplemented -// - returns: Indicates a known return value. Implies PARTIAL support. Values are syscall errors. -// This is treated as a string so you can use something like "returns:EPERM or ENOSYS". -// - issue: A GitHub issue number. -// - note: A note - -package main - -import ( - "encoding/json" - "flag" - "fmt" - "go/ast" - "go/parser" - "go/token" - "log" - "os" - "path/filepath" - "regexp" - "sort" - "strings" - "text/template" -) - -var ( - srcDir = flag.String("dir", "./", "The source directory") - jsonOut = flag.Bool("json", false, "Output info as json") - - r *regexp.Regexp - r2 *regexp.Regexp - - mdTemplate = template.Must(template.New("name").Parse(`+++ -title = "AMD64" -description = "Syscall Compatibility Reference Documentation for AMD64" -weight = 10 -+++ - -This table is a reference of Linux syscalls for the AMD64 architecture and -their compatibility status in gVisor. gVisor does not support all syscalls and -some syscalls may have a partial implementation. - -Of {{ .Total }} syscalls, {{ .Implemented }} syscalls have a full or partial -implementation. There are currently {{ .Unimplemented }} unimplemented -syscalls. {{ .Unknown }} syscalls are not yet documented. - -<table> - <thead> - <tr> - <th>#</th> - <th>Name</th> - <th>Support</th> - <th>GitHub Issue</th> - <th>Notes</th> - </tr> - </thead> - <tbody>{{ range .Syscalls }}{{ if ne .Support "Unknown" }} - <tr> - <td><a class="doc-table-anchor" id="{{ .Name }}{{ if index .Metadata "arg" }}({{ index .Metadata "arg" }}){{ end }}"></a>{{ .Number }}</td> - <td><a href="http://man7.org/linux/man-pages/man2/{{ .Name }}.2.html" target="_blank" rel="noopener">{{ .Name }}{{ if index .Metadata "arg" }}({{ index .Metadata "arg" }}){{ end }}</a></td> - <td>{{ .Support }}</td> - <td>{{ if index .Metadata "issue" }}<a href="https://github.com/google/gvisor/issues/{{ index .Metadata "issue" }}">#{{ index .Metadata "issue" }}</a>{{ end }}</td> - <td>{{ .Note }}</td> - </tr>{{ end }}{{ end }} - </tbody> -</table> -`)) -) - -// Syscall represents a function implementation of a syscall. -type Syscall struct { - File string - Line int - - Number int - Name string - - Metadata map[string]string -} - -const ( - UNKNOWN = iota - UNIMPLEMENTED - PARTIAL_SUPPORT - FULL_SUPPORT -) - -func (s *Syscall) SupportLevel() int { - supportLevel := UNKNOWN - switch strings.ToUpper(s.Metadata["support"]) { - case "FULL": - supportLevel = FULL_SUPPORT - case "PARTIAL": - supportLevel = PARTIAL_SUPPORT - case "UNIMPLEMENTED": - supportLevel = UNIMPLEMENTED - } - - // If an arg or returns is specifed treat that as a partial implementation even if - // there is full support for the argument. - if s.Metadata["arg"] != "" { - supportLevel = PARTIAL_SUPPORT - } - if s.Metadata["returns"] != "" && supportLevel == UNKNOWN { - returns := strings.ToUpper(s.Metadata["returns"]) - // Default to PARTIAL support if only returns is specified - supportLevel = PARTIAL_SUPPORT - - // If ENOSYS is returned unequivically, treat it as unimplemented. - if returns == "ENOSYS" { - supportLevel = UNIMPLEMENTED - } - } - - return supportLevel -} - -func (s *Syscall) Support() string { - l := s.SupportLevel() - switch l { - case FULL_SUPPORT: - return "Full" - case PARTIAL_SUPPORT: - return "Partial" - case UNIMPLEMENTED: - return "Unimplemented" - default: - return "Unknown" - } -} - -func (s *Syscall) Note() string { - note := s.Metadata["note"] - returns := s.Metadata["returns"] - // Add "Returns ENOSYS" note by default if support:UNIMPLEMENTED - if returns == "" && s.SupportLevel() == UNIMPLEMENTED { - returns = "ENOSYS" - } - if returns != "" { - return_note := fmt.Sprintf("Returns %s", returns) - if note != "" { - note = return_note + "; " + note - } else { - note = return_note - } - } - if note == "" && s.SupportLevel() == FULL_SUPPORT { - note = "Full Support" - } - return note -} - -type Report struct { - Implemented int - Unimplemented int - Unknown int - Total int - Syscalls []*Syscall -} - -func init() { - // Build a regex that will attempt to match all fields in tokens. - - // Regexp for matching syscall definitions - s := "@Syscall\\(([^\\),]+)([^\\)]+)\\)" - r = regexp.MustCompile(s) - - // Regexp for matching metadata - s2 := "([^\\ ),]+):([^\\),]+)" - r2 = regexp.MustCompile(s2) - - ReverseSyscallMap = make(map[string]int) - for no, name := range SyscallMap { - ReverseSyscallMap[name] = no - } -} - -// parseDoc parses all comments in a file and returns the parsed syscall -// information. -func parseDoc(fs *token.FileSet, f *ast.File) []*Syscall { - syscalls := []*Syscall{} - for _, cg := range f.Comments { - for _, line := range strings.Split(cg.Text(), "\n") { - if syscall := parseLine(fs, line); syscall != nil { - pos := fs.Position(cg.Pos()) - syscall.File = pos.Filename - syscall.Line = pos.Line - - syscalls = append(syscalls, syscall) - } - } - } - return syscalls -} - -// parseLine parses a single line of Godoc and returns the parsed syscall -// information. If no information is found, nil is returned. -// Syscall declarations take the form: -// @Syscall(<name>, <verb>:<value>, ...) -func parseLine(fs *token.FileSet, line string) *Syscall { - s := r.FindAllStringSubmatch(line, -1) - if len(s) > 0 { - name := strings.ToLower(s[0][1]) - if n, ok := ReverseSyscallMap[name]; ok { - syscall := Syscall{} - syscall.Name = name - syscall.Number = n - syscall.Metadata = make(map[string]string) - s2 := r2.FindAllStringSubmatch(s[0][2], -1) - for _, match := range s2 { - syscall.Metadata[match[1]] = match[2] - } - return &syscall - } else { - log.Printf("Warning: unknown syscall %q", name) - } - } - return nil -} - -func main() { - flag.Parse() - - var syscalls []*Syscall - - err := filepath.Walk(*srcDir, func(path string, info os.FileInfo, err error) error { - if info != nil && info.IsDir() { - fs := token.NewFileSet() - d, err := parser.ParseDir(fs, path, nil, parser.ParseComments) - if err != nil { - return err - } - - for _, p := range d { - for _, f := range p.Files { - s := parseDoc(fs, f) - syscalls = append(syscalls, s...) - } - } - } - - return nil - }) - - if err != nil { - fmt.Printf("failed to walk dir %s: %v", *srcDir, err) - os.Exit(1) - } - - var fullList []*Syscall - for no, name := range SyscallMap { - found := false - for _, s := range syscalls { - if s.Number == no { - fullList = append(fullList, s) - found = true - } - } - if !found { - fullList = append(fullList, &Syscall{ - Name: name, - Number: no, - }) - } - } - - // Sort the syscalls by number. - sort.Slice(fullList, func(i, j int) bool { - return fullList[i].Number < fullList[j].Number - }) - - if *jsonOut { - j, err := json.Marshal(fullList) - if err != nil { - fmt.Printf("failed to marshal JSON: %v", err) - os.Exit(1) - } - os.Stdout.Write(j) - return - } - - // Count syscalls and group by syscall number and support level - supportMap := map[int]int{} - for _, s := range fullList { - supportLevel := s.SupportLevel() - - // If we already have set a higher level of support - // keep the current value - if current, ok := supportMap[s.Number]; ok && supportLevel < current { - continue - } - - supportMap[s.Number] = supportLevel - } - report := Report{ - Syscalls: fullList, - } - for _, s := range supportMap { - switch s { - case FULL_SUPPORT: - report.Implemented += 1 - case PARTIAL_SUPPORT: - report.Implemented += 1 - case UNIMPLEMENTED: - report.Unimplemented += 1 - case UNKNOWN: - report.Unknown += 1 - } - report.Total += 1 - } - - err = mdTemplate.Execute(os.Stdout, report) - if err != nil { - fmt.Printf("failed to execute template: %v", err) - os.Exit(1) - return - } -} diff --git a/cmd/parse-syscall-annotations/syscall.go b/cmd/parse-syscall-annotations/syscall.go deleted file mode 100644 index b4a756440..000000000 --- a/cmd/parse-syscall-annotations/syscall.go +++ /dev/null @@ -1,359 +0,0 @@ -// Copyright 2018 Google LLC -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. - -// This program will take a single golang source file, or a directory containing -// many source files and produce a JSON output which represent any comments -// containing compatibility metadata. - -// Command parse-syscall-annotations parses syscall annotations from Godoc and -// generates a JSON file with the parsed syscall info. - -package main - -// ReverseSyscallMap is a map of syscall name (lowercase) to number -var ReverseSyscallMap map[string]int - -// SyscallMap is a map of syscall number to syscall name (lowercase) -var SyscallMap = map[int]string{ - 0: "read", - 1: "write", - 2: "open", - 3: "close", - 4: "stat", - 5: "fstat", - 6: "lstat", - 7: "poll", - 8: "lseek", - 9: "mmap", - 10: "mprotect", - 11: "munmap", - 12: "brk", - 13: "rtsigaction", - 14: "rtsigprocmask", - 15: "rtsigreturn", - 16: "ioctl", - 17: "pread64", - 18: "pwrite64", - 19: "readv", - 20: "writev", - 21: "access", - 22: "pipe", - 23: "select", - 24: "schedyield", - 25: "mremap", - 26: "msync", - 27: "mincore", - 28: "madvise", - 29: "shmget", - 30: "shmat", - 31: "shmctl", - 32: "dup", - 33: "dup2", - 34: "pause", - 35: "nanosleep", - 36: "getitimer", - 37: "alarm", - 38: "setitimer", - 39: "getpid", - 40: "sendfile", - 41: "socket", - 42: "connect", - 43: "accept", - 44: "sendto", - 45: "recvfrom", - 46: "sendmsg", - 47: "recvmsg", - 48: "shutdown", - 49: "bind", - 50: "listen", - 51: "getsockname", - 52: "getpeername", - 53: "socketpair", - 54: "setsockopt", - 55: "getsockopt", - 56: "clone", - 57: "fork", - 58: "vfork", - 59: "execve", - 60: "exit", - 61: "wait4", - 62: "kill", - 63: "uname", - 64: "semget", - 65: "semop", - 66: "semctl", - 67: "shmdt", - 68: "msgget", - 69: "msgsnd", - 70: "msgrcv", - 71: "msgctl", - 72: "fcntl", - 73: "flock", - 74: "fsync", - 75: "fdatasync", - 76: "truncate", - 77: "ftruncate", - 78: "getdents", - 79: "getcwd", - 80: "chdir", - 81: "fchdir", - 82: "rename", - 83: "mkdir", - 84: "rmdir", - 85: "creat", - 86: "link", - 87: "unlink", - 88: "symlink", - 89: "readlink", - 90: "chmod", - 91: "fchmod", - 92: "chown", - 93: "fchown", - 94: "lchown", - 95: "umask", - 96: "gettimeofday", - 97: "getrlimit", - 98: "getrusage", - 99: "sysinfo", - 100: "times", - 101: "ptrace", - 102: "getuid", - 103: "syslog", - 104: "getgid", - 105: "setuid", - 106: "setgid", - 107: "geteuid", - 108: "getegid", - 109: "setpgid", - 110: "getppid", - 111: "getpgrp", - 112: "setsid", - 113: "setreuid", - 114: "setregid", - 115: "getgroups", - 116: "setgroups", - 117: "setresuid", - 118: "getresuid", - 119: "setresgid", - 120: "getresgid", - 121: "getpgid", - 122: "setfsuid", - 123: "setfsgid", - 124: "getsid", - 125: "capget", - 126: "capset", - 127: "rtsigpending", - 128: "rtsigtimedwait", - 129: "rtsigqueueinfo", - 130: "rtsigsuspend", - 131: "sigaltstack", - 132: "utime", - 133: "mknod", - 134: "uselib", - 135: "setpersonality", - 136: "ustat", - 137: "statfs", - 138: "fstatfs", - 139: "sysfs", - 140: "getpriority", - 141: "setpriority", - 142: "schedsetparam", - 143: "schedgetparam", - 144: "schedsetscheduler", - 145: "schedgetscheduler", - 146: "schedgetprioritymax", - 147: "schedgetprioritymin", - 148: "schedrrgetinterval", - 149: "mlock", - 150: "munlock", - 151: "mlockall", - 152: "munlockall", - 153: "vhangup", - 154: "modifyldt", - 155: "pivotroot", - 156: "sysctl", - 157: "prctl", - 158: "archprctl", - 159: "adjtimex", - 160: "setrlimit", - 161: "chroot", - 162: "sync", - 163: "acct", - 164: "settimeofday", - 165: "mount", - 166: "umount2", - 167: "swapon", - 168: "swapoff", - 169: "reboot", - 170: "sethostname", - 171: "setdomainname", - 172: "iopl", - 173: "ioperm", - 174: "createmodule", - 175: "initmodule", - 176: "deletemodule", - 177: "getkernelsyms", - 178: "querymodule", - 179: "quotactl", - 180: "nfsservctl", - 181: "getpmsg", - 182: "putpmsg", - 183: "afssyscall", - 184: "tuxcall", - 185: "security", - 186: "gettid", - 187: "readahead", - 188: "setxattr", - 189: "lsetxattr", - 190: "fsetxattr", - 191: "getxattr", - 192: "lgetxattr", - 193: "fgetxattr", - 194: "listxattr", - 195: "llistxattr", - 196: "flistxattr", - 197: "removexattr", - 198: "lremovexattr", - 199: "fremovexattr", - 200: "tkill", - 201: "time", - 202: "futex", - 203: "schedsetaffinity", - 204: "schedgetaffinity", - 205: "setthreadarea", - 206: "iosetup", - 207: "iodestroy", - 208: "iogetevents", - 209: "iosubmit", - 210: "iocancel", - 211: "getthreadarea", - 212: "lookupdcookie", - 213: "epollcreate", - 214: "epollctlold", - 215: "epollwaitold", - 216: "remapfilepages", - 217: "getdents64", - 218: "settidaddress", - 219: "restartsyscall", - 220: "semtimedop", - 221: "fadvise64", - 222: "timercreate", - 223: "timersettime", - 224: "timergettime", - 225: "timergetoverrun", - 226: "timerdelete", - 227: "clocksettime", - 228: "clockgettime", - 229: "clockgetres", - 230: "clocknanosleep", - 231: "exitgroup", - 232: "epollwait", - 233: "epollctl", - 234: "tgkill", - 235: "utimes", - 236: "vserver", - 237: "mbind", - 238: "setmempolicy", - 239: "getmempolicy", - 240: "mqopen", - 241: "mqunlink", - 242: "mqtimedsend", - 243: "mqtimedreceive", - 244: "mqnotify", - 245: "mqgetsetattr", - 246: "kexec_load", - 247: "waitid", - 248: "addkey", - 249: "requestkey", - 250: "keyctl", - 251: "ioprioset", - 252: "ioprioget", - 253: "inotifyinit", - 254: "inotifyaddwatch", - 255: "inotifyrmwatch", - 256: "migratepages", - 257: "openat", - 258: "mkdirat", - 259: "mknodat", - 260: "fchownat", - 261: "futimesat", - 262: "fstatat", - 263: "unlinkat", - 264: "renameat", - 265: "linkat", - 266: "symlinkat", - 267: "readlinkat", - 268: "fchmodat", - 269: "faccessat", - 270: "pselect", - 271: "ppoll", - 272: "unshare", - 273: "setrobustlist", - 274: "getrobustlist", - 275: "splice", - 276: "tee", - 277: "syncfilerange", - 278: "vmsplice", - 279: "movepages", - 280: "utimensat", - 281: "epollpwait", - 282: "signalfd", - 283: "timerfdcreate", - 284: "eventfd", - 285: "fallocate", - 286: "timerfdsettime", - 287: "timerfdgettime", - 288: "accept4", - 289: "signalfd4", - 290: "eventfd2", - 291: "epollcreate1", - 292: "dup3", - 293: "pipe2", - 294: "inotifyinit1", - 295: "preadv", - 296: "pwritev", - 297: "rttgsigqueueinfo", - 298: "perfeventopen", - 299: "recvmmsg", - 300: "fanotifyinit", - 301: "fanotifymark", - 302: "prlimit64", - 303: "nametohandleat", - 304: "openbyhandleat", - 305: "clockadjtime", - 306: "syncfs", - 307: "sendmmsg", - 308: "setns", - 309: "getcpu", - 310: "processvmreadv", - 311: "processvmwritev", - 312: "kcmp", - 313: "finitmodule", - 314: "schedsetattr", - 315: "schedgetattr", - 316: "renameat2", - 317: "seccomp", - 318: "getrandom", - 319: "memfdcreate", - 320: "kexecfileload", - 321: "bpf", - 322: "execveat", - 323: "userfaultfd", - 324: "membarrier", - 325: "mlock2", - // syscalls after 325 are "backports" from versions of linux after 4.4. - 326: "copyfilerange", - 327: "preadv2", - 328: "pwritev2", -} |