diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2020-03-16 08:14:39 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2020-03-17 21:19:13 +0100 |
| commit | 1ea952c9ffd767584c60a91d6f6d8ca603817c50 (patch) | |
| tree | 3a495458a9fed4e4bfc0488a34f65dde34b9eac0 /pkg | |
| parent | 8bec3911ad478b6fef8df96e4dc89f8080229133 (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.go | 35 |
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 |
