aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--prog/any.go19
-rw-r--r--prog/prog.go35
-rw-r--r--prog/rand.go2
-rw-r--r--prog/target.go28
-rw-r--r--prog/types.go17
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