All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.github.unidbg.ios.DarwinSyscallHandler Maven / Gradle / Ivy

The newest version!
package com.github.unidbg.ios;

import com.github.unidbg.AbstractEmulator;
import com.github.unidbg.Emulator;
import com.github.unidbg.arm.Cpsr;
import com.github.unidbg.arm.context.RegisterContext;
import com.github.unidbg.file.FileResult;
import com.github.unidbg.file.ios.DarwinFileIO;
import com.github.unidbg.file.ios.IOConstants;
import com.github.unidbg.ios.kevent.KEvent;
import com.github.unidbg.ios.kevent.KEvent64;
import com.github.unidbg.ios.kevent.KEventWaiter;
import com.github.unidbg.ios.signal.SigAction;
import com.github.unidbg.ios.signal.SignalTask;
import com.github.unidbg.ios.struct.VMStatistics;
import com.github.unidbg.ios.struct.kernel.HostStatisticsReply;
import com.github.unidbg.ios.struct.kernel.HostStatisticsRequest;
import com.github.unidbg.ios.struct.kernel.MachMsgHeader;
import com.github.unidbg.ios.struct.kernel.Pthread;
import com.github.unidbg.ios.struct.kernel.StatFS;
import com.github.unidbg.ios.struct.kernel.VprocMigLookupData;
import com.github.unidbg.ios.struct.kernel.VprocMigLookupReply;
import com.github.unidbg.ios.struct.kernel.VprocMigLookupRequest;
import com.github.unidbg.ios.thread.BsdThread;
import com.github.unidbg.ios.thread.SemWaiter;
import com.github.unidbg.memory.MemoryBlock;
import com.github.unidbg.pointer.UnidbgPointer;
import com.github.unidbg.pointer.UnidbgStructure;
import com.github.unidbg.signal.SigSet;
import com.github.unidbg.signal.SignalOps;
import com.github.unidbg.signal.UnixSigSet;
import com.github.unidbg.spi.SyscallHandler;
import com.github.unidbg.thread.RunnableTask;
import com.github.unidbg.thread.Task;
import com.github.unidbg.thread.ThreadContextSwitchException;
import com.github.unidbg.thread.ThreadDispatcher;
import com.github.unidbg.thread.ThreadTask;
import com.github.unidbg.unix.UnixEmulator;
import com.github.unidbg.unix.UnixSyscallHandler;
import com.github.unidbg.unix.struct.TimeSpec;
import com.sun.jna.Pointer;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;

import java.util.Arrays;
import java.util.HashMap;
import java.util.Map;

public abstract class DarwinSyscallHandler extends UnixSyscallHandler implements SyscallHandler, DarwinSyscall  {

    private static final Log log = LogFactory.getLog(DarwinSyscallHandler.class);

    final long bootTime = System.currentTimeMillis();

    /**
     * sysctl hw.machine
     */
    protected String getHwMachine() {
        return "iPhone6,2";
    }

    /**
     * sysctl hw.ncpu
     */
    protected int getHwNcpu() {
        return 2;
    }

    /**
     * sysctl kern.boottime
     */
    protected abstract void fillKernelBootTime(Pointer buffer);

    protected final void exit(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int status = context.getIntArg(0);
        if (status != 0 || LogFactory.getLog(AbstractEmulator.class).isDebugEnabled()) {
            emulator.attach().debug();
        }
        System.exit(status);
    }

    protected int fork(Emulator emulator) {
        log.info("fork");
        if (emulator.is64Bit()) {
            Cpsr.getArm64(emulator.getBackend()).setCarry(true);
        } else {
            Cpsr.getArm(emulator.getBackend()).setCarry(true);
        }
        return UnixEmulator.ENOSYS;
    }

    protected final int open_NOCANCEL(Emulator emulator, int offset) {
        RegisterContext context = emulator.getContext();
        Pointer pathname_p = context.getPointerArg(offset);
        int oflags = context.getIntArg(offset + 1);
        int mode = context.getIntArg(offset + 2);
        String pathname = pathname_p.getString(0);
        int fd = open(emulator, pathname, oflags);
        if (log.isDebugEnabled()) {
            log.debug("open_NOCANCEL pathname=" + pathname + ", oflags=0x" + Integer.toHexString(oflags) + ", mode=" + Integer.toHexString(mode) + ", fd=" + fd + ", LR=" + context.getLRPointer());
        }
        if (fd == -1) {
            if (emulator.is64Bit()) {
                Cpsr.getArm64(emulator.getBackend()).setCarry(true);
            } else {
                Cpsr.getArm(emulator.getBackend()).setCarry(true);
            }
            return emulator.getMemory().getLastErrno();
        } else {
            return fd;
        }
    }

    protected int getfsstat64(Emulator emulator, int off) {
        RegisterContext context = emulator.getContext();
        UnidbgPointer buf = context.getPointerArg(off);
        int bufSize = context.getIntArg(off + 1);
        int flags = context.getIntArg(off + 2);
        if (log.isDebugEnabled()) {
            log.debug("getfsstat64 buf=" + buf + ", bufSize=" + bufSize + ", flags=0x" + Integer.toHexString(flags));
        }

        final int mountedFsSize = 2;
        if (buf == null) {
            return mountedFsSize;
        }

        buf.setSize(bufSize);
        Pointer pointer = buf;
        int statfs_size = UnidbgStructure.calculateSize(StatFS.class);

        if (bufSize >= statfs_size) {
            StatFS statFS = new StatFS(pointer);
            statFS.f_bsize = 0x1000;
            statFS.f_iosize = 0x100000;
            statFS.f_blocks = 507876;
            statFS.f_bfree = 76016;
            statFS.f_bavail = 70938;
            statFS.f_files = 507874;
            statFS.f_ffree = 70938;
            statFS.f_fsid = 0x1101000002L;
            statFS.f_owner = 0;
            statFS.f_type = 0x11;
            statFS.f_flags = 0x480d000;
            statFS.f_fssubtype = 0x3;
            statFS.setFsTypeName("hfs");
            statFS.setMntOnName("/");
            statFS.setMntFromName("/dev/disk0s1s1");
            statFS.pack();

            bufSize -= statfs_size;
            pointer = pointer.share(statfs_size);
        }

        if (bufSize >= statfs_size) {
            StatFS statFS = new StatFS(pointer);
            statFS.f_bsize = 0x1000;
            statFS.f_iosize = 0x100000;
            statFS.f_blocks = 3362844;
            statFS.f_bfree = 3000788;
            statFS.f_bavail = 3000788;
            statFS.f_files = 3362842;
            statFS.f_ffree = 3000788;
            statFS.f_fsid = 0x1101000003L;
            statFS.f_owner = 0;
            statFS.f_type = 0x11;
            statFS.f_flags = 0x14809080;
            statFS.f_fssubtype = 0x3;
            statFS.setFsTypeName("hfs");
            statFS.setMntOnName("/private/var");
            statFS.setMntFromName("/dev/disk0s1s2");
            statFS.pack();
        }
        if (verbose) {
            System.out.printf("getfsstat from %s%n", emulator.getContext().getLRPointer());
        }

        return mountedFsSize;
    }

    protected final int access(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer pathname = context.getPointerArg(0);
        int mode = context.getIntArg(1);
        String path = pathname.getString(0);
        if (log.isDebugEnabled()) {
            log.debug("access pathname=" + path + ", mode=" + mode);
        }
        return faccessat(emulator, path, mode);
    }

    protected final int faccessat(Emulator emulator, String pathname, int mode) {
        FileResult result = resolve(emulator, pathname, IOConstants.O_RDONLY);
        if (result != null && result.isSuccess()) {
            if (verbose) {
                System.out.printf("File access '%s' with mode=0x%x from %s%n", pathname, mode, emulator.getContext().getLRPointer());
            }
            return 0;
        }

        emulator.getMemory().setErrno(result != null ? result.errno : UnixEmulator.ENOENT);
        if (verbose) {
            System.out.printf("File access failed '%s' with mode=0x%x from %s%n", pathname, mode, emulator.getContext().getLRPointer());
        }
        return -1;
    }

    protected final int flistxattr(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int fd = context.getIntArg(0);
        UnidbgPointer namebuf = context.getPointerArg(1);
        int size = context.getIntArg(2);
        int options = context.getIntArg(3);
        DarwinFileIO io = fdMap.get(fd);
        if (namebuf != null) {
            namebuf.setSize(size);
        }
        if (io != null) {
            int ret = io.listxattr(namebuf, size, options);
            if (ret == -1) {
                log.info("flistxattr fd=" + fd + ", namebuf=" + namebuf + ", size=" + size + ", options=" + options + ", LR=" + context.getLRPointer());
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("flistxattr fd=" + fd + ", namebuf=" + namebuf + ", size=" + size + ", options=" + options + ", LR=" + context.getLRPointer());
                }
            }
            return ret;
        } else {
            log.info("flistxattr fd=" + fd + ", namebuf=" + namebuf + ", size=" + size + ", options=" + options + ", LR=" + context.getLRPointer());
            emulator.getMemory().setErrno(UnixEmulator.ENOENT);
            return -1;
        }
    }

    protected final int listxattr(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer path = context.getPointerArg(0);
        UnidbgPointer namebuf = context.getPointerArg(1);
        int size = context.getIntArg(2);
        int options = context.getIntArg(3);
        String pathname = path.getString(0);
        FileResult result = resolve(emulator, pathname, IOConstants.O_RDONLY);
        if (namebuf != null) {
            namebuf.setSize(size);
        }
        if (result.isSuccess()) {
            int ret = result.io.listxattr(namebuf, size, options);
            if (ret == -1) {
                log.info("listxattr path=" + pathname + ", namebuf=" + namebuf + ", size=" + size + ", options=" + options + ", LR=" + context.getLRPointer());
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("listxattr path=" + pathname + ", namebuf=" + namebuf + ", size=" + size + ", options=" + options + ", LR=" + context.getLRPointer());
                }
            }
            return ret;
        } else {
            log.info("listxattr path=" + pathname + ", namebuf=" + namebuf + ", size=" + size + ", options=" + options + ", LR=" + context.getLRPointer());
            emulator.getMemory().setErrno(UnixEmulator.ENOENT);
            return -1;
        }
    }

    protected final int fchmodx_np(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int fd = context.getIntArg(0);
        int fsowner = context.getIntArg(1);
        int fsgrp = context.getIntArg(2);
        int fsmode = context.getIntArg(3);
        int fsacl = context.getIntArg(4);
        DarwinFileIO io = fdMap.get(fd);
        log.debug("fchmodx_np fd=" + fd + ", fsowner=" + fsowner + ", fsgrp=" + fsgrp + ", fsmode=0x" + Integer.toHexString(fsmode) + ", fsacl=" + fsacl + ", io=" + io);
        if (io != null) {
            int ret = io.chmod(fsmode);
            if (ret == -1) {
                log.info("fchmodx_np fd=" + fd + ", fsmode=0x" + Integer.toHexString(fsmode));
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("fchmodx_np fd=" + fd + ", fsmode=0x" + Integer.toHexString(fsmode));
                }
            }
            return ret;
        } else {
            log.info("fchmodx_np fd=" + fd + ", fsmode=0x" + Integer.toHexString(fsmode));
            Cpsr.getArm64(emulator.getBackend()).setCarry(true);
            return UnixEmulator.ENOENT;
        }
    }

    protected final int chmodx_np(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer path = context.getPointerArg(0);
        int fsowner = context.getIntArg(1);
        int fsgrp = context.getIntArg(2);
        int fsmode = context.getIntArg(3);
        int fsacl = context.getIntArg(4);
        String pathname = path.getString(0);
        log.debug("chmodx_np pathname=" + pathname + ", fsowner=" + fsowner + ", fsgrp=" + fsgrp + ", fsmode=0x" + Integer.toHexString(fsmode) + ", fsacl=" + fsacl);
        FileResult result = resolve(emulator, pathname, IOConstants.O_RDONLY);
        if (result.isSuccess()) {
            int ret = result.io.chmod(fsmode);
            if (ret == -1) {
                log.info("chmodx_np path=" + pathname + ", fsmode=0x" + Integer.toHexString(fsmode));
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("chmodx_np path=" + pathname + ", fsmode=0x" + Integer.toHexString(fsmode));
                }
            }
            return ret;
        } else {
            log.info("chmodx_np path=" + pathname + ", fsmode=0x" + Integer.toHexString(fsmode));
            Cpsr.getArm64(emulator.getBackend()).setCarry(true);
            return UnixEmulator.ENOENT;
        }
    }

    protected int fchmod(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int fd = context.getIntArg(0);
        int mode = context.getIntArg(1) & 0xffff;
        DarwinFileIO io = fdMap.get(fd);
        if (io != null) {
            int ret = io.chmod(mode);
            if (ret == -1) {
                log.info("fchmod fd=" + fd + ", mode=0x" + Integer.toHexString(mode));
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("fchmod fd=" + fd + ", mode=0x" + Integer.toHexString(mode));
                }
            }
            return ret;
        } else {
            log.info("fchmod fd=" + fd + ", mode=0x" + Integer.toHexString(mode));
            Cpsr.getArm64(emulator.getBackend()).setCarry(true);
            return UnixEmulator.ENOENT;
        }
    }

    protected final int select(int nfds, Pointer checkfds, Pointer clearfds, boolean checkRead) {
        int count = 0;
        for (int i = 0; i < nfds; i++) {
            int mask = checkfds.getInt(i / 32);
            if (((mask >> i) & 1) == 1) {
                DarwinFileIO io = fdMap.get(i);
                if (!checkRead || io.canRead()) {
                    count++;
                } else {
                    mask &= ~(1 << i);
                    checkfds.setInt(i / 32, mask);
                }
            }
        }
        if (count > 0) {
            if (clearfds != null) {
                for (int i = 0; i < nfds; i++) {
                    clearfds.setInt(i / 32, 0);
                }
            }
        }
        return count;
    }

    protected final int chmod(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer path = context.getPointerArg(0);
        int mode = context.getIntArg(1) & 0xffff;
        String pathname = path.getString(0);
        FileResult result = resolve(emulator, pathname, IOConstants.O_RDONLY);
        if (result.isSuccess()) {
            int ret = result.io.chmod(mode);
            if (ret == -1) {
                log.info("chmod path=" + pathname + ", mode=0x" + Integer.toHexString(mode));
            } else {
                if (log.isDebugEnabled()) {
                    log.debug("chmod path=" + pathname + ", mode=0x" + Integer.toHexString(mode));
                }
            }
            return ret;
        } else {
            log.info("chmod path=" + pathname + ", mode=0x" + Integer.toHexString(mode));
            Cpsr.getArm64(emulator.getBackend()).setCarry(true);
            return UnixEmulator.ENOENT;
        }
    }

    protected final boolean host_statistics(Pointer request, MachMsgHeader header) {
        HostStatisticsRequest args = new HostStatisticsRequest(request);
        args.unpack();
        if (log.isDebugEnabled()) {
            log.debug("host_statistics args=" + args);
        }

        if (args.flavor == HostStatisticsRequest.HOST_VM_INFO) {
            int size = UnidbgStructure.calculateSize(VMStatistics.class);
            HostStatisticsReply reply = new HostStatisticsReply(request, size);
            reply.unpack();

            header.setMsgBits(false);
            header.msgh_size = header.size() + reply.size();
            header.msgh_remote_port = header.msgh_local_port;
            header.msgh_local_port = 0;
            header.msgh_id += 100; // reply Id always equals reqId+100
            header.pack();

            reply.writeVMStatistics();
            reply.retCode = 0;
            reply.host_info_outCnt = size / 4;
            reply.pack();

            if (log.isDebugEnabled()) {
                log.debug("host_statistics HOST_VM_INFO reply=" + reply);
            }
            return true;
        }

        return false;
    }

    final int vproc_mig_look_up2(Pointer request, MachMsgHeader header) {
        VprocMigLookupRequest args = new VprocMigLookupRequest(request);
        args.unpack();
        String serviceName = args.getServiceName();
        if (log.isDebugEnabled()) {
            log.debug("vproc_mig_look_up2 args=" + args + ", serviceName=" + serviceName);
        }

        if ("cy:com.saurik.substrated".equals(serviceName)) {
            return -1;
        }

        VprocMigLookupReply reply = new VprocMigLookupReply(request);
        reply.unpack();

        header.msgh_bits = (header.msgh_bits & 0xff) | MACH_MSGH_BITS_COMPLEX;
        header.msgh_size = header.size() + reply.size();
        header.msgh_remote_port = header.msgh_local_port;
        header.msgh_local_port = 0;
        header.msgh_id += 100; // reply Id always equals reqId+100
        header.pack();

        reply.body.msgh_descriptor_count = 1;
        reply.sp.name = STATIC_PORT;
        reply.sp.pad1 = 0;
        reply.sp.pad2 = 0;
        reply.sp.disposition = 17;
        reply.sp.type = MACH_MSG_PORT_DESCRIPTOR;
        reply.pack();

        VprocMigLookupData data = new VprocMigLookupData(request.share(reply.size()));
        data.size = 0x20;
        Arrays.fill(data.au_tok.val, 0);
        data.pack();

        if (log.isDebugEnabled()) {
            log.debug("vproc_mig_look_up2 reply=" + reply + ", data=" + data);
        }
        return MACH_MSG_SUCCESS;
    }

    protected String executableBundlePath;

    public void setExecutableBundlePath(String executableBundlePath) {
        this.executableBundlePath = executableBundlePath;
    }

    private int threadId;

    private int incrementThreadId(Emulator emulator) {
        if (threadId == 0) {
            threadId = emulator.getPid();
        }
        return (++threadId) & 0xffff;
    }

    private int processSignal(ThreadDispatcher threadDispatcher, int sig, Task task, SigAction action) {
        if (action != null) {
            SignalOps signalOps = task.isMainThread() ? threadDispatcher : task;
            SigSet sigMaskSet = signalOps.getSigMaskSet();
            SigSet sigPendingSet = signalOps.getSigPendingSet();
            if (sigMaskSet == null || !sigMaskSet.containsSigNumber(sig)) {
                task.addSignalTask(new SignalTask(sig, action));
                throw new ThreadContextSwitchException().setReturnValue(0);
            } else if (sigPendingSet != null) {
                sigPendingSet.addSigNumber(sig);
            }
        }
        return 0;
    }

    protected int pthread_kill(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int threadPort = context.getIntArg(0);
        int sig = context.getIntArg(1);
        if (log.isDebugEnabled()) {
            log.debug("pthread_kill threadPort=" + threadPort + ", sig=" + sig);
        }
        if (sig > 0) {
            SigAction action = sigActionMap.get(sig);
            if (emulator.getThreadDispatcher().sendSignal(threadPort, sig, action == null ? null : new SignalTask(sig, action))) {
                throw new ThreadContextSwitchException().setReturnValue(0);
            }
        }
        return 0;
    }

    protected int _semaphore_wait_trap(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int port = context.getIntArg(0);
        if (log.isDebugEnabled()) {
            log.debug("_semaphore_wait_trap port=" + port + ", LR=" + context.getLRPointer());
        }
        if (log.isDebugEnabled()) {
            createBreaker(emulator).debug();
        }
        RunnableTask runningTask = emulator.getThreadDispatcher().getRunningTask();
        if (threadDispatcherEnabled && runningTask != null) {
            runningTask.setWaiter(emulator, new SemWaiter(port, semaphoreMap));
            throw new ThreadContextSwitchException().setReturnValue(0);
        }
        if (LogFactory.getLog(AbstractEmulator.class).isDebugEnabled()) {
            createBreaker(emulator).debug();
        }
        return 0;
    }

    protected final Map semaphoreMap = new HashMap<>();

    protected int semwait_signal(Emulator emulator, RunnableTask runningTask, int cond_sem, int mutex_sem, int timeout, int relative,
                                 long tv_sec, int tv_nsec) {
        if (timeout == 1 && relative == 1 && (tv_sec > 0 || tv_nsec > 0)) {
            if (threadDispatcherEnabled) {
                runningTask.setWaiter(emulator, new SemWaiter(cond_sem, semaphoreMap, tv_sec, tv_nsec));
                throw new ThreadContextSwitchException().setReturnValue(0);
            }

            try {
                Thread.sleep(tv_sec * 1000L + tv_nsec / 1000L, tv_nsec % 1000);
                emulator.getMemory().setErrno(ETIMEDOUT);
                return -1;
            } catch (InterruptedException e) {
                throw new IllegalStateException(e);
            }
        }
        if (mutex_sem != 0 || timeout != 0 ||
                relative != 0 || tv_sec != 0 || tv_nsec != 0) {
            createBreaker(emulator).debug();
            throw new UnsupportedOperationException("semwait_signal cond_sem=" + cond_sem + ", mutex_sem=" + mutex_sem + ", timeout=" + timeout + ", relative=" + relative + ", tv_sec=" + tv_sec + ", tv_nsec=" + tv_nsec);
        }
        runningTask.setWaiter(emulator, new SemWaiter(cond_sem, semaphoreMap));
        throw new ThreadContextSwitchException().setReturnValue(0);
    }

    protected int disable_threadsignal(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int status = context.getIntArg(0);
        if (log.isDebugEnabled()) {
            log.debug("disable_threadsignal status=" + status);
        }
        Task task = emulator.get(Task.TASK_KEY);
        if (task == emulator.getThreadDispatcher().getRunningTask() &&
                !task.getSignalTaskList().isEmpty()) {
            throw new ThreadContextSwitchException().setReturnValue(0);
        }
        return 0;
    }

    protected int sigpending(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer set = context.getPointerArg(0);
        if (log.isDebugEnabled()) {
            log.debug("sigpending set=" + set);
        }
        Task task = emulator.get(Task.TASK_KEY);
        SignalOps signalOps = task.isMainThread() ? emulator.getThreadDispatcher() : task;
        SigSet sigSet = signalOps.getSigPendingSet();
        if (set != null && sigSet != null) {
            set.setInt(0, (int) sigSet.getMask());
        }
        return 0;
    }

    protected int sigwait(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer set = context.getPointerArg(0);
        Pointer sig = context.getPointerArg(1);

        int mask = set.getInt(0);
        Task task = emulator.get(Task.TASK_KEY);
        SigSet sigSet = new UnixSigSet(mask);
        SignalOps signalOps = task.isMainThread() ? emulator.getThreadDispatcher() : task;
        SigSet sigPendingSet = signalOps.getSigPendingSet();
        if (sigPendingSet != null) {
            for (Integer signum : sigSet) {
                if (sigPendingSet.containsSigNumber(signum)) {
                    sigPendingSet.removeSigNumber(signum);
                    sig.setInt(0, signum);
                    return 0;
                }
            }
        }
        if (!task.isMainThread()) {
            throw new ThreadContextSwitchException().setReturnValue(-1);
        }
        log.info("sigwait set=" + set + ", sig=" + sig);
        Log log = LogFactory.getLog(AbstractEmulator.class);
        if (log.isDebugEnabled()) {
            emulator.attach().debug();
        }
        return 0;
    }

    protected int kill(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int pid = context.getIntArg(0);
        int sig = context.getIntArg(1);
        if (log.isDebugEnabled()) {
            log.debug("kill pid=" + pid + ", sig=" + sig);
        }
        Task task = emulator.get(Task.TASK_KEY);
        if ((pid == 0 || pid == emulator.getPid()) && sig > 0 && task != null) {
            SigAction action = sigActionMap.get(sig);
            return processSignal(emulator.getThreadDispatcher(), sig, task, action);
        }
        throw new UnsupportedOperationException("kill pid=" + pid + ", sig=" + sig + ", LR=" + context.getLRPointer());
    }

    private final Map sigActionMap = new HashMap<>();

    @Override
    protected int sigaction(Emulator emulator, int signum, Pointer act, Pointer oldact) {
        SigAction action = SigAction.create(emulator, act);
        SigAction oldAction = SigAction.create(emulator, oldact);
        if (log.isDebugEnabled()) {
            log.debug("sigaction signum=" + signum + ", action=" + action + ", oldAction=" + oldAction);
        }
        SigAction lastAction = sigActionMap.put(signum, action);
        if (oldAction != null) {
            if (lastAction == null) {
                oldact.write(0, new byte[oldAction.size()], 0, oldAction.size());
            } else {
                oldAction.setSaHandler(lastAction.getSaHandler());
                oldAction.sa_mask = lastAction.sa_mask;
                oldAction.sa_flags = lastAction.sa_flags;
                oldAction.pack();
            }
        }
        return 0;
    }

    // https://github.com/lunixbochs/usercorn/blob/master/go/kernel/mach/thread.go
    protected int thread_selfid(Emulator emulator) {
        Task task = emulator.get(Task.TASK_KEY);
        if (task != null) {
            if (task.isMainThread()) {
                return emulator.getPid();
            } else if (task instanceof ThreadTask) {
                ThreadTask thread = (ThreadTask) task;
                return thread.getId();
            }
        }
        log.debug("thread_selfid");
        return 1;
    }

    private static final int SIG_BLOCK = 1; /* block specified signal set */
    private static final int SIG_UNBLOCK = 2; /* unblock specified signal set */
    private static final int SIG_SETMASK = 3; /* set specified signal set */

    protected int pthread_sigmask(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int how = context.getIntArg(0);
        Pointer set = context.getPointerArg(1);
        Pointer oset = context.getPointerArg(2);
        if (log.isDebugEnabled()) {
            log.debug("pthread_sigmask how=" + how + ", set=" + set + ", oset=" + oset);
        }

        Task task = emulator.get(Task.TASK_KEY);
        SignalOps signalOps = task.isMainThread() ? emulator.getThreadDispatcher() : task;
        SigSet old = signalOps.getSigMaskSet();
        if (oset != null && old != null) {
            oset.setInt(0, (int) old.getMask());
        }
        if (set == null) {
            return 0;
        }
        int mask = set.getInt(0);
        switch (how) {
            case SIG_BLOCK:
                if (old == null) {
                    SigSet sigSet = new UnixSigSet(mask);
                    SigSet sigPendingSet = new UnixSigSet(0);
                    signalOps.setSigMaskSet(sigSet);
                    signalOps.setSigPendingSet(sigPendingSet);
                } else {
                    old.blockSigSet(mask);
                }
                return 0;
            case SIG_UNBLOCK:
                if (old != null) {
                    old.unblockSigSet(mask);
                }
                return 0;
            case SIG_SETMASK:
                SigSet sigSet = new UnixSigSet(mask);
                SigSet sigPendingSet = new UnixSigSet(0);
                signalOps.setSigMaskSet(sigSet);
                signalOps.setSigPendingSet(sigPendingSet);
                return 0;
            default:
                throw new IllegalStateException();
        }
    }

    protected int kqueue() {
        if (log.isDebugEnabled()) {
            log.debug("kqueue");
        }
        int fd = getMinFd();
        fdMap.put(fd, new KEvent(0));
        return fd;
    }

    protected int guarded_kqueue_np(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer guard = context.getPointerArg(0);
        int guardFlags = context.getIntArg(1);
        KEvent64 kev = new KEvent64(guard.getPointer(0));
        kev.unpack();
        if (log.isDebugEnabled()) {
            log.debug("guarded_kqueue_np kev=" + kev + ", guardFlags=0x" + Integer.toHexString(guardFlags) + ", LR=" + context.getLRPointer());
        }
        int fd = getMinFd();
        fdMap.put(fd, new KEvent(guardFlags));
        return fd;
    }

    protected int kevent64(Emulator emulator, int kq, Pointer changelist, int nchanges, Pointer eventlist, int nevents, int flags, TimeSpec timeSpec) {
        RegisterContext context = emulator.getContext();
        if (log.isDebugEnabled()) {
            log.debug("kevent64 kq=" + kq + ", changelist=" + changelist + ", nchanges=" + nchanges + ", eventlist=" + eventlist + ", nevents=" + nevents + ", flags=0x" + Integer.toHexString(flags) + ", timeSpec=" + timeSpec + ", LR=" + context.getLRPointer());
        }
        if (timeSpec != null) {
            throw new UnsupportedOperationException();
        }
        KEvent event = (KEvent) fdMap.get(kq);
        event.processChangeList(changelist, nchanges);
        if (eventlist == null || nevents <= 0) {
            return 0;
        }
        RunnableTask runningTask = emulator.getThreadDispatcher().getRunningTask();
        if (runningTask != null) {
            runningTask.setWaiter(emulator, new KEventWaiter(event, eventlist, nevents));
            throw new ThreadContextSwitchException();
        }
        if (log.isDebugEnabled() || LogFactory.getLog(AbstractEmulator.class).isDebugEnabled()) {
            createBreaker(emulator).debug();
        }
        return 0;
    }

    protected int psynch_cvbroad(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        Pointer ocond = context.getPointerArg(0);
        if (log.isDebugEnabled()) {
            log.debug("psynch_cvbroad ocond=" + ocond);
        }
        if (threadDispatcherEnabled) {
            throw new ThreadContextSwitchException().setReturnValue(0);
        }
        return 0;
    }

    private UnidbgPointer thread_start;
    private int pthreadSize;

    protected int bsdthread_register(UnidbgPointer thread_start, int pthreadSize) {
        this.thread_start = thread_start;
        this.pthreadSize = pthreadSize;
        return 0;
    }

    protected int bsdthread_terminate(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        final UnidbgPointer freeaddr = context.getPointerArg(0);
        final int freesize = context.getIntArg(1);
        int kport = context.getIntArg(2);
        int joinsem = context.getIntArg(3);
        if (log.isDebugEnabled()) {
            log.debug("bsdthread_terminate freeaddr=" + freeaddr + ", freesize=" + freesize + ", kport=" + kport + ", joinsem=" + joinsem);
        }
        if (joinsem != 0) {
            semaphoreMap.put(joinsem, Boolean.TRUE);
        }
        Task task = emulator.get(Task.TASK_KEY);
        if (task instanceof ThreadTask) {
            ThreadTask threadTask = (ThreadTask) task;
            threadTask.setExitStatus(0);
            emulator.getMemory().munmap(freeaddr.peer, freesize);
            throw new ThreadContextSwitchException().setReturnValue(0);
        }
        return 0;
    }

    protected long bsdthread_create(Emulator emulator, UnidbgPointer start_routine, UnidbgPointer arg, UnidbgPointer stack, UnidbgPointer thread, int flags) {
        int threadId = incrementThreadId(emulator);

        if (thread == null) {
            if (thread_start == null || pthreadSize <= 0) {
                throw new IllegalStateException();
            }

            int stackSize = (int) stack.toUIntPeer();
            int pageSize = emulator.getPageAlign();
            MemoryBlock memoryBlock = emulator.getMemory().malloc(pageSize + stackSize + pthreadSize, true);
            thread = memoryBlock.getPointer().share(pageSize + stackSize, 0);

            Pthread pThread = Pthread.create(emulator, thread);
            pThread.setMachThreadSelf(threadId);
            pThread.pack();

            String msg = "bsdthread_create start_routine=" + start_routine + ", arg=" + arg + ", stack=" + stack + ", thread=" + thread + ", flags=0x" + Integer.toHexString(flags);
            if (threadDispatcherEnabled) {
                if (log.isDebugEnabled()) {
                    log.debug(msg);
                }

                if (verbose) {
                    System.out.printf("bsdthread_create start_routine=%s, stack=%s, thread=%s%n", start_routine, stack, thread);
                }
                if (log.isTraceEnabled()) {
                    createBreaker(emulator).debug();
                }

                emulator.getThreadDispatcher().addThread(new BsdThread(emulator, threadId, thread_start, thread, start_routine, arg, stackSize));
            } else {
                log.info(msg);
            }
            return thread.peer;
        } else {
            throw new UnsupportedOperationException();
        }
    }

    protected int swtch_pri(Emulator emulator) {
        RegisterContext context = emulator.getContext();
        int pri = context.getIntArg(0);
        if (log.isDebugEnabled()) {
            log.debug("swtch_pri pri=" + pri + ", LR=" + context.getLRPointer());
        }
        if (log.isDebugEnabled() || LogFactory.getLog(AbstractEmulator.class).isDebugEnabled()) {
            createBreaker(emulator).debug();
        }
        return 0;
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy