func NewUsercornRaw(l models.Loader, config *models.Config) (*Usercorn, error) { config = config.Init() a, OS, err := arch.GetArch(l.Arch(), l.OS()) if err != nil { return nil, err } unicorn, err := NewUnicorn(a, OS, l.ByteOrder()) if err != nil { return nil, err } u := &Usercorn{ Unicorn: unicorn, traceMatching: true, config: config, loader: l, exit: 0xffffffffffffffff, } if config.Output == os.Stderr && readline.IsTerminal(int(os.Stderr.Fd())) { config.Color = true } u.memio = memio.NewMemIO( // ReadAt() callback func(p []byte, addr uint64) (int, error) { if err := u.MemReadInto(p, addr); err != nil { return 0, err } if u.config.TraceMemBatch { u.memlog.UpdateBytes(addr, p, false) } return len(p), nil }, // WriteAt() callback func(p []byte, addr uint64) (int, error) { if err := u.MemWrite(addr, p); err != nil { return 0, err } if u.config.TraceMemBatch { u.memlog.UpdateBytes(addr, p, true) } return len(p), nil }, ) // load kernels // the array cast is a trick to work around circular imports if OS.Kernels != nil { kernelI := OS.Kernels(u) kernels := make([]co.Kernel, len(kernelI)) for i, k := range kernelI { kernels[i] = k.(co.Kernel) } u.kernels = kernels } u.status = models.StatusDiff{U: u} if u.config.LoopCollapse > 0 { u.blockloop = models.NewLoopDetect(u.config.LoopCollapse) } // TODO: if we error, should close Usercorn/Unicorn instance? // GC might take its time if err := u.mapStack(); err != nil { return nil, err } if err := u.addHooks(); err != nil { return nil, err } return u, nil }
func (u *Usercorn) Run(args []string, env []string) error { if u.LoopCollapse > 0 { u.blockloop = models.NewLoopDetect(u.LoopCollapse) } if err := u.addHooks(); err != nil { return err } if err := u.setupStack(); err != nil { return err } if u.os.Init != nil { if err := u.os.Init(u, args, env); err != nil { return err } } if u.Verbose { fmt.Fprintf(os.Stderr, "[entry @ 0x%x]\n", u.entry) dis, err := u.Disas(u.entry, 64) if err != nil { fmt.Fprintln(os.Stderr, err) } else { fmt.Fprintln(os.Stderr, dis) } sp, err := u.RegRead(u.arch.SP) if err != nil { return err } buf := make([]byte, u.StackBase+STACK_SIZE-sp) if err := u.MemReadInto(buf, sp); err != nil { return err } fmt.Fprintf(os.Stderr, "[stack @ 0x%x]\n", sp) for _, line := range models.HexDump(sp, buf[:], u.arch.Bits) { fmt.Fprintf(os.Stderr, "%s\n", line) } } if u.Verbose || u.TraceReg { u.status.Changes().Print("", true, false) } if u.Verbose { fmt.Fprintln(os.Stderr, "=====================================") fmt.Fprintln(os.Stderr, "==== Program output begins here. ====") fmt.Fprintln(os.Stderr, "=====================================") } if u.TraceReg || u.TraceExec { sp, _ := u.RegRead(u.arch.SP) sym, _ := u.Symbolicate(u.entry) u.stacktrace.Update(u.entry, sp, sym) } if u.TraceMemBatch { u.memlog = *models.NewMemLog(u.ByteOrder()) } err := u.Unicorn.Start(u.entry, 0xffffffffffffffff) if u.TraceMemBatch && !u.memlog.Empty() { u.memlog.Print("", u.arch.Bits) u.memlog.Reset() } if err != nil { fmt.Fprintln(os.Stderr, "Registers:") u.status.Changes().Print("", true, false) fmt.Fprintln(os.Stderr, "Stacktrace:") u.stacktrace.Print(u) } if err == nil && u.exitStatus != nil { err = u.exitStatus } return err }