diff options
| author | Dmitry Vyukov <dvyukov@google.com> | 2018-02-19 19:35:04 +0100 |
|---|---|---|
| committer | Dmitry Vyukov <dvyukov@google.com> | 2018-02-19 21:48:20 +0100 |
| commit | 75a7c5e2d1f09a4a58e7e1f1f4ef0b0f55a33413 (patch) | |
| tree | d44c2457c44b53192005f0b89cd6633a2a2b0ff9 /prog/encoding.go | |
| parent | 90fd6503136121e9494761a460898e83bc0b6b3e (diff) | |
prog: rework address allocation
1. mmap all memory always, without explicit mmap calls in the program.
This makes lots of things much easier and removes lots of code.
Makes mmap not a special syscall and allows to fuzz without mmap enabled.
2. Change address assignment algorithm.
Current algorithm allocates unmapped addresses too frequently
and allows collisions between arguments of a single syscall.
The new algorithm analyzes actual allocations in the program
and places new arguments at unused locations.
Diffstat (limited to 'prog/encoding.go')
| -rw-r--r-- | prog/encoding.go | 129 |
1 files changed, 52 insertions, 77 deletions
diff --git a/prog/encoding.go b/prog/encoding.go index 0261d4772..daa7eb71d 100644 --- a/prog/encoding.go +++ b/prog/encoding.go @@ -46,14 +46,14 @@ func (p *Prog) Serialize() []byte { if i != 0 { fmt.Fprintf(buf, ", ") } - serialize(a, buf, vars, &varSeq) + p.Target.serialize(a, buf, vars, &varSeq) } fmt.Fprintf(buf, ")\n") } return buf.Bytes() } -func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { +func (target *Target) serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { if arg == nil { fmt.Fprintf(buf, "nil") return @@ -67,14 +67,14 @@ func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { case *ConstArg: fmt.Fprintf(buf, "0x%x", a.Val) case *PointerArg: - if a.Res == nil && a.PagesNum == 0 { + if a.IsNull() { fmt.Fprintf(buf, "0x0") break } - fmt.Fprintf(buf, "&%v", serializeAddr(arg)) - if a.Res == nil || !isDefaultArg(a.Res) { + fmt.Fprintf(buf, "&%v", target.serializeAddr(a)) + if a.Res == nil || !target.isDefaultArg(a.Res) { fmt.Fprintf(buf, "=") - serialize(a.Res, buf, vars, varSeq) + target.serialize(a.Res, buf, vars, varSeq) } case *DataArg: if a.Type().Dir() == DirOut { @@ -104,7 +104,7 @@ func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { lastNonDefault := len(a.Inner) - 1 if a.fixedInnerSize() { for ; lastNonDefault >= 0; lastNonDefault-- { - if !isDefaultArg(a.Inner[lastNonDefault]) { + if !target.isDefaultArg(a.Inner[lastNonDefault]) { break } } @@ -117,14 +117,14 @@ func serialize(arg Arg, buf *bytes.Buffer, vars map[Arg]int, varSeq *int) { if i != 0 { fmt.Fprintf(buf, ", ") } - serialize(arg1, buf, vars, varSeq) + target.serialize(arg1, buf, vars, varSeq) } buf.Write([]byte{delims[1]}) case *UnionArg: fmt.Fprintf(buf, "@%v", a.Option.Type().FieldName()) - if !isDefaultArg(a.Option) { + if !target.isDefaultArg(a.Option) { fmt.Fprintf(buf, "=") - serialize(a.Option, buf, vars, varSeq) + target.serialize(a.Option, buf, vars, varSeq) } case *ResultArg: if a.Res == nil { @@ -198,7 +198,7 @@ func (target *Target) Deserialize(data []byte) (prog *Prog, err error) { } if len(c.Args) < len(meta.Args) { for i := len(c.Args); i < len(meta.Args); i++ { - c.Args = append(c.Args, defaultArg(meta.Args[i])) + c.Args = append(c.Args, target.defaultArg(meta.Args[i])) } } if len(c.Args) != len(meta.Args) { @@ -241,10 +241,8 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e arg = MakeConstArg(typ, v) case *ResourceType: arg = MakeResultArg(typ, nil, v) - case *PtrType: - arg = MakePointerArg(typ, 0, 0, 0, nil) - case *VmaType: - arg = MakePointerArg(typ, 0, 0, 0, nil) + case *PtrType, *VmaType: + arg = MakeNullPointerArg(typ) default: return nil, fmt.Errorf("bad const type %+v", typ) } @@ -288,7 +286,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e return nil, fmt.Errorf("& arg is not a pointer: %#v", typ) } p.Parse('&') - page, off, size, err := parseAddr(p, true) + addr, vmaSize, err := target.parseAddr(p) if err != nil { return nil, err } @@ -300,17 +298,13 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e return nil, err } } else { - inner = defaultArg(typ1) + inner = target.defaultArg(typ1) } - arg = MakePointerArg(typ, page, off, size, inner) - case '(': - // This used to parse length of VmaType and return ArgPageSize, which is now removed. - // Leaving this for now for backwards compatibility. - pages, _, _, err := parseAddr(p, false) - if err != nil { - return nil, err + if typ1 != nil { + arg = MakePointerArg(typ, addr, inner) + } else { + arg = MakeVmaPointerArg(typ, addr, vmaSize) } - arg = MakeConstArg(typ, pages*target.PageSize) case '"', '\'': data, err := deserializeData(p) if err != nil { @@ -366,7 +360,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e } p.Parse('}') for len(inner) < len(t1.Fields) { - inner = append(inner, defaultArg(t1.Fields[len(inner)])) + inner = append(inner, target.defaultArg(t1.Fields[len(inner)])) } arg = MakeGroupArg(typ, inner) case '[': @@ -389,7 +383,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e p.Parse(']') if t1.Kind == ArrayRangeLen && t1.RangeBegin == t1.RangeEnd { for uint64(len(inner)) < t1.RangeBegin { - inner = append(inner, defaultArg(t1.Type)) + inner = append(inner, target.defaultArg(t1.Type)) } inner = inner[:t1.RangeBegin] } @@ -420,7 +414,7 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e return nil, err } } else { - opt = defaultArg(optType) + opt = target.defaultArg(optType) } arg = MakeUnionArg(typ, opt) case 'n': @@ -441,58 +435,29 @@ func (target *Target) parseArg(typ Type, p *parser, vars map[string]Arg) (Arg, e const ( encodingAddrBase = 0x7f0000000000 - encodingPageSize = 4 << 10 maxLineLen = 256 << 10 ) -func serializeAddr(arg Arg) string { - var pageIndex, pagesNum uint64 - var pageOffset int - switch a := arg.(type) { - case *PointerArg: - pageIndex = a.PageIndex - pageOffset = a.PageOffset - pagesNum = a.PagesNum - default: - panic("bad addr arg") - } - page := pageIndex * encodingPageSize - page += encodingAddrBase - soff := "" - if off := pageOffset; off != 0 { - sign := "+" - if off < 0 { - sign = "-" - off = -off - page += encodingPageSize - } - soff = fmt.Sprintf("%v0x%x", sign, off) - } +func (target *Target) serializeAddr(arg *PointerArg) string { ssize := "" - if size := pagesNum; size != 0 { - size *= encodingPageSize - ssize = fmt.Sprintf("/0x%x", size) + if arg.VmaSize != 0 { + ssize = fmt.Sprintf("/0x%x", arg.VmaSize) } - return fmt.Sprintf("(0x%x%v%v)", page, soff, ssize) + return fmt.Sprintf("(0x%x%v)", encodingAddrBase+arg.Address, ssize) } -func parseAddr(p *parser, base bool) (uint64, int, uint64, error) { +func (target *Target) parseAddr(p *parser) (uint64, uint64, error) { p.Parse('(') pstr := p.Ident() - page, err := strconv.ParseUint(pstr, 0, 64) + addr, err := strconv.ParseUint(pstr, 0, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse addr page: '%v'", pstr) - } - if page%encodingPageSize != 0 { - return 0, 0, 0, fmt.Errorf("address base is not page size aligned: '%v'", pstr) + return 0, 0, fmt.Errorf("failed to parse addr: %q", pstr) } - if base { - if page < encodingAddrBase { - return 0, 0, 0, fmt.Errorf("address without base offset: '%v'", pstr) - } - page -= encodingAddrBase + if addr < encodingAddrBase { + return 0, 0, fmt.Errorf("address without base offset: %q", pstr) } - var off int64 + addr -= encodingAddrBase + // This is not used anymore, but left here to parse old programs. if p.Char() == '+' || p.Char() == '-' { minus := false if p.Char() == '-' { @@ -502,28 +467,38 @@ func parseAddr(p *parser, base bool) (uint64, int, uint64, error) { p.Parse('+') } ostr := p.Ident() - off, err = strconv.ParseInt(ostr, 0, 64) + off, err := strconv.ParseUint(ostr, 0, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse addr offset: '%v'", ostr) + return 0, 0, fmt.Errorf("failed to parse addr offset: %q", ostr) } if minus { - page -= encodingPageSize off = -off } + addr += off } - var size uint64 + maxMem := target.NumPages * target.PageSize + var vmaSize uint64 if p.Char() == '/' { p.Parse('/') pstr := p.Ident() - size, err = strconv.ParseUint(pstr, 0, 64) + size, err := strconv.ParseUint(pstr, 0, 64) if err != nil { - return 0, 0, 0, fmt.Errorf("failed to parse addr size: '%v'", pstr) + return 0, 0, fmt.Errorf("failed to parse addr size: %q", pstr) + } + addr = addr & ^(target.PageSize - 1) + vmaSize = (size + target.PageSize - 1) & ^(target.PageSize - 1) + if vmaSize == 0 { + vmaSize = target.PageSize + } + if vmaSize > maxMem { + vmaSize = maxMem + } + if addr > maxMem-vmaSize { + addr = maxMem - vmaSize } } p.Parse(')') - page /= encodingPageSize - size /= encodingPageSize - return page, int(off), size, nil + return addr, vmaSize, nil } func serializeData(buf *bytes.Buffer, data []byte) { |
