aboutsummaryrefslogtreecommitdiffstats
path: root/pkg
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2020-03-16 08:14:39 +0100
committerDmitry Vyukov <dvyukov@google.com>2020-03-17 21:19:13 +0100
commit1ea952c9ffd767584c60a91d6f6d8ca603817c50 (patch)
tree3a495458a9fed4e4bfc0488a34f65dde34b9eac0 /pkg
parent8bec3911ad478b6fef8df96e4dc89f8080229133 (diff)
pkg/compiler: calculate more precise sizes for arguments
If we have: ioctl(fd fd, cmd int32) ioctl$FOO(fd fd, cmd const[FOO]) Currently we assume that cmd size in ioctl$FOO is sizeof(void*). However, we know that in ioctl it's specified as int32, so we can infer that the actual syscall size is 4. This massively reduces sizes of socket/setsockopt/getsockopt/ioctl and some other syscalls, which is good because we now use physical size in mutation/hints and some other places. This will also enable not morphing ioctl's into other ioctl's. Update #477 Update #502
Diffstat (limited to 'pkg')
-rw-r--r--pkg/compiler/gen.go35
1 files changed, 31 insertions, 4 deletions
diff --git a/pkg/compiler/gen.go b/pkg/compiler/gen.go
index 1ced4f7e3..30080f56a 100644
--- a/pkg/compiler/gen.go
+++ b/pkg/compiler/gen.go
@@ -97,7 +97,7 @@ func (comp *compiler) genSyscalls() []*prog.Syscall {
var calls []*prog.Syscall
for _, decl := range comp.desc.Nodes {
if n, ok := decl.(*ast.Call); ok && n.NR != ^uint64(0) {
- calls = append(calls, comp.genSyscall(n, len(callArgSizes[n.CallName])))
+ calls = append(calls, comp.genSyscall(n, callArgSizes[n.CallName]))
}
}
sort.Slice(calls, func(i, j int) bool {
@@ -106,21 +106,48 @@ func (comp *compiler) genSyscalls() []*prog.Syscall {
return calls
}
-func (comp *compiler) genSyscall(n *ast.Call, maxArgs int) *prog.Syscall {
+func (comp *compiler) genSyscall(n *ast.Call, argSizes []uint64) *prog.Syscall {
var ret prog.Type
if n.Ret != nil {
ret = comp.genType(n.Ret, "ret", prog.DirOut, true)
}
+ args := comp.genFieldArray(n.Args, prog.DirIn, true)
+ for i, arg := range args {
+ // Now that we know a more precise size, patch the type.
+ // This is somewhat hacky. Ideally we figure out the size earlier,
+ // store it somewhere and use during generation of the arg base type.
+ if argSizes[i] != 0 {
+ patchArgBaseSize(arg, argSizes[i])
+ }
+ }
return &prog.Syscall{
Name: n.Name.Name,
CallName: n.CallName,
NR: n.NR,
- MissingArgs: maxArgs - len(n.Args),
- Args: comp.genFieldArray(n.Args, prog.DirIn, true),
+ MissingArgs: len(argSizes) - len(n.Args),
+ Args: args,
Ret: ret,
}
}
+func patchArgBaseSize(t0 prog.Type, size uint64) {
+ // We only need types that (1) can be arg, (2) have base type.
+ switch t := t0.(type) {
+ case *prog.ConstType:
+ t.TypeSize = size
+ case *prog.LenType:
+ t.TypeSize = size
+ case *prog.FlagsType:
+ t.TypeSize = size
+ case *prog.ProcType:
+ t.TypeSize = size
+ case *prog.IntType, *prog.ResourceType, *prog.PtrType, *prog.VmaType, *prog.UnionType:
+ // These don't have base.
+ default:
+ panic(fmt.Sprintf("type %#v can't be an arg", t))
+ }
+}
+
func (comp *compiler) genStructDescs(syscalls []*prog.Syscall) []*prog.KeyedStruct {
// Calculate struct/union/array sizes, add padding to structs and detach
// StructDesc's from StructType's. StructType's can be recursive so it's