예제 #1
0
func (a *Arg) serialize(buf io.Writer, vars map[*Arg]int, varSeq *int) {
	if a == nil {
		fmt.Fprintf(buf, "nil")
		return
	}
	if len(a.Uses) != 0 {
		fmt.Fprintf(buf, "<r%v=>", *varSeq)
		vars[a] = *varSeq
		*varSeq++
	}
	switch a.Kind {
	case ArgConst:
		fmt.Fprintf(buf, "0x%x", a.Val)
	case ArgResult:
		id, ok := vars[a.Res]
		if !ok {
			panic("no result")
		}
		fmt.Fprintf(buf, "r%v", id)
		if a.OpDiv != 0 {
			fmt.Fprintf(buf, "/%v", a.OpDiv)
		}
		if a.OpAdd != 0 {
			fmt.Fprintf(buf, "+%v", a.OpAdd)
		}
	case ArgPointer:
		fmt.Fprintf(buf, "&%v=", serializeAddr(a, true))
		a.Res.serialize(buf, vars, varSeq)
	case ArgPageSize:
		fmt.Fprintf(buf, "%v", serializeAddr(a, false))
	case ArgData:
		fmt.Fprintf(buf, "\"%v\"", hex.EncodeToString(a.Data))
	case ArgGroup:
		var delims []byte
		switch a.Type.(type) {
		case *sys.StructType:
			delims = []byte{'{', '}'}
		case sys.ArrayType:
			delims = []byte{'[', ']'}
		default:
			panic("unknown group type")
		}
		buf.Write([]byte{delims[0]})
		for i, a1 := range a.Inner {
			if a1 != nil && sys.IsPad(a1.Type) {
				continue
			}
			if i != 0 {
				fmt.Fprintf(buf, ", ")
			}
			a1.serialize(buf, vars, varSeq)
		}
		buf.Write([]byte{delims[1]})
	case ArgUnion:
		fmt.Fprintf(buf, "@%v=", a.OptionType.Name())
		a.Option.serialize(buf, vars, varSeq)
	default:
		panic("unknown arg kind")
	}
}
예제 #2
0
func (p *Prog) Serialize() []byte {
	/*
		if err := p.validate(); err != nil {
			panic("serializing invalid program")
		}
	*/
	buf := new(bytes.Buffer)
	vars := make(map[*Arg]int)
	varSeq := 0
	for _, c := range p.Calls {
		if len(c.Ret.Uses) != 0 {
			fmt.Fprintf(buf, "r%v = ", varSeq)
			vars[c.Ret] = varSeq
			varSeq++
		}
		fmt.Fprintf(buf, "%v(", c.Meta.Name)
		for i, a := range c.Args {
			if sys.IsPad(a.Type) {
				continue
			}
			if i != 0 {
				fmt.Fprintf(buf, ", ")
			}
			a.serialize(buf, vars, &varSeq)
		}
		fmt.Fprintf(buf, ")\n")
	}
	return buf.Bytes()
}
예제 #3
0
func assignSizes(args []*Arg) {
	// Create a map of args and calculate size of the whole struct.
	argsMap := make(map[string]*Arg)
	var parentSize uintptr
	for _, arg := range args {
		parentSize += arg.Size()
		if sys.IsPad(arg.Type) {
			continue
		}
		argsMap[arg.Type.Name()] = arg
	}

	// Fill in size arguments.
	for _, arg := range args {
		if arg = arg.InnerArg(); arg == nil {
			continue // Pointer to optional len field, no need to fill in value.
		}
		if typ, ok := arg.Type.(*sys.LenType); ok {
			if typ.Buf == "parent" {
				arg.Val = parentSize
				continue
			}

			buf, ok := argsMap[typ.Buf]
			if !ok {
				panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v",
					typ.Name(), typ.Buf, argsMap))
			}

			*arg = *generateSize(buf.InnerArg(), typ)
		}
	}
}
예제 #4
0
func assignSizes(types []sys.Type, args []*Arg) {
	argsMap := make(map[string]*Arg)
	typesMap := make(map[string]sys.Type)

	// Create a map of args and types.
	for i, typ := range types {
		if sys.IsPad(typ) {
			continue
		}
		if typ.Name() == "parent" {
			panic("parent is reserved len name")
		}

		innerArg := args[i].InnerArg(typ)
		innerType := typ.InnerType()

		if _, ok := argsMap[typ.Name()]; ok {
			panic(fmt.Sprintf("mutiple args with the same name '%v', types: %+v, args: %+v", typ.Name(), types, args))
		}
		argsMap[typ.Name()] = innerArg
		typesMap[typ.Name()] = innerType
	}

	// Calculate size of the whole struct.
	var parentSize uintptr
	for i, typ := range types {
		parentSize += args[i].Size(typ)
	}

	// Fill in size arguments.
	for i, typ := range types {
		if lenType, ok := typ.InnerType().(sys.LenType); ok {
			lenArg := args[i].InnerArg(typ)
			if lenArg == nil {
				// Pointer to optional len field, no need to fill in value.
				continue
			}

			if lenType.Buf == "parent" {
				*lenArg = *constArg(parentSize)
				continue
			}

			arg, ok := argsMap[lenType.Buf]
			if !ok {
				panic(fmt.Sprintf("len field '%v' references non existent field '%v', argsMap: %+v, typesMap: %+v",
					lenType.Name(), lenType.Buf, argsMap, typesMap))
			}
			typ := typesMap[lenType.Buf]

			*lenArg = *generateSize(typ, arg, lenType)
		}
	}
}
예제 #5
0
func (p *Prog) SerializeForExec(pid int) []byte {
	if err := p.validate(); err != nil {
		panic(fmt.Errorf("serializing invalid program: %v", err))
	}
	var instrSeq uintptr
	w := &execContext{args: make(map[*Arg]*argInfo)}
	for _, c := range p.Calls {
		// Calculate arg offsets within structs.
		foreachArg(c, func(arg, base *Arg, _ *[]*Arg) {
			if base == nil || arg.Kind == ArgGroup || arg.Kind == ArgUnion {
				return
			}
			if w.args[base] == nil {
				w.args[base] = &argInfo{}
			}
			w.args[arg] = &argInfo{Offset: w.args[base].CurSize}
			w.args[base].CurSize += arg.Size()
		})
		// Generate copyin instructions that fill in data into pointer arguments.
		foreachArg(c, func(arg, _ *Arg, _ *[]*Arg) {
			if arg.Kind == ArgPointer && arg.Res != nil {
				var rec func(*Arg)
				rec = func(arg1 *Arg) {
					if arg1.Kind == ArgGroup {
						for _, arg2 := range arg1.Inner {
							rec(arg2)
						}
						return
					}
					if arg1.Kind == ArgUnion {
						rec(arg1.Option)
						return
					}
					if sys.IsPad(arg1.Type) {
						return
					}
					if arg1.Kind == ArgData && len(arg1.Data) == 0 {
						return
					}
					if arg1.Type.Dir() != sys.DirOut {
						w.write(ExecInstrCopyin)
						w.write(physicalAddr(arg) + w.args[arg1].Offset)
						w.writeArg(arg1, pid)
						instrSeq++
					}
				}
				rec(arg.Res)
			}
		})
		// Generate the call itself.
		w.write(uintptr(c.Meta.ID))
		w.write(uintptr(len(c.Args)))
		for _, arg := range c.Args {
			w.writeArg(arg, pid)
		}
		w.args[c.Ret] = &argInfo{Idx: instrSeq}
		instrSeq++
		// Generate copyout instructions that persist interesting return values.
		foreachArg(c, func(arg, base *Arg, _ *[]*Arg) {
			if len(arg.Uses) == 0 {
				return
			}
			switch arg.Kind {
			case ArgReturn:
				// Idx is already assigned above.
			case ArgConst, ArgResult:
				// Create a separate copyout instruction that has own Idx.
				if base.Kind != ArgPointer {
					panic("arg base is not a pointer")
				}
				info := w.args[arg]
				info.Idx = instrSeq
				instrSeq++
				w.write(ExecInstrCopyout)
				w.write(physicalAddr(base) + info.Offset)
				w.write(arg.Size())
			default:
				panic("bad arg kind in copyout")
			}
		})
	}
	w.write(ExecInstrEOF)
	return w.buf
}
예제 #6
0
func parseArg(typ sys.Type, p *parser, vars map[string]*Arg) (*Arg, error) {
	r := ""
	if p.Char() == '<' {
		p.Parse('<')
		r = p.Ident()
		p.Parse('=')
		p.Parse('>')
	}
	var arg *Arg
	switch p.Char() {
	case '0':
		val := p.Ident()
		v, err := strconv.ParseUint(val, 0, 64)
		if err != nil {
			return nil, fmt.Errorf("wrong arg value '%v': %v", val, err)
		}
		arg = constArg(uintptr(v))
	case 'r':
		id := p.Ident()
		v, ok := vars[id]
		if !ok || v == nil {
			return nil, fmt.Errorf("result %v references unknown variable (vars=%+v)", id, vars)
		}
		arg = resultArg(v)
		if p.Char() == '/' {
			p.Parse('/')
			op := p.Ident()
			v, err := strconv.ParseUint(op, 0, 64)
			if err != nil {
				return nil, fmt.Errorf("wrong result div op: '%v'", op)
			}
			arg.OpDiv = uintptr(v)
		}
		if p.Char() == '+' {
			p.Parse('+')
			op := p.Ident()
			v, err := strconv.ParseUint(op, 0, 64)
			if err != nil {
				return nil, fmt.Errorf("wrong result add op: '%v'", op)
			}
			arg.OpAdd = uintptr(v)
		}
	case '&':
		var typ1 sys.Type
		switch t1 := typ.(type) {
		case sys.PtrType:
			typ1 = t1.Type
		case sys.VmaType:
		default:
			return nil, fmt.Errorf("& arg is not a pointer: %#v", typ)
		}
		p.Parse('&')
		page, off, size, err := parseAddr(p, true)
		if err != nil {
			return nil, err
		}
		p.Parse('=')
		inner, err := parseArg(typ1, p, vars)
		if err != nil {
			return nil, err
		}
		arg = pointerArg(page, off, size, inner)
	case '(':
		page, off, _, err := parseAddr(p, false)
		if err != nil {
			return nil, err
		}
		arg = pageSizeArg(page, off)
	case '"':
		p.Parse('"')
		val := ""
		if p.Char() != '"' {
			val = p.Ident()
		}
		p.Parse('"')
		data, err := hex.DecodeString(val)
		if err != nil {
			return nil, fmt.Errorf("data arg has bad value '%v'", val)
		}
		arg = dataArg(data)
	case '{':
		t1, ok := typ.(*sys.StructType)
		if !ok {
			return nil, fmt.Errorf("'{' arg is not a struct: %#v", typ)
		}
		p.Parse('{')
		var inner []*Arg
		for i := 0; p.Char() != '}'; i++ {
			if i >= len(t1.Fields) {
				return nil, fmt.Errorf("wrong struct arg count: %v, want %v", i+1, len(t1.Fields))
			}
			fld := t1.Fields[i]
			if sys.IsPad(fld) {
				inner = append(inner, constArg(0))
			} else {
				arg, err := parseArg(fld, p, vars)
				if err != nil {
					return nil, err
				}
				inner = append(inner, arg)
				if p.Char() != '}' {
					p.Parse(',')
				}
			}
		}
		p.Parse('}')
		if sys.IsPad(t1.Fields[len(t1.Fields)-1]) {
			inner = append(inner, constArg(0))
		}
		arg = groupArg(inner)
	case '[':
		t1, ok := typ.(sys.ArrayType)
		if !ok {
			return nil, fmt.Errorf("'[' arg is not an array: %#v", typ)
		}
		p.Parse('[')
		var inner []*Arg
		for i := 0; p.Char() != ']'; i++ {
			arg, err := parseArg(t1.Type, p, vars)
			if err != nil {
				return nil, err
			}
			inner = append(inner, arg)
			if p.Char() != ']' {
				p.Parse(',')
			}
		}
		p.Parse(']')
		arg = groupArg(inner)
	case '@':
		t1, ok := typ.(*sys.UnionType)
		if !ok {
			return nil, fmt.Errorf("'@' arg is not a union: %#v", typ)
		}
		p.Parse('@')
		name := p.Ident()
		p.Parse('=')
		var optType sys.Type
		for _, t2 := range t1.Options {
			if name == t2.Name() {
				optType = t2
				break
			}
		}
		if optType == nil {
			return nil, fmt.Errorf("union arg %v has unknown option: %v", typ.Name(), name)
		}
		opt, err := parseArg(optType, p, vars)
		if err != nil {
			return nil, err
		}
		arg = unionArg(opt, optType)
	case 'n':
		p.Parse('n')
		p.Parse('i')
		p.Parse('l')
		if r != "" {
			return nil, fmt.Errorf("named nil argument")
		}
	default:
		return nil, fmt.Errorf("failed to parse argument at %v (line #%v/%v: %v)", int(p.Char()), p.l, p.i, p.s)
	}
	if r != "" {
		vars[r] = arg
	}
	return arg, nil
}
예제 #7
0
func Deserialize(data []byte) (prog *Prog, err error) {
	prog = new(Prog)
	p := &parser{r: bufio.NewScanner(bytes.NewReader(data))}
	vars := make(map[string]*Arg)
	for p.Scan() {
		if p.EOF() || p.Char() == '#' {
			continue
		}
		name := p.Ident()
		r := ""
		if p.Char() == '=' {
			r = name
			p.Parse('=')
			name = p.Ident()

		}
		meta := sys.CallMap[name]
		if meta == nil {
			return nil, fmt.Errorf("unknown syscall %v", name)
		}
		c := &Call{Meta: meta}
		prog.Calls = append(prog.Calls, c)
		p.Parse('(')
		for i := 0; p.Char() != ')'; i++ {
			if i >= len(meta.Args) {
				return nil, fmt.Errorf("wrong call arg count: %v, want %v", i+1, len(meta.Args))
			}
			typ := meta.Args[i]
			if sys.IsPad(typ) {
				return nil, fmt.Errorf("padding in syscall %v arguments", name)
			}
			arg, err := parseArg(typ, p, vars)
			if err != nil {
				return nil, err
			}
			c.Args = append(c.Args, arg)
			if p.Char() != ')' {
				p.Parse(',')
			}
		}
		p.Parse(')')
		if !p.EOF() {
			return nil, fmt.Errorf("tailing data (line #%v)", p.l)
		}
		if len(c.Args) != len(meta.Args) {
			return nil, fmt.Errorf("wrong call arg count: %v, want %v", len(c.Args), len(meta.Args))
		}
		if err := assignTypeAndDir(c); err != nil {
			return nil, err
		}
		if r != "" {
			vars[r] = c.Ret
		}
	}
	if p.Err() != nil {
		return nil, err
	}
	if err := prog.validate(); err != nil {
		return nil, err
	}
	return
}