aboutsummaryrefslogtreecommitdiffstats
path: root/prog/resources.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2018-06-18 19:45:48 +0200
committerDmitry Vyukov <dvyukov@google.com>2018-06-18 19:45:48 +0200
commitdcb1eebb7ffdd179de39e7cb89ca085368ee69d5 (patch)
tree00cd2f8591f0dbb82cade9531b5af050a303127d /prog/resources.go
parent920b18be87d248413f549d978d7dd68495a6ea7c (diff)
prog: more precise constructor calculation
Currently a call that both accepts and creates a resource self-justifies itself and thus is always enabled. A good example is accept call. Accepts are always self-enable and thus enable all other syscalls that work with the socket. Calculate TransitivelyEnabledCalls in the opposite direction to resolve this. Start with empty set of enable syscalls, then enable syscalls that don't accept any resources, then enable syscalls that accept resources created by the previous batch of syscalls, and so on. This prevents self-enablement of accept.
Diffstat (limited to 'prog/resources.go')
-rw-r--r--prog/resources.go128
1 files changed, 79 insertions, 49 deletions
diff --git a/prog/resources.go b/prog/resources.go
index 68fbe1599..bddb158d9 100644
--- a/prog/resources.go
+++ b/prog/resources.go
@@ -7,6 +7,13 @@ import (
"fmt"
)
+// We need to support structs as resources,
+// but for now we just special-case timespec/timeval.
+var timespecRes = &ResourceDesc{
+ Name: "timespec",
+ Kind: []string{"timespec"},
+}
+
func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall {
// Find calls that produce the necessary resources.
var metas []*Syscall
@@ -28,6 +35,11 @@ func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall
metas = append(metas, meta)
}
}
+ if kind[0] == timespecRes.Name {
+ if c := target.SyscallMap["clock_gettime"]; c != nil {
+ metas = append(metas, c)
+ }
+ }
return metas
}
@@ -72,82 +84,100 @@ func isCompatibleResourceImpl(dst, src []string, precise bool) bool {
return true
}
-func (c *Syscall) inputResources() []*ResourceType {
- var resources []*ResourceType
+func (target *Target) inputResources(c *Syscall) []*ResourceDesc {
+ var resources []*ResourceDesc
+ ForeachType(c, func(typ Type) {
+ if typ.Dir() == DirOut {
+ return
+ }
+ switch typ1 := typ.(type) {
+ case *ResourceType:
+ if !typ1.IsOptional {
+ resources = append(resources, typ1.Desc)
+ }
+ case *StructType:
+ if target.OS == "linux" && (typ1.Name() == "timespec" || typ1.Name() == "timeval") {
+ resources = append(resources, timespecRes)
+ }
+ }
+ })
+ return resources
+}
+
+func (target *Target) outputResources(c *Syscall) []*ResourceDesc {
+ var resources []*ResourceDesc
ForeachType(c, func(typ Type) {
switch typ1 := typ.(type) {
case *ResourceType:
- if typ1.Dir() != DirOut && !typ1.IsOptional {
- resources = append(resources, typ1)
+ if typ1.Dir() != DirIn {
+ resources = append(resources, typ1.Desc)
}
}
})
+ if c.CallName == "clock_gettime" {
+ resources = append(resources, timespecRes)
+ }
return resources
}
func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) (map[*Syscall]bool, map[*Syscall]string) {
supported := make(map[*Syscall]bool)
disabled := make(map[*Syscall]string)
+ canCreate := make(map[string]bool)
+ inputResources := make(map[*Syscall][]*ResourceDesc)
for c := range enabled {
- supported[c] = true
- }
- inputResources := make(map[*Syscall][]*ResourceType)
- ctors := make(map[string][]*Syscall)
- for c := range supported {
- inputs := c.inputResources()
- inputResources[c] = inputs
- for _, res := range inputs {
- if _, ok := ctors[res.Desc.Name]; ok {
- continue
- }
- ctors[res.Desc.Name] = target.calcResourceCtors(res.Desc.Kind, true)
- }
+ inputResources[c] = target.inputResources(c)
}
for {
n := len(supported)
- haveGettime := supported[target.SyscallMap["clock_gettime"]]
- for c := range supported {
- cantCreate := ""
- var resourceCtors []*Syscall
+ for c := range enabled {
+ if supported[c] {
+ continue
+ }
+ ready := true
for _, res := range inputResources[c] {
- noctors := true
- for _, ctor := range ctors[res.Desc.Name] {
- if supported[ctor] {
- noctors = false
- break
- }
- }
- if noctors {
- cantCreate = res.Desc.Name
- resourceCtors = ctors[res.Desc.Name]
+ if !canCreate[res.Name] {
+ ready = false
break
}
}
- // We need to support structs as resources,
- // but for now we just special-case timespec/timeval.
- if cantCreate == "" && !haveGettime && target.SyscallMap["clock_gettime"] != nil {
- ForeachType(c, func(typ Type) {
- if a, ok := typ.(*StructType); ok && a.Dir() != DirOut &&
- (a.Name() == "timespec" || a.Name() == "timeval") {
- cantCreate = a.Name()
- resourceCtors = []*Syscall{target.SyscallMap["clock_gettime"]}
+ if ready {
+ supported[c] = true
+ for _, res := range target.outputResources(c) {
+ for _, kind := range res.Kind {
+ canCreate[kind] = true
}
- })
- }
- if cantCreate != "" {
- delete(supported, c)
- var ctorNames []string
- for _, ctor := range resourceCtors {
- ctorNames = append(ctorNames, ctor.Name)
}
- disabled[c] = fmt.Sprintf("no syscalls can create resource %v,"+
- " enable some syscalls that can create it %v",
- cantCreate, ctorNames)
}
}
if n == len(supported) {
break
}
}
+ ctors := make(map[string][]string)
+ for c := range enabled {
+ if supported[c] {
+ continue
+ }
+ for _, res := range inputResources[c] {
+ if canCreate[res.Name] {
+ continue
+ }
+ if ctors[res.Name] == nil {
+ var names []string
+ for _, call := range target.calcResourceCtors(res.Kind, true) {
+ names = append(names, call.Name)
+ }
+ ctors[res.Name] = names
+ }
+ disabled[c] = fmt.Sprintf("no syscalls can create resource %v,"+
+ " enable some syscalls that can create it %v",
+ res.Name, ctors[res.Name])
+ break
+ }
+ }
+ if len(enabled) != len(supported)+len(disabled) {
+ panic("lost syscalls")
+ }
return supported, disabled
}