aboutsummaryrefslogtreecommitdiffstats
path: root/prog/encodingc.go
diff options
context:
space:
mode:
authorDmitry Vyukov <dvyukov@google.com>2015-10-12 10:16:57 +0200
committerDmitry Vyukov <dvyukov@google.com>2015-10-12 10:16:57 +0200
commit874c5754bb22dbf77d6b600ff91f0f4f1fc5073a (patch)
tree0075fbd088046ad5c86e6e972235701d68b3ce7c /prog/encodingc.go
initial commit
Diffstat (limited to 'prog/encodingc.go')
-rw-r--r--prog/encodingc.go114
1 files changed, 114 insertions, 0 deletions
diff --git a/prog/encodingc.go b/prog/encodingc.go
new file mode 100644
index 000000000..c84acc918
--- /dev/null
+++ b/prog/encodingc.go
@@ -0,0 +1,114 @@
+// Copyright 2015 syzkaller project authors. All rights reserved.
+// Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file.
+
+package prog
+
+import (
+ "bytes"
+ "fmt"
+ "io"
+ "unsafe"
+
+ "github.com/google/syzkaller/sys"
+)
+
+func (p *Prog) WriteCSource() []byte {
+ exec := p.SerializeForExec()
+ buf := new(bytes.Buffer)
+ writeCSource(buf, exec)
+ return buf.Bytes()
+}
+
+func writeCSource(w io.Writer, exec []byte) {
+ fmt.Fprintf(w, `// autogenerated by syzkaller (http://github.com/google/syzkaller)
+#include <syscall.h>
+#include <string.h>
+#include <stdint.h>
+
+int main()
+{
+`)
+ read := func() uintptr {
+ if len(exec) < 8 {
+ panic("exec program overflow")
+ }
+ v := *(*uint64)(unsafe.Pointer(&exec[0]))
+ exec = exec[8:]
+ return uintptr(v)
+ }
+ resultRef := func() string {
+ arg := read()
+ res := fmt.Sprintf("r%v", arg)
+ if opDiv := read(); opDiv != 0 {
+ res = fmt.Sprintf("%v/%v", res, opDiv)
+ }
+ if opAdd := read(); opAdd != 0 {
+ res = fmt.Sprintf("%v+%v", res, opAdd)
+ }
+ return res
+ }
+ lastCall := 0
+ for n := 0; ; n++ {
+ switch instr := read(); instr {
+ case instrEOF:
+ fmt.Fprintf(w, "\treturn 0;\n}\n")
+ return
+ case instrCopyin:
+ addr := read()
+ typ := read()
+ size := read()
+ switch typ {
+ case execArgConst:
+ arg := read()
+ fmt.Fprintf(w, "\t*(uint%v_t*)0x%x = 0x%x;\n", size*8, addr, arg)
+ case execArgResult:
+ fmt.Fprintf(w, "\t*(uint%v_t*)0x%x = %v;\n", size*8, addr, resultRef())
+ case execArgData:
+ data := exec[:size]
+ exec = exec[(size+7)/8*8:]
+ var esc []byte
+ for _, v := range data {
+ hex := func(v byte) byte {
+ if v < 10 {
+ return '0' + v
+ }
+ return 'a' + v - 10
+ }
+ esc = append(esc, '\\', 'x', hex(v>>4), hex(v<<4>>4))
+ }
+ fmt.Fprintf(w, "\tmemcpy((void*)0x%x, \"%s\", %v);\n", addr, esc, size)
+ default:
+ panic("bad argument type")
+ }
+ case instrCopyout:
+ addr := read()
+ size := read()
+ fmt.Fprintf(w, "\tlong r%v = -1;\n", n)
+ fmt.Fprintf(w, "\tif (r%v != -1)\n", lastCall)
+ fmt.Fprintf(w, "\t\tr%v = *(uint%v_t*)0x%x;\n", n, size*8, addr)
+ default:
+ // Normal syscall.
+ meta := sys.Calls[instr]
+ fmt.Fprintf(w, "\tlong r%v = syscall(SYS_%v", n, meta.CallName)
+ nargs := read()
+ for i := uintptr(0); i < nargs; i++ {
+ typ := read()
+ size := read()
+ _ = size
+ switch typ {
+ case execArgConst:
+ fmt.Fprintf(w, ", 0x%xul", read())
+ case execArgResult:
+ fmt.Fprintf(w, ", %v", resultRef())
+ default:
+ panic("unknown arg type")
+ }
+ }
+ for i := nargs; i < 6; i++ {
+ fmt.Fprintf(w, ", 0")
+ }
+ fmt.Fprintf(w, ");\n")
+ lastCall = n
+ }
+ }
+}