diff options
Diffstat (limited to 'prog')
| -rw-r--r-- | prog/any.go | 196 | ||||
| -rw-r--r-- | prog/decodeexec.go | 9 | ||||
| -rw-r--r-- | prog/encodingexec.go | 20 | ||||
| -rw-r--r-- | prog/encodingexec_test.go | 2 | ||||
| -rw-r--r-- | prog/prog.go | 37 | ||||
| -rw-r--r-- | prog/resources.go | 20 | ||||
| -rw-r--r-- | prog/types.go | 28 |
7 files changed, 207 insertions, 105 deletions
diff --git a/prog/any.go b/prog/any.go index 92e466280..3f0cb4825 100644 --- a/prog/any.go +++ b/prog/any.go @@ -13,6 +13,9 @@ type anyTypes struct { res16 *ResourceType res32 *ResourceType res64 *ResourceType + resdec *ResourceType + reshex *ResourceType + resoct *ResourceType } // This generates type descriptions for: @@ -27,6 +30,9 @@ type anyTypes struct { // res16 ANYRES16 // res32 ANYRES32 // res64 ANYRES64 +// resdec fmt[dec, ANYRES64] +// reshex fmt[hex, ANYRES64] +// resoct fmt[oct, ANYRES64] // ] [varlen] func initAnyTypes(target *Target) { target.any.union = &UnionType{ @@ -65,7 +71,7 @@ func initAnyTypes(target *Target) { IsVarlen: true, }, } - createResource := func(name, base string, size uint64) *ResourceType { + createResource := func(name, base string, bf BinaryFormat, size uint64) *ResourceType { return &ResourceType{ TypeCommon: TypeCommon{ TypeName: name, @@ -74,6 +80,7 @@ func initAnyTypes(target *Target) { TypeSize: size, IsOptional: true, }, + ArgFormat: bf, Desc: &ResourceDesc{ Name: name, Kind: []string{name}, @@ -89,9 +96,12 @@ func initAnyTypes(target *Target) { }, } } - target.any.res16 = createResource("ANYRES16", "int16", 2) - target.any.res32 = createResource("ANYRES32", "int32", 4) - target.any.res64 = createResource("ANYRES64", "int64", 8) + target.any.res16 = createResource("ANYRES16", "int16", FormatNative, 2) + target.any.res32 = createResource("ANYRES32", "int32", FormatNative, 4) + target.any.res64 = createResource("ANYRES64", "int64", FormatNative, 8) + target.any.resdec = createResource("ANYRESDEC", "int64", FormatStrDec, 20) + target.any.reshex = createResource("ANYRESHEX", "int64", FormatStrHex, 18) + target.any.resoct = createResource("ANYRESOCT", "int64", FormatStrOct, 23) target.any.union.StructDesc = &StructDesc{ TypeCommon: TypeCommon{ TypeName: "ANYUNION", @@ -106,6 +116,9 @@ func initAnyTypes(target *Target) { target.any.res16, target.any.res32, target.any.res64, + target.any.resdec, + target.any.reshex, + target.any.resoct, }, } } @@ -220,28 +233,9 @@ func (target *Target) squashPtrImpl(a Arg, elems *[]Arg) { var pad uint64 switch arg := a.(type) { case *ConstArg: - if IsPad(arg.Type()) { - pad = arg.Size() - } else { - v := target.squashConst(arg) - elem := target.ensureDataElem(elems) - for i := uint64(0); i < arg.Size(); i++ { - elem.data = append(elem.Data(), byte(v)) - v >>= 8 - } - } + target.squashConst(arg, elems) case *ResultArg: - switch arg.Size() { - case 2: - arg.typ = target.any.res16 - case 4: - arg.typ = target.any.res32 - case 8: - arg.typ = target.any.res64 - default: - panic("bad size") - } - *elems = append(*elems, MakeUnionArg(target.any.union, arg)) + target.squashResult(arg, elems) case *PointerArg: if arg.Res != nil { target.squashPtr(arg, false) @@ -267,40 +261,107 @@ func (target *Target) squashPtrImpl(a Arg, elems *[]Arg) { elem.data = append(elem.Data(), arg.Data()...) } case *GroupArg: - if typ, ok := arg.Type().(*StructType); ok && typ.Varlen() && typ.AlignAttr != 0 { - var fieldsSize uint64 - for _, fld := range arg.Inner { - if !fld.Type().BitfieldMiddle() { - fieldsSize += fld.Size() - } - } - if fieldsSize%typ.AlignAttr != 0 { - pad = typ.AlignAttr - fieldsSize%typ.AlignAttr - } + target.squashGroup(arg, elems) + default: + panic("bad arg kind") + } + if pad != 0 { + elem := target.ensureDataElem(elems) + elem.data = append(elem.Data(), make([]byte, pad)...) + } +} + +func (target *Target) squashConst(arg *ConstArg, elems *[]Arg) { + if IsPad(arg.Type()) { + elem := target.ensureDataElem(elems) + elem.data = append(elem.Data(), make([]byte, arg.Size())...) + return + } + v, bf := target.squashedValue(arg) + var data []byte + switch bf { + case FormatNative: + for i := uint64(0); i < arg.Size(); i++ { + data = append(data, byte(v)) + v >>= 8 + } + case FormatStrDec: + data = []byte(fmt.Sprintf("%020v", v)) + case FormatStrHex: + data = []byte(fmt.Sprintf("0x%016x", v)) + case FormatStrOct: + data = []byte(fmt.Sprintf("%023o", v)) + default: + panic(fmt.Sprintf("unknown binary format: %v", bf)) + } + if uint64(len(data)) != arg.Size() { + panic("squashed value of wrong size") + } + elem := target.ensureDataElem(elems) + elem.data = append(elem.Data(), data...) +} + +func (target *Target) squashResult(arg *ResultArg, elems *[]Arg) { + switch arg.Type().Format() { + case FormatNative, FormatBigEndian: + switch arg.Size() { + case 2: + arg.typ = target.any.res16 + case 4: + arg.typ = target.any.res32 + case 8: + arg.typ = target.any.res64 + default: + panic("bad size") } - var bitfield uint64 + case FormatStrDec: + arg.typ = target.any.resdec + case FormatStrHex: + arg.typ = target.any.reshex + case FormatStrOct: + arg.typ = target.any.resoct + default: + panic("bad") + } + *elems = append(*elems, MakeUnionArg(target.any.union, arg)) +} + +func (target *Target) squashGroup(arg *GroupArg, elems *[]Arg) { + var pad uint64 + if typ, ok := arg.Type().(*StructType); ok && typ.Varlen() && typ.AlignAttr != 0 { + var fieldsSize uint64 for _, fld := range arg.Inner { - // Squash bitfields separately. - if bfLen := fld.Type().BitfieldLength(); bfLen != 0 { - bfOff := fld.Type().BitfieldOffset() - // Note: we can have a ResultArg here as well, - // but it is unsupported at the moment. - v := target.squashConst(fld.(*ConstArg)) - bitfield |= (v & ((1 << bfLen) - 1)) << bfOff - if !fld.Type().BitfieldMiddle() { - elem := target.ensureDataElem(elems) - for i := uint64(0); i < fld.Size(); i++ { - elem.data = append(elem.Data(), byte(bitfield)) - bitfield >>= 8 - } - bitfield = 0 + if !fld.Type().BitfieldMiddle() { + fieldsSize += fld.Size() + } + } + if fieldsSize%typ.AlignAttr != 0 { + pad = typ.AlignAttr - fieldsSize%typ.AlignAttr + } + } + var bitfield uint64 + for _, fld := range arg.Inner { + // Squash bitfields separately. + if bfLen := fld.Type().BitfieldLength(); bfLen != 0 { + bfOff := fld.Type().BitfieldOffset() + // Note: we can have a ResultArg here as well, + // but it is unsupported at the moment. + v, bf := target.squashedValue(fld.(*ConstArg)) + if bf != FormatNative { + panic(fmt.Sprintf("bitfield has bad format %v", bf)) + } + bitfield |= (v & ((1 << bfLen) - 1)) << bfOff + if !fld.Type().BitfieldMiddle() { + elem := target.ensureDataElem(elems) + for i := uint64(0); i < fld.Size(); i++ { + elem.data = append(elem.Data(), byte(bitfield)) + bitfield >>= 8 } - continue + bitfield = 0 } - target.squashPtrImpl(fld, elems) + continue } - default: - panic("bad arg kind") + target.squashPtrImpl(fld, elems) } if pad != 0 { elem := target.ensureDataElem(elems) @@ -308,15 +369,32 @@ func (target *Target) squashPtrImpl(a Arg, elems *[]Arg) { } } -func (target *Target) squashConst(arg *ConstArg) uint64 { - // Note: we need a constant value, but it depends on pid for proc. - v := arg.ValueForProc(0) +func (target *Target) squashedValue(arg *ConstArg) (uint64, BinaryFormat) { + bf := arg.Type().Format() if _, ok := arg.Type().(*CsumType); ok { // We can't compute value for the checksum here, // but at least leave something recognizable by hints code. - v = 0xabcdef1234567890 + // TODO: hints code won't recognize this, because it won't find + // the const in any arg. We either need to put this const as + // actual csum arg value, or special case it in hints. + return 0xabcdef1234567890, FormatNative + } + // Note: we need a constant value, but it depends on pid for proc. + v, _ := arg.Value() + if bf == FormatBigEndian { + bf = FormatNative + switch arg.Size() { + case 2: + v = uint64(swap16(uint16(v))) + case 4: + v = uint64(swap32(uint32(v))) + case 8: + v = swap64(v) + default: + panic(fmt.Sprintf("bad const size %v", arg.Size())) + } } - return v + return v, bf } func (target *Target) ensureDataElem(elems *[]Arg) *DataArg { diff --git a/prog/decodeexec.go b/prog/decodeexec.go index f8c29a517..5866d8627 100644 --- a/prog/decodeexec.go +++ b/prog/decodeexec.go @@ -35,15 +35,16 @@ type ExecArg interface{} // one of ExecArg* type ExecArgConst struct { Size uint64 + Format BinaryFormat Value uint64 BitfieldOffset uint64 BitfieldLength uint64 PidStride uint64 - BigEndian bool } type ExecArgResult struct { Size uint64 + Format BinaryFormat Index uint64 DivOp uint64 AddOp uint64 @@ -139,14 +140,16 @@ func (dec *execDecoder) readArg() ExecArg { return ExecArgConst{ Value: dec.read(), Size: meta & 0xff, + Format: BinaryFormat((meta >> 8) & 0xff), BitfieldOffset: (meta >> 16) & 0xff, BitfieldLength: (meta >> 24) & 0xff, PidStride: meta >> 32, - BigEndian: (meta & (1 << 8)) != 0, } case execArgResult: + meta := dec.read() arg := ExecArgResult{ - Size: dec.read(), + Size: meta & 0xff, + Format: BinaryFormat((meta >> 8) & 0xff), Index: dec.read(), DivOp: dec.read(), AddOp: dec.read(), diff --git a/prog/encodingexec.go b/prog/encodingexec.go index a162a7126..25e99e215 100644 --- a/prog/encodingexec.go +++ b/prog/encodingexec.go @@ -230,26 +230,27 @@ func (w *execContext) write(v uint64) { func (w *execContext) writeArg(arg Arg) { switch a := arg.(type) { case *ConstArg: - val, pidStride, bigEndian := a.Value() - w.writeConstArg(a.Size(), val, a.Type().BitfieldOffset(), a.Type().BitfieldLength(), - pidStride, bigEndian) + val, pidStride := a.Value() + typ := a.Type() + w.writeConstArg(a.Size(), val, typ.BitfieldOffset(), typ.BitfieldLength(), pidStride, typ.Format()) case *ResultArg: if a.Res == nil { - w.writeConstArg(a.Size(), a.Val, 0, 0, 0, false) + w.writeConstArg(a.Size(), a.Val, 0, 0, 0, a.Type().Format()) } else { info, ok := w.args[a.Res] if !ok { panic("no copyout index") } w.write(execArgResult) - w.write(a.Size()) + meta := a.Size() | uint64(a.Type().Format())<<8 + w.write(meta) w.write(info.Idx) w.write(a.OpDiv) w.write(a.OpAdd) w.write(a.Type().(*ResourceType).Default()) } case *PointerArg: - w.writeConstArg(a.Size(), w.target.PhysicalAddr(a), 0, 0, 0, false) + w.writeConstArg(a.Size(), w.target.PhysicalAddr(a), 0, 0, 0, FormatNative) case *DataArg: data := a.Data() w.write(execArgData) @@ -271,12 +272,9 @@ func (w *execContext) writeArg(arg Arg) { } } -func (w *execContext) writeConstArg(size, val, bfOffset, bfLength, pidStride uint64, bigEndian bool) { +func (w *execContext) writeConstArg(size, val, bfOffset, bfLength, pidStride uint64, bf BinaryFormat) { w.write(execArgConst) - meta := size | bfOffset<<16 | bfLength<<24 | pidStride<<32 - if bigEndian { - meta |= 1 << 8 - } + meta := size | uint64(bf)<<8 | bfOffset<<16 | bfLength<<24 | pidStride<<32 w.write(meta) w.write(val) } diff --git a/prog/encodingexec_test.go b/prog/encodingexec_test.go index 1b3fb14b4..ed0a41ddc 100644 --- a/prog/encodingexec_test.go +++ b/prog/encodingexec_test.go @@ -324,10 +324,10 @@ func TestSerializeForExec(t *testing.T) { Addr: dataOffset + 26, Arg: ExecArgConst{ Size: 2, + Format: FormatBigEndian, Value: 0x42, BitfieldOffset: 0, BitfieldLength: 11, - BigEndian: true, }, }, { diff --git a/prog/prog.go b/prog/prog.go index 3474950b9..19db1893d 100644 --- a/prog/prog.go +++ b/prog/prog.go @@ -47,50 +47,31 @@ func (arg *ConstArg) Size() uint64 { } // Value returns value, pid stride and endianness. -func (arg *ConstArg) Value() (uint64, uint64, bool) { +func (arg *ConstArg) Value() (uint64, uint64) { switch typ := (*arg).Type().(type) { case *IntType: - return arg.Val, 0, typ.BigEndian + return arg.Val, 0 case *ConstType: - return arg.Val, 0, typ.BigEndian + return arg.Val, 0 case *FlagsType: - return arg.Val, 0, typ.BigEndian + return arg.Val, 0 case *LenType: - return arg.Val, 0, typ.BigEndian + return arg.Val, 0 case *CsumType: // Checksums are computed dynamically in executor. - return 0, 0, false + return 0, 0 case *ResourceType: - t := typ.Desc.Type.(*IntType) - return arg.Val, 0, t.BigEndian + return arg.Val, 0 case *ProcType: if arg.Val == typ.Default() { - return 0, 0, false + return 0, 0 } - return typ.ValuesStart + arg.Val, typ.ValuesPerProc, typ.BigEndian + return typ.ValuesStart + arg.Val, typ.ValuesPerProc default: panic(fmt.Sprintf("unknown ConstArg type %#v", typ)) } } -func (arg *ConstArg) ValueForProc(pid uint64) uint64 { - v, stride, be := arg.Value() - v += stride * pid - if be { - switch arg.Size() { - case 2: - v = uint64(swap16(uint16(v))) - case 4: - v = uint64(swap32(uint32(v))) - case 8: - v = swap64(v) - default: - panic(fmt.Sprintf("bad const size %v", arg.Size())) - } - } - return v -} - // Used for PtrType and VmaType. type PointerArg struct { ArgCommon diff --git a/prog/resources.go b/prog/resources.go index bddb158d9..478a6030f 100644 --- a/prog/resources.go +++ b/prog/resources.go @@ -15,17 +15,24 @@ var timespecRes = &ResourceDesc{ } func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall { + + //fmt.Printf("calcResourceCtors: kind=%+v\n", kind) + // Find calls that produce the necessary resources. var metas []*Syscall for _, meta := range target.Syscalls { // Recurse into arguments to see if there is an out/inout arg of necessary type. ok := false + //if meta.Name != "pipe$9p" { continue } + //fmt.Printf("found pipe$9p\n") + ForeachType(meta, func(typ Type) { if ok { return } switch typ1 := typ.(type) { case *ResourceType: + //fmt.Printf(" output: %+v\n", typ1.Desc.Kind) if typ1.Dir() != DirIn && isCompatibleResourceImpl(kind, typ1.Desc.Kind, precise) { ok = true } @@ -47,7 +54,10 @@ func (target *Target) calcResourceCtors(kind []string, precise bool) []*Syscall func (target *Target) isCompatibleResource(dst, src string) bool { if dst == target.any.res16.TypeName || dst == target.any.res32.TypeName || - dst == target.any.res64.TypeName { + dst == target.any.res64.TypeName || + dst == target.any.resdec.TypeName || + dst == target.any.reshex.TypeName || + dst == target.any.resoct.TypeName { return true } dstRes := target.resourceMap[dst] @@ -65,9 +75,11 @@ func (target *Target) isCompatibleResource(dst, src string) bool { // If precise is true, then it does not allow passing a less specialized resource (e.g. fd) // as a more specialized resource (e.g. socket). Otherwise it does. func isCompatibleResourceImpl(dst, src []string, precise bool) bool { + //fmt.Printf("isCompatibleResourceImpl: %+v/%v vs %+v/%v\n", dst, len(dst), src, len(src)) if len(dst) > len(src) { // dst is more specialized, e.g dst=socket, src=fd. if precise { + //fmt.Printf(" = false1\n") return false } dst = dst[:len(src)] @@ -78,9 +90,11 @@ func isCompatibleResourceImpl(dst, src []string, precise bool) bool { } for i, k := range dst { if k != src[i] { + //fmt.Printf(" = false2\n") return false } } + //fmt.Printf(" = true\n") return true } @@ -127,6 +141,10 @@ func (target *Target) TransitivelyEnabledCalls(enabled map[*Syscall]bool) (map[* inputResources := make(map[*Syscall][]*ResourceDesc) for c := range enabled { inputResources[c] = target.inputResources(c) + + if c.Name == "pipe$9p" { + fmt.Printf("%v: input resource: %+v\n", c.Name, inputResources[c]) + } } for { n := len(supported) diff --git a/prog/types.go b/prog/types.go index 29e0899bf..532716193 100644 --- a/prog/types.go +++ b/prog/types.go @@ -37,6 +37,16 @@ func (dir Dir) String() string { } } +type BinaryFormat int + +const ( + FormatNative BinaryFormat = iota + FormatBigEndian + FormatStrDec + FormatStrHex + FormatStrOct +) + type Type interface { String() string Name() string @@ -46,6 +56,7 @@ type Type interface { Default() uint64 Varlen() bool Size() uint64 + Format() BinaryFormat BitfieldOffset() uint64 BitfieldLength() uint64 BitfieldMiddle() bool // returns true for all but last bitfield in a group @@ -97,6 +108,10 @@ func (t *TypeCommon) Varlen() bool { return t.IsVarlen } +func (t *TypeCommon) Format() BinaryFormat { + return FormatNative +} + func (t *TypeCommon) BitfieldOffset() uint64 { return 0 } @@ -122,7 +137,8 @@ type ResourceDesc struct { type ResourceType struct { TypeCommon - Desc *ResourceDesc + ArgFormat BinaryFormat + Desc *ResourceDesc } func (t *ResourceType) String() string { @@ -137,11 +153,15 @@ func (t *ResourceType) SpecialValues() []uint64 { return t.Desc.Values } +func (t *ResourceType) Format() BinaryFormat { + return t.ArgFormat +} + type IntTypeCommon struct { TypeCommon + ArgFormat BinaryFormat BitfieldOff uint64 BitfieldLen uint64 - BigEndian bool BitfieldMdl bool } @@ -149,6 +169,10 @@ func (t *IntTypeCommon) String() string { return t.Name() } +func (t *IntTypeCommon) Format() BinaryFormat { + return t.ArgFormat +} + func (t *IntTypeCommon) BitfieldOffset() uint64 { return t.BitfieldOff } |
