aboutsummaryrefslogtreecommitdiffstats
path: root/prog
diff options
context:
space:
mode:
Diffstat (limited to 'prog')
-rw-r--r--prog/any.go196
-rw-r--r--prog/decodeexec.go9
-rw-r--r--prog/encodingexec.go20
-rw-r--r--prog/encodingexec_test.go2
-rw-r--r--prog/prog.go37
-rw-r--r--prog/resources.go20
-rw-r--r--prog/types.go28
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
}