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 NewUsercorn(exe string, config *models.Config) (models.Usercorn, error) { config = config.Init() f, err := os.Open(exe) if err != nil { return nil, err } defer f.Close() l, err := loader.Load(f) if err == loader.UnknownMagic { f.Seek(0, 0) scanner := bufio.NewScanner(f) if scanner.Scan() { line := scanner.Text() if strings.HasPrefix(line, "#!") && len(line) > 2 { args := strings.Split(line[2:], " ") prefix := append(args[1:], exe) config.PrefixArgs = append(prefix, config.PrefixArgs...) shell := config.PrefixPath(args[0], false) return NewUsercorn(shell, config) } } } if err != nil { return nil, err } u, err := NewUsercornRaw(l, config) if err != nil { return nil, err } exe, _ = filepath.Abs(exe) u.exe = exe u.loader = l // map binary (and interp) into memory u.interpBase, u.entry, u.base, u.binEntry, err = u.mapBinary(f, false, l.Arch()) if err != nil { return nil, err } // find data segment for brk u.brk = 0 segments, err := l.Segments() if err != nil { return nil, err } for _, seg := range segments { if seg.Prot&uc.PROT_WRITE != 0 { addr := u.base + seg.Addr + seg.Size if addr > u.brk { u.brk = addr } } } // TODO: have a "host page size", maybe arch.Align() // TODO: allow setting brk addr for raw Usercorn? mask := uint64(4096 - 1) u.Brk((u.brk + mask) & ^mask) // make sure PC is set to entry point for debuggers u.RegWrite(u.Arch().PC, u.Entry()) return u, nil }