diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2017-08-28 15:59:22 +0200 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2017-09-02 13:06:53 +0200 |
| commit | a7206b24cac96c08aecf2f3b4cc3c2e555eec708 (patch) | |
| tree | 80c678141148ce2eafaab5617f168bd840b8c8a6 /sys/syz-sysgen | |
| parent | aa51461a34f998908d10f551615ad242bdff8fe9 (diff) | |
pkg/compiler: check and generate types
Move most of the logic from sysgen to pkg/compiler.
Update #217
Diffstat (limited to 'sys/syz-sysgen')
| -rw-r--r-- | sys/syz-sysgen/syscallnr.go | 4 | ||||
| -rw-r--r-- | sys/syz-sysgen/sysgen.go | 884 |
2 files changed, 76 insertions, 812 deletions
diff --git a/sys/syz-sysgen/syscallnr.go b/sys/syz-sysgen/syscallnr.go index d98192a03..68e20e3b9 100644 --- a/sys/syz-sysgen/syscallnr.go +++ b/sys/syz-sysgen/syscallnr.go @@ -8,6 +8,8 @@ import ( "sort" "strings" "text/template" + + "github.com/google/syzkaller/sys" ) type Arch struct { @@ -23,7 +25,7 @@ var archs = []*Arch{ {"ppc64le", []string{"__ppc64__", "__PPC64__", "__powerpc64__"}}, } -func generateExecutorSyscalls(arch *Arch, syscalls []Syscall) []byte { +func generateExecutorSyscalls(arch *Arch, syscalls []*sys.Call) []byte { data := ArchData{ CARCH: arch.CARCH, } diff --git a/sys/syz-sysgen/sysgen.go b/sys/syz-sysgen/sysgen.go index 438d92a93..244d34521 100644 --- a/sys/syz-sysgen/sysgen.go +++ b/sys/syz-sysgen/sysgen.go @@ -12,26 +12,19 @@ import ( "io/ioutil" "os" "path/filepath" - "regexp" "runtime" "runtime/pprof" "sort" - "strconv" - "strings" + "sync" "github.com/google/syzkaller/pkg/ast" "github.com/google/syzkaller/pkg/compiler" + "github.com/google/syzkaller/pkg/serializer" ) var ( flagV = flag.Int("v", 0, "verbosity") flagMemProfile = flag.String("memprofile", "", "write a memory profile to the file") - - intRegExp = regexp.MustCompile("^int([0-9]+|ptr)(be)?(:[0-9]+)?$") -) - -const ( - ptrSize = 8 ) func main() { @@ -42,33 +35,61 @@ func main() { os.Exit(1) } + type Result struct { + OK bool + Errors []string + Unsupported map[string]bool + ArchData []byte + } + results := make([]Result, len(archs)) + var wg sync.WaitGroup + wg.Add(len(archs)) + + for i, arch := range archs { + arch := arch + res := &results[i] + go func() { + defer wg.Done() + eh := func(pos ast.Pos, msg string) { + res.Errors = append(res.Errors, fmt.Sprintf("%v: %v\n", pos, msg)) + } + consts := compiler.DeserializeConstsGlob("sys/*_"+arch.Name+"\\.const", eh) + if consts == nil { + return + } + prog := compiler.Compile(top, consts, eh) + if prog == nil { + return + } + res.Unsupported = prog.Unsupported + + sysFile := filepath.Join("sys", "sys_"+arch.Name+".go") + out := new(bytes.Buffer) + generate(arch.Name, prog, consts, out) + writeSource(sysFile, out.Bytes()) + + res.ArchData = generateExecutorSyscalls(arch, prog.Syscalls) + res.OK = true + }() + } + wg.Wait() + var syscallArchs [][]byte unsupported := make(map[string]int) - for _, arch := range archs { - logf(0, "generating %v...", arch.Name) - - consts := compiler.DeserializeConstsGlob("sys/*_"+arch.Name+"\\.const", nil) - if consts == nil { - os.Exit(1) + for i, arch := range archs { + res := &results[i] + fmt.Printf("generating %v...\n", arch.Name) + for _, msg := range res.Errors { + fmt.Print(msg) } - prog := compiler.Compile(top, consts, nil) - if prog == nil { + if !res.OK { os.Exit(1) } - for u := range prog.Unsupported { + syscallArchs = append(syscallArchs, res.ArchData) + for u := range res.Unsupported { unsupported[u]++ } - desc := astToDesc(prog.Desc) - - sysFile := filepath.Join("sys", "sys_"+arch.Name+".go") - logf(1, "Generate code to init system call data in %v", sysFile) - out := new(bytes.Buffer) - generate(arch.Name, desc, consts, out) - writeSource(sysFile, out.Bytes()) - logf(0, "") - - archData := generateExecutorSyscalls(arch, desc.Syscalls) - syscallArchs = append(syscallArchs, archData) + fmt.Printf("\n") } for what, count := range unsupported { @@ -92,320 +113,14 @@ func main() { } } -type Description struct { - Syscalls []Syscall - Structs map[string]*Struct - Unnamed map[string][]string - Flags map[string][]string - StrFlags map[string][]string - Resources map[string]Resource -} - -type Syscall struct { - Name string - CallName string - NR uint64 - Args [][]string - Ret []string -} - -type Struct struct { - Name string - Flds [][]string - IsUnion bool - Packed bool - Varlen bool - Align int -} - -type Resource struct { - Name string - Base string - Values []string -} - -type syscallArray []Syscall - -func (a syscallArray) Len() int { return len(a) } -func (a syscallArray) Less(i, j int) bool { return a[i].Name < a[j].Name } -func (a syscallArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -func astToDesc(top *ast.Description) *Description { - // As a temporal measure we just convert the new representation to the old one. - desc := &Description{ - Structs: make(map[string]*Struct), - Unnamed: make(map[string][]string), - Flags: make(map[string][]string), - StrFlags: make(map[string][]string), - Resources: make(map[string]Resource), - } - unnamedSeq := 0 - for _, decl := range top.Nodes { - switch n := decl.(type) { - case *ast.Resource: - var vals []string - for _, v := range n.Values { - if v.ValueHex { - vals = append(vals, fmt.Sprintf("0x%x", uintptr(v.Value))) - } else { - vals = append(vals, fmt.Sprint(uintptr(v.Value))) - } - } - desc.Resources[n.Name.Name] = Resource{ - Name: n.Name.Name, - Base: n.Base.Ident, - Values: vals, - } - case *ast.Call: - call := Syscall{ - Name: n.Name.Name, - CallName: n.CallName, - NR: n.NR, - } - for _, a := range n.Args { - call.Args = append(call.Args, astToDescField(a, desc.Unnamed, &unnamedSeq)) - } - if n.Ret != nil { - call.Ret = astToDescType(n.Ret, desc.Unnamed, &unnamedSeq) - } - desc.Syscalls = append(desc.Syscalls, call) - case *ast.Struct: - str := &Struct{ - Name: n.Name.Name, - IsUnion: n.IsUnion, - } - for _, f := range n.Fields { - str.Flds = append(str.Flds, astToDescField(f, desc.Unnamed, &unnamedSeq)) - } - if n.IsUnion { - for _, attr := range n.Attrs { - switch attr.Name { - case "varlen": - str.Varlen = true - default: - failf("unknown union %v attribute: %v", str.Name, attr.Name) - } - } - } else { - for _, attr := range n.Attrs { - switch { - case attr.Name == "packed": - str.Packed = true - case attr.Name == "align_ptr": - str.Align = 8 // TODO: this must be target pointer size - case strings.HasPrefix(attr.Name, "align_"): - a, err := strconv.ParseUint(attr.Name[6:], 10, 64) - if err != nil { - failf("bad struct %v alignment %v: %v", str.Name, attr.Name, err) - } - if a&(a-1) != 0 || a == 0 || a > 1<<30 { - failf("bad struct %v alignment %v: must be sane power of 2", str.Name, a) - } - str.Align = int(a) - default: - failf("unknown struct %v attribute: %v", str.Name, attr.Name) - } - } - } - desc.Structs[str.Name] = str - case *ast.IntFlags: - var vals []string - for _, v := range n.Values { - if v.ValueHex { - vals = append(vals, fmt.Sprintf("0x%x", uintptr(v.Value))) - } else { - vals = append(vals, fmt.Sprint(uintptr(v.Value))) - } - } - desc.Flags[n.Name.Name] = vals - case *ast.StrFlags: - var vals []string - for _, v := range n.Values { - vals = append(vals, v.Value) - } - desc.StrFlags[n.Name.Name] = vals - } - } - sort.Sort(syscallArray(desc.Syscalls)) - return desc -} - -func astToDescField(n *ast.Field, unnamed map[string][]string, unnamedSeq *int) []string { - return append([]string{n.Name.Name}, astToDescType(n.Type, unnamed, unnamedSeq)...) -} - -func astToDescType(n *ast.Type, unnamed map[string][]string, unnamedSeq *int) []string { - res := []string{astTypeToStr(n)} - for _, t := range n.Args { - if len(t.Args) == 0 { - res = append(res, astTypeToStr(t)) - continue - } - id := fmt.Sprintf("unnamed%v", *unnamedSeq) - (*unnamedSeq)++ - unnamed[id] = astToDescType(t, unnamed, unnamedSeq) - res = append(res, id) - } - return res -} - -func astTypeToStr(n *ast.Type) string { - res := "" - switch { - case n.Ident != "": - res = n.Ident - case n.String != "": - res = fmt.Sprintf("\"%v\"", n.String) - default: - if n.ValueHex { - res = fmt.Sprintf("0x%x", uintptr(n.Value)) - } else { - res = fmt.Sprint(uintptr(n.Value)) - } - } - if n.Ident2 != "" { - res += ":" + n.Ident2 - } else if n.Value2 != 0 { - if n.Value2Hex { - res += fmt.Sprintf(":0x%x", uintptr(n.Value2)) - } else { - res += ":" + fmt.Sprint(uintptr(n.Value2)) - } - } - return res -} - -func generate(arch string, desc *Description, consts map[string]uint64, out io.Writer) { +func generate(arch string, prog *compiler.Prog, consts map[string]uint64, out io.Writer) { fmt.Fprintf(out, "// AUTOGENERATED FILE\n") fmt.Fprintf(out, "package sys\n\n") - generateResources(desc, out) - generateStructs(desc, out) - - fmt.Fprintf(out, "var Calls = []*Call{\n") - for _, s := range desc.Syscalls { - logf(4, " generate population code for %v", s.Name) - native := !strings.HasPrefix(s.CallName, "syz_") - fmt.Fprintf(out, "&Call{Name: \"%v\", CallName: \"%v\", Native: %v", s.Name, s.CallName, native) - if len(s.Ret) != 0 { - fmt.Fprintf(out, ", Ret: ") - generateArg("", "ret", s.Ret[0], "out", s.Ret[1:], desc, true, false, out) - } - fmt.Fprintf(out, ", Args: []Type{") - for i, a := range s.Args { - if i != 0 { - fmt.Fprintf(out, ", ") - } - logf(5, " generate description for arg %v", i) - generateArg("", a[0], a[1], "in", a[2:], desc, true, false, out) - } - fmt.Fprintf(out, "}, NR: %v},\n", s.NR) - } - fmt.Fprintf(out, "}\n\n") - - var constArr []NameValue - for name, val := range consts { - constArr = append(constArr, NameValue{name, val}) - } - sort.Sort(NameValueArray(constArr)) - - fmt.Fprintf(out, "const (\n") - for _, nv := range constArr { - fmt.Fprintf(out, "%v = %v\n", nv.name, nv.val) - } - fmt.Fprintf(out, ")\n") -} - -func generateResources(desc *Description, out io.Writer) { - var resArray ResourceArray - for _, res := range desc.Resources { - resArray = append(resArray, res) - } - sort.Sort(resArray) + fmt.Fprintf(out, "var resourceArray = ") + serializer.Write(out, prog.Resources) + fmt.Fprintf(out, "\n\n") - fmt.Fprintf(out, "var resourceArray = []*ResourceDesc{\n") - for _, res := range resArray { - underlying := "" - name := res.Name - kind := []string{name} - var values []string - loop: - for { - values = append(append([]string{}, res.Values...), values...) - switch res.Base { - case "int8", "int16", "int32", "int64", "intptr": - underlying = res.Base - break loop - default: - if _, ok := desc.Resources[res.Base]; !ok { - failf("resource '%v' has unknown parent resource '%v'", name, res.Base) - } - kind = append([]string{res.Base}, kind...) - res = desc.Resources[res.Base] - } - } - fmt.Fprintf(out, "&ResourceDesc{Name: \"%v\", Type: ", name) - generateArg("", "resource-type", underlying, "inout", nil, desc, true, true, out) - fmt.Fprintf(out, ", Kind: []string{") - for i, k := range kind { - if i != 0 { - fmt.Fprintf(out, ", ") - } - fmt.Fprintf(out, "\"%v\"", k) - } - fmt.Fprintf(out, "}, Values: []uint64{") - if len(values) == 0 { - values = append(values, "0") - } - for i, v := range values { - if i != 0 { - fmt.Fprintf(out, ", ") - } - fmt.Fprintf(out, "%v", v) - } - fmt.Fprintf(out, "}},\n") - } - fmt.Fprintf(out, "}\n") -} - -type structKey struct { - name string - field string - dir string -} - -func generateStructEntry(str *Struct, out io.Writer) { - typ := "StructType" - if str.IsUnion { - typ = "UnionType" - } - packed := "" - if str.Packed { - packed = ", IsPacked: true" - } - varlen := "" - if str.Varlen { - varlen = ", IsVarlen: true" - } - align := "" - if str.Align != 0 { - align = fmt.Sprintf(", AlignAttr: %v", str.Align) - } - fmt.Fprintf(out, "&%v{TypeCommon: TypeCommon{TypeName: \"%v\", IsOptional: %v} %v %v %v},\n", - typ, str.Name, false, packed, align, varlen) -} - -func generateStructFields(str *Struct, key structKey, desc *Description, out io.Writer) { - fmt.Fprintf(out, "{structKey{\"%v\", \"%v\", %v}, []Type{\n", key.name, key.field, fmtDir(key.dir)) - for _, a := range str.Flds { - generateArg(str.Name, a[0], a[1], key.dir, a[2:], desc, false, true, out) - fmt.Fprintf(out, ",\n") - } - fmt.Fprintf(out, "}},\n") - -} - -func generateStructs(desc *Description, out io.Writer) { // Struct fields can refer to other structs. Go compiler won't like if // we refer to Structs during Structs initialization. So we do // it in 2 passes: on the first pass create struct types without fields, @@ -414,441 +129,31 @@ func generateStructs(desc *Description, out io.Writer) { // Since structs of the same type can be fields with different names // of multiple other structs, we have an instance of those structs // for each field indexed by the name of the parent struct, field name and dir. + fmt.Fprintf(out, "var structFields = ") + serializer.Write(out, prog.StructFields) + fmt.Fprintf(out, "\n\n") - structMap := make(map[structKey]*Struct) - for _, str := range desc.Structs { - for _, dir := range []string{"in", "out", "inout"} { - structMap[structKey{str.Name, "", dir}] = str - } - for _, a := range str.Flds { - if innerStr, ok := desc.Structs[a[1]]; ok { - for _, dir := range []string{"in", "out", "inout"} { - structMap[structKey{a[1], a[0], dir}] = innerStr - } - } - } - } - - fmt.Fprintf(out, "var structArray = []Type{\n") - sortedStructs := make([]*Struct, 0, len(desc.Structs)) - for _, str := range desc.Structs { - sortedStructs = append(sortedStructs, str) - } - sort.Sort(structSorter(sortedStructs)) - for _, str := range sortedStructs { - generateStructEntry(str, out) - } - fmt.Fprintf(out, "}\n") + fmt.Fprintf(out, "var Calls = ") + serializer.Write(out, prog.Syscalls) + fmt.Fprintf(out, "\n\n") - fmt.Fprintf(out, "var structFields = []struct{key structKey; fields []Type}{") - sortedKeys := make([]structKey, 0, len(structMap)) - for key := range structMap { - sortedKeys = append(sortedKeys, key) + type NameValue struct { + name string + val uint64 } - sort.Sort(structKeySorter(sortedKeys)) - for _, key := range sortedKeys { - generateStructFields(structMap[key], key, desc, out) - } - fmt.Fprintf(out, "}\n") -} - -func parseRange(buffer string) (string, string) { - parts := strings.Split(buffer, ":") - switch len(parts) { - case 1: - return buffer, buffer - case 2: - return parts[0], parts[1] - default: - failf("bad range: %v", buffer) - return "", "" - } -} - -func generateArg( - parent, name, typ, dir string, - a []string, - desc *Description, - isArg, isField bool, - out io.Writer) { - origName := name - name = "\"" + name + "\"" - opt := false - for i, v := range a { - if v == "opt" { - opt = true - copy(a[i:], a[i+1:]) - a = a[:len(a)-1] - break - } - } - fmtDir(dir) // Make sure that dir is "in", "out" or "inout" - common := func() string { - return fmt.Sprintf("TypeCommon: TypeCommon{TypeName: \"%v\", FldName: %v, ArgDir: %v, IsOptional: %v}", typ, name, fmtDir(dir), opt) - } - intCommon := func(typeSize uint64, bigEndian bool, bitfieldLen uint64) string { - // BitfieldOff and BitfieldLst will be filled in in initAlign(). - return fmt.Sprintf("IntTypeCommon: IntTypeCommon{%v, TypeSize: %v, BigEndian: %v, BitfieldLen: %v}", common(), typeSize, bigEndian, bitfieldLen) - } - canBeArg := false - switch typ { - case "fileoff": - canBeArg = true - size := uint64(ptrSize) - bigEndian := false - bitfieldLen := uint64(0) - if isField { - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - size, bigEndian, bitfieldLen = decodeIntType(a[0]) - } else { - if want := 0; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - } - fmt.Fprintf(out, "&IntType{%v, Kind: IntFileoff}", intCommon(size, bigEndian, bitfieldLen)) - case "buffer": - canBeArg = true - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - ptrCommonHdr := common() - dir = a[0] - opt = false - fmt.Fprintf(out, "&PtrType{%v, Type: &BufferType{%v, Kind: BufferBlobRand}}", ptrCommonHdr, common()) - case "string": - if len(a) != 0 && len(a) != 1 && len(a) != 2 { - failf("wrong number of arguments for %v arg %v, want 0-2, got %v", typ, name, len(a)) - } - var vals []string - subkind := "" - if len(a) >= 1 { - if a[0][0] == '"' { - vals = append(vals, a[0][1:len(a[0])-1]) - } else { - vals1, ok := desc.StrFlags[a[0]] - if !ok { - failf("unknown string flags %v", a[0]) - } - vals = append([]string{}, vals1...) - subkind = a[0] - } - } - for i, s := range vals { - vals[i] = s + "\x00" - } - var size uint64 - if len(a) >= 2 { - v, err := strconv.ParseUint(a[1], 10, 64) - if err != nil { - failf("failed to parse string length for %v", name, a[1]) - } - size = v - for i, s := range vals { - if uint64(len(s)) > size { - failf("string value %q exceeds buffer length %v for arg %v", s, size, name) - } - for uint64(len(s)) < size { - s += "\x00" - } - vals[i] = s - } - } else { - for _, s := range vals { - if size != 0 && size != uint64(len(s)) { - size = 0 - break - } - size = uint64(len(s)) - } - } - fmt.Fprintf(out, "&BufferType{%v, Kind: BufferString, SubKind: %q, Values: %#v, Length: %v}", common(), subkind, vals, size) - case "vma": - canBeArg = true - begin, end := "0", "0" - switch len(a) { - case 0: - case 1: - begin, end = parseRange(a[0]) - default: - failf("wrong number of arguments for %v arg %v, want 0 or 1, got %v", typ, name, len(a)) - } - fmt.Fprintf(out, "&VmaType{%v, RangeBegin: %v, RangeEnd: %v}", common(), begin, end) - case "len", "bytesize", "bytesize2", "bytesize4", "bytesize8": - canBeArg = true - size := uint64(ptrSize) - bigEndian := false - bitfieldLen := uint64(0) - if isField { - if want := 2; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - size, bigEndian, bitfieldLen = decodeIntType(a[1]) - } else { - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - } - byteSize := uint8(0) - if typ != "len" { - byteSize = decodeByteSizeType(typ) - } - fmt.Fprintf(out, "&LenType{%v, Buf: \"%v\", ByteSize: %v}", intCommon(size, bigEndian, bitfieldLen), a[0], byteSize) - case "csum": - if len(a) != 3 && len(a) != 4 { - failf("wrong number of arguments for %v arg %v, want 3-4, got %v", typ, name, len(a)) - } - var size uint64 - var bigEndian bool - var bitfieldLen uint64 - var protocol uint64 - var kind string - switch a[1] { - case "inet": - kind = "CsumInet" - size, bigEndian, bitfieldLen = decodeIntType(a[2]) - case "pseudo": - kind = "CsumPseudo" - size, bigEndian, bitfieldLen = decodeIntType(a[3]) - v, err := strconv.ParseUint(a[2], 10, 64) - if err != nil { - failf("failed to parse protocol %v", a[2]) - } - protocol = v - default: - failf("unknown checksum kind '%v'", a[0]) - } - fmt.Fprintf(out, "&CsumType{%v, Buf: \"%s\", Kind: %v, Protocol: %v}", intCommon(size, bigEndian, bitfieldLen), a[0], kind, protocol) - case "flags": - canBeArg = true - size := uint64(ptrSize) - bigEndian := false - bitfieldLen := uint64(0) - if isField { - if want := 2; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - size, bigEndian, bitfieldLen = decodeIntType(a[1]) - } else { - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - } - vals, ok := desc.Flags[a[0]] - if !ok { - failf("unknown flag %v", a[0]) - } - if len(vals) == 0 { - fmt.Fprintf(out, "&IntType{%v}", intCommon(size, bigEndian, bitfieldLen)) - } else { - fmt.Fprintf(out, "&FlagsType{%v, Vals: []uint64{%v}}", intCommon(size, bigEndian, bitfieldLen), strings.Join(vals, ",")) - } - case "const": - canBeArg = true - size := uint64(ptrSize) - bigEndian := false - bitfieldLen := uint64(0) - if isField { - if want := 2; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - size, bigEndian, bitfieldLen = decodeIntType(a[1]) - } else { - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - } - fmt.Fprintf(out, "&ConstType{%v, Val: uint64(%v)}", intCommon(size, bigEndian, bitfieldLen), a[0]) - case "proc": - canBeArg = true - want := 2 - if isField { - want = 3 - } - if len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - valuesStart := a[0] - valuesPerProc := a[1] - size, bitfieldLen, bigEndian := uint64(ptrSize), uint64(0), false - if isField { - size, bigEndian, bitfieldLen = decodeIntType(a[2]) - } - valuesStartInt, err := strconv.ParseInt(valuesStart, 10, 64) - if err != nil { - failf("couldn't parse '%v' as int64", valuesStart) - } - valuesPerProcInt, err := strconv.ParseInt(valuesPerProc, 10, 64) - if err != nil { - failf("couldn't parse '%v' as int64", valuesPerProc) - } - if valuesPerProcInt < 1 { - failf("values per proc '%v' should be >= 1", valuesPerProcInt) - } - if size != 8 && valuesStartInt >= (1<<(size*8)) { - failf("values starting from '%v' overflow desired type of size '%v'", valuesStartInt, size) - } - const maxPids = 32 // executor knows about this constant (MAX_PIDS) - if size != 8 && valuesStartInt+maxPids*valuesPerProcInt >= (1<<(size*8)) { - failf("not enough values starting from '%v' with step '%v' and type size '%v' for 32 procs", valuesStartInt, valuesPerProcInt, size) - } - fmt.Fprintf(out, "&ProcType{%v, ValuesStart: %v, ValuesPerProc: %v}", intCommon(size, bigEndian, bitfieldLen), valuesStartInt, valuesPerProcInt) - case "signalno": - canBeArg = true - if want := 0; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - fmt.Fprintf(out, "&IntType{%v, Kind: IntSignalno}", intCommon(4, false, 0)) - case "filename": - if want := 0; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - fmt.Fprintf(out, "&BufferType{%v, Kind: BufferFilename}", common()) - case "text": - if want := 1; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - kind := "" - switch a[0] { - case "x86_real", "x86_16", "x86_32", "x86_64", "arm64": - kind = "Text_" + a[0] - default: - failf("unknown text type %v for %v arg %v", a[0], typ, name) - } - fmt.Fprintf(out, "&BufferType{%v, Kind: BufferText, Text: %v}", common(), kind) - case "array": - if len(a) != 1 && len(a) != 2 { - failf("wrong number of arguments for %v arg %v, want 1 or 2, got %v", typ, name, len(a)) - } - if len(a) == 1 { - if a[0] == "int8" { - fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRand}", common()) - } else { - fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRandLen}", common(), generateType(a[0], dir, desc)) - } - } else { - begin, end := parseRange(a[1]) - if a[0] == "int8" { - fmt.Fprintf(out, "&BufferType{%v, Kind: BufferBlobRange, RangeBegin: %v, RangeEnd: %v}", common(), begin, end) - } else { - fmt.Fprintf(out, "&ArrayType{%v, Type: %v, Kind: ArrayRangeLen, RangeBegin: %v, RangeEnd: %v}", common(), generateType(a[0], dir, desc), begin, end) - } - } - case "ptr": - canBeArg = true - if want := 2; len(a) != want { - failf("wrong number of arguments for %v arg %v, want %v, got %v", typ, name, want, len(a)) - } - dir = "in" - fmt.Fprintf(out, "&PtrType{%v, Type: %v}", common(), generateType(a[1], a[0], desc)) - default: - if intRegExp.MatchString(typ) { - canBeArg = true - size, bigEndian, bitfieldLen := decodeIntType(typ) - switch len(a) { - case 0: - fmt.Fprintf(out, "&IntType{%v}", intCommon(size, bigEndian, bitfieldLen)) - case 1: - begin, end := parseRange(a[0]) - fmt.Fprintf(out, "&IntType{%v, Kind: IntRange, RangeBegin: %v, RangeEnd: %v}", - intCommon(size, bigEndian, bitfieldLen), begin, end) - default: - failf("wrong number of arguments for %v arg %v, want 0 or 1, got %v", typ, name, len(a)) - } - } else if strings.HasPrefix(typ, "unnamed") { - if inner, ok := desc.Unnamed[typ]; ok { - generateArg("", "", inner[0], dir, inner[1:], desc, false, isField, out) - } else { - failf("unknown unnamed type '%v'", typ) - } - } else if _, ok := desc.Structs[typ]; ok { - if len(a) != 0 { - failf("struct '%v' has args", typ) - } - fmt.Fprintf(out, "getStruct(structKey{\"%v\", \"%v\", %v})", typ, origName, fmtDir(dir)) - } else if _, ok := desc.Resources[typ]; ok { - if len(a) != 0 { - failf("resource '%v' has args", typ) - } - fmt.Fprintf(out, "&ResourceType{%v, Desc: resource(\"%v\")}", common(), typ) - return - } else { - failf("unknown arg type \"%v\" for %v", typ, name) - } - } - if isArg && !canBeArg { - failf("%v %v can't be syscall argument/return", name, typ) - } -} - -func generateType(typ, dir string, desc *Description) string { - buf := new(bytes.Buffer) - generateArg("", "", typ, dir, nil, desc, false, true, buf) - return buf.String() -} - -func fmtDir(s string) string { - switch s { - case "in": - return "DirIn" - case "out": - return "DirOut" - case "inout": - return "DirInOut" - default: - failf("bad direction %v", s) - return "" - } -} - -func decodeIntType(typ string) (uint64, bool, uint64) { - bigEndian := false - bitfieldLen := uint64(0) - - parts := strings.Split(typ, ":") - if len(parts) == 2 { - var err error - bitfieldLen, err = strconv.ParseUint(parts[1], 10, 64) - if err != nil { - failf("failed to parse bitfield length '%v'", parts[1]) - } - typ = parts[0] - } - - if strings.HasSuffix(typ, "be") { - bigEndian = true - typ = typ[:len(typ)-2] - } - - switch typ { - case "int8", "int16", "int32", "int64", "intptr": - default: - failf("unknown type %v", typ) - } - sz := int64(ptrSize * 8) - if typ != "intptr" { - sz, _ = strconv.ParseInt(typ[3:], 10, 64) - } - - if bitfieldLen > uint64(sz) { - failf("bitfield of size %v is too large for base type of size %v", bitfieldLen, sz/8) + constArr := make([]NameValue, 0, len(consts)) + for name, val := range consts { + constArr = append(constArr, NameValue{name, val}) } + sort.Slice(constArr, func(i, j int) bool { + return constArr[i].name < constArr[j].name + }) - return uint64(sz / 8), bigEndian, bitfieldLen -} - -func decodeByteSizeType(typ string) uint8 { - switch typ { - case "bytesize", "bytesize2", "bytesize4", "bytesize8": - default: - failf("unknown type %v", typ) - } - sz := int64(1) - if typ != "bytesize" { - sz, _ = strconv.ParseInt(typ[8:], 10, 8) + fmt.Fprintf(out, "const (\n") + for _, nv := range constArr { + fmt.Fprintf(out, "%v = %v\n", nv.name, nv.val) } - return uint8(sz) + fmt.Fprintf(out, ")\n") } func writeSource(file string, data []byte) { @@ -872,49 +177,6 @@ func writeFile(file string, data []byte) { outf.Write(data) } -type NameValue struct { - name string - val uint64 -} - -type NameValueArray []NameValue - -func (a NameValueArray) Len() int { return len(a) } -func (a NameValueArray) Less(i, j int) bool { return a[i].name < a[j].name } -func (a NameValueArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -type ResourceArray []Resource - -func (a ResourceArray) Len() int { return len(a) } -func (a ResourceArray) Less(i, j int) bool { return a[i].Name < a[j].Name } -func (a ResourceArray) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -type structSorter []*Struct - -func (a structSorter) Len() int { return len(a) } -func (a structSorter) Less(i, j int) bool { return a[i].Name < a[j].Name } -func (a structSorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - -type structKeySorter []structKey - -func (a structKeySorter) Len() int { return len(a) } -func (a structKeySorter) Less(i, j int) bool { - if a[i].name < a[j].name { - return true - } - if a[i].name > a[j].name { - return false - } - if a[i].field < a[j].field { - return true - } - if a[i].field > a[j].field { - return false - } - return a[i].dir < a[j].dir -} -func (a structKeySorter) Swap(i, j int) { a[i], a[j] = a[j], a[i] } - func failf(msg string, args ...interface{}) { fmt.Fprintf(os.Stderr, msg+"\n", args...) os.Exit(1) |
