diff options
| -rw-r--r-- | prog/any.go | 19 | ||||
| -rw-r--r-- | prog/prog.go | 35 | ||||
| -rw-r--r-- | prog/rand.go | 2 | ||||
| -rw-r--r-- | prog/target.go | 28 | ||||
| -rw-r--r-- | prog/types.go | 17 |
5 files changed, 72 insertions, 29 deletions
diff --git a/prog/any.go b/prog/any.go index 7bf38b6be..bb80eaa38 100644 --- a/prog/any.go +++ b/prog/any.go @@ -135,8 +135,9 @@ func (target *Target) squashPtr(arg *PointerArg) { size0 := res0.Size() var elems []Arg target.squashPtrImpl(arg.Res, &elems) - arg.typ = target.getAnyPtrType(arg.Type().Size()) - arg.Res = MakeGroupArg(arg.typ.(*PtrType).Elem, DirIn, elems) + newType := target.getAnyPtrType(arg.Type().Size()) + arg.ref = newType.ref() + arg.Res = MakeGroupArg(newType.Elem, DirIn, elems) if size := arg.Res.Size(); size != size0 { panic(fmt.Sprintf("squash changed size %v->%v for %v", size0, size, res0.Type())) } @@ -206,28 +207,30 @@ func (target *Target) squashConst(arg *ConstArg, elems *[]Arg) { } func (target *Target) squashResult(arg *ResultArg, elems *[]Arg) { + var typ *ResourceType index := -1 switch arg.Type().Format() { case FormatNative, FormatBigEndian: switch arg.Size() { case 2: - arg.typ, index = target.any.res16, 1 + typ, index = target.any.res16, 1 case 4: - arg.typ, index = target.any.res32, 2 + typ, index = target.any.res32, 2 case 8: - arg.typ, index = target.any.res64, 3 + typ, index = target.any.res64, 3 default: panic("bad size") } case FormatStrDec: - arg.typ, index = target.any.resdec, 4 + typ, index = target.any.resdec, 4 case FormatStrHex: - arg.typ, index = target.any.reshex, 5 + typ, index = target.any.reshex, 5 case FormatStrOct: - arg.typ, index = target.any.resoct, 6 + typ, index = target.any.resoct, 6 default: panic("bad") } + arg.ref = typ.ref() arg.dir = DirIn *elems = append(*elems, MakeUnionArg(target.any.union, DirIn, arg, index)) } diff --git a/prog/prog.go b/prog/prog.go index 00e290175..3e46e15ea 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -30,12 +30,15 @@ type Arg interface { } type ArgCommon struct { - typ Type + ref Ref dir Dir } -func (arg *ArgCommon) Type() Type { - return arg.typ +func (arg ArgCommon) Type() Type { + if arg.ref == 0 { + panic("broken type ref") + } + return typeRefs.Load().([]Type)[arg.ref] } func (arg *ArgCommon) Dir() Dir { @@ -49,11 +52,11 @@ type ConstArg struct { } func MakeConstArg(t Type, dir Dir, v uint64) *ConstArg { - return &ConstArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Val: v} + return &ConstArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Val: v} } func (arg *ConstArg) Size() uint64 { - return arg.typ.Size() + return arg.Type().Size() } // Value returns value and pid stride. @@ -95,7 +98,7 @@ func MakePointerArg(t Type, dir Dir, addr uint64, data Arg) *PointerArg { panic("nil pointer data arg") } return &PointerArg{ - ArgCommon: ArgCommon{typ: t, dir: DirIn}, // pointers are always in + ArgCommon: ArgCommon{ref: t.ref(), dir: DirIn}, // pointers are always in Address: addr, Res: data, } @@ -106,7 +109,7 @@ func MakeVmaPointerArg(t Type, dir Dir, addr, size uint64) *PointerArg { panic("unaligned vma address") } return &PointerArg{ - ArgCommon: ArgCommon{typ: t, dir: dir}, + ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Address: addr, VmaSize: size, } @@ -120,13 +123,13 @@ func MakeSpecialPointerArg(t Type, dir Dir, index uint64) *PointerArg { dir = DirIn // pointers are always in } return &PointerArg{ - ArgCommon: ArgCommon{typ: t, dir: dir}, + ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Address: -index, } } func (arg *PointerArg) Size() uint64 { - return arg.typ.Size() + return arg.Type().Size() } func (arg *PointerArg) IsSpecial() bool { @@ -151,14 +154,14 @@ func MakeDataArg(t Type, dir Dir, data []byte) *DataArg { if dir == DirOut { panic("non-empty output data arg") } - return &DataArg{ArgCommon: ArgCommon{typ: t, dir: dir}, data: append([]byte{}, data...)} + return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, data: append([]byte{}, data...)} } func MakeOutDataArg(t Type, dir Dir, size uint64) *DataArg { if dir != DirOut { panic("empty input data arg") } - return &DataArg{ArgCommon: ArgCommon{typ: t, dir: dir}, size: size} + return &DataArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, size: size} } func (arg *DataArg) Size() uint64 { @@ -190,7 +193,7 @@ type GroupArg struct { } func MakeGroupArg(t Type, dir Dir, inner []Arg) *GroupArg { - return &GroupArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Inner: inner} + return &GroupArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Inner: inner} } func (arg *GroupArg) Size() uint64 { @@ -238,7 +241,7 @@ type UnionArg struct { } func MakeUnionArg(t Type, dir Dir, opt Arg, index int) *UnionArg { - return &UnionArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Option: opt, Index: index} + return &UnionArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Option: opt, Index: index} } func (arg *UnionArg) Size() uint64 { @@ -261,7 +264,7 @@ type ResultArg struct { } func MakeResultArg(t Type, dir Dir, r *ResultArg, v uint64) *ResultArg { - arg := &ResultArg{ArgCommon: ArgCommon{typ: t, dir: dir}, Res: r, Val: v} + arg := &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: dir}, Res: r, Val: v} if r == nil { return arg } @@ -276,11 +279,11 @@ func MakeReturnArg(t Type) *ResultArg { if t == nil { return nil } - return &ResultArg{ArgCommon: ArgCommon{typ: t, dir: DirOut}} + return &ResultArg{ArgCommon: ArgCommon{ref: t.ref(), dir: DirOut}} } func (arg *ResultArg) Size() uint64 { - return arg.typ.Size() + return arg.Type().Size() } // Returns inner arg for pointer args. diff --git a/prog/rand.go b/prog/rand.go index 18c86d77a..019745161 100644 --- a/prog/rand.go +++ b/prog/rand.go @@ -901,7 +901,7 @@ func getCompatibleResources(p *Prog, resourceType string, r *randGen) (resources if !ok || len(a.uses) == 0 || a.Dir() != DirOut { return } - if !r.target.isCompatibleResource(resourceType, a.typ.Name()) { + if !r.target.isCompatibleResource(resourceType, a.Type().Name()) { return } resources = append(resources, a) diff --git a/prog/target.go b/prog/target.go index 630fb7cbf..f19ed3fa2 100644 --- a/prog/target.go +++ b/prog/target.go @@ -8,6 +8,7 @@ import ( "math/rand" "sort" "sync" + "sync/atomic" ) // Target describes target OS/arch pair. @@ -182,16 +183,35 @@ func RestoreLinks(syscalls []*Syscall, resources []*ResourceDesc, types []Type) restoreLinks(syscalls, resources, types) } +var ( + typeRefMu sync.Mutex + typeRefs atomic.Value // []Type +) + func restoreLinks(syscalls []*Syscall, resources []*ResourceDesc, types []Type) map[string]*ResourceDesc { + typeRefMu.Lock() + defer typeRefMu.Unlock() + refs := []Type{nil} + if old := typeRefs.Load(); old != nil { + refs = old.([]Type) + } + for _, typ := range types { + typ.setRef(Ref(len(refs))) + refs = append(refs, typ) + } + typeRefs.Store(refs) + resourceMap := make(map[string]*ResourceDesc) for _, res := range resources { resourceMap[res.Name] = res } - ForeachType(syscalls, func(_ Type, ctx TypeCtx) { - if ref, ok := (*ctx.Ptr).(Ref); ok { - *ctx.Ptr = types[ref] + + ForeachType(syscalls, func(typ Type, ctx TypeCtx) { + if ref, ok := typ.(Ref); ok { + typ = types[ref] + *ctx.Ptr = typ } - switch t := (*ctx.Ptr).(type) { + switch t := typ.(type) { case *ResourceType: t.Desc = resourceMap[t.TypeName] if t.Desc == nil { diff --git a/prog/types.go b/prog/types.go index 33c7bd356..2928e54c8 100644 --- a/prog/types.go +++ b/prog/types.go @@ -104,6 +104,8 @@ type Type interface { mutate(r *randGen, s *state, arg Arg, ctx ArgCtx) (calls []*Call, retry, preserve bool) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (prio float64, stopRecursion bool) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool + ref() Ref + setRef(ref Ref) } type Ref uint32 @@ -135,6 +137,8 @@ func (ti Ref) getMutationPrio(target *Target, arg Arg, ignoreSpecial bool) (floa func (ti Ref) minimize(ctx *minimizeArgsCtx, arg Arg, path string) bool { panic("prog.Ref method called") } +func (ti Ref) ref() Ref { panic("prog.Ref method called") } +func (ti Ref) setRef(ref Ref) { panic("prog.Ref method called") } func IsPad(t Type) bool { if ct, ok := t.(*ConstType); ok && ct.IsPad { @@ -149,6 +153,8 @@ type TypeCommon struct { TypeSize uint64 IsOptional bool IsVarlen bool + + self Ref } func (t *TypeCommon) Name() string { @@ -206,6 +212,17 @@ func (t *TypeCommon) IsBitfield() bool { return false } +func (t *TypeCommon) ref() Ref { + if t.self == 0 { + panic("ref is not assigned yet") + } + return t.self +} + +func (t *TypeCommon) setRef(ref Ref) { + t.self = ref +} + type ResourceDesc struct { Name string Kind []string |
