mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 18:44:01 +00:00
更新Wine+更新menuconfig
This commit is contained in:
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -69,6 +69,48 @@ SYS_PROC_LAST_SIGNAL = 57
|
||||
SYS_PROC_FAULT_VECTOR = 58
|
||||
SYS_PROC_FAULT_ERROR = 59
|
||||
SYS_PROC_FAULT_RIP = 60
|
||||
SYS_PROC_COUNT = 61
|
||||
SYS_PROC_PID_AT = 62
|
||||
SYS_PROC_SNAPSHOT = 63
|
||||
SYS_PROC_KILL = 64
|
||||
SYS_KDBG_SYM = 65
|
||||
SYS_KDBG_BT = 66
|
||||
SYS_KDBG_REGS = 67
|
||||
SYS_STATS_TOTAL = 68
|
||||
SYS_STATS_ID_COUNT = 69
|
||||
SYS_STATS_RECENT_WINDOW = 70
|
||||
SYS_STATS_RECENT_ID = 71
|
||||
SYS_FD_OPEN = 72
|
||||
SYS_FD_READ = 73
|
||||
SYS_FD_WRITE = 74
|
||||
SYS_FD_CLOSE = 75
|
||||
SYS_FD_DUP = 76
|
||||
SYS_DL_OPEN = 77
|
||||
SYS_DL_CLOSE = 78
|
||||
SYS_DL_SYM = 79
|
||||
SYS_EXEC_PATHV_IO = 80
|
||||
|
||||
# proc states (from cleonos/c/include/cleonos_syscall.h)
|
||||
PROC_STATE_UNUSED = 0
|
||||
PROC_STATE_PENDING = 1
|
||||
PROC_STATE_RUNNING = 2
|
||||
PROC_STATE_EXITED = 3
|
||||
PROC_STATE_STOPPED = 4
|
||||
|
||||
# signals (from cleonos/c/include/cleonos_syscall.h)
|
||||
SIGKILL = 9
|
||||
SIGTERM = 15
|
||||
SIGCONT = 18
|
||||
SIGSTOP = 19
|
||||
|
||||
# open flags (from cleonos/c/include/cleonos_syscall.h)
|
||||
O_RDONLY = 0x0000
|
||||
O_WRONLY = 0x0001
|
||||
O_RDWR = 0x0002
|
||||
O_CREAT = 0x0040
|
||||
O_TRUNC = 0x0200
|
||||
O_APPEND = 0x0400
|
||||
FD_INHERIT = U64_MASK
|
||||
|
||||
|
||||
def u64(value: int) -> int:
|
||||
|
||||
@@ -6,40 +6,48 @@ import sys
|
||||
import time
|
||||
from dataclasses import dataclass
|
||||
from pathlib import Path
|
||||
from typing import List, Optional, Tuple
|
||||
from typing import Dict, List, Optional, Tuple
|
||||
|
||||
from .constants import (
|
||||
DEFAULT_MAX_EXEC_DEPTH,
|
||||
FD_INHERIT,
|
||||
FS_NAME_MAX,
|
||||
MAX_CSTR,
|
||||
MAX_IO_READ,
|
||||
O_APPEND,
|
||||
O_CREAT,
|
||||
O_RDONLY,
|
||||
O_RDWR,
|
||||
O_TRUNC,
|
||||
O_WRONLY,
|
||||
PAGE_SIZE,
|
||||
PROC_STATE_EXITED,
|
||||
PROC_STATE_PENDING,
|
||||
PROC_STATE_RUNNING,
|
||||
PROC_STATE_STOPPED,
|
||||
SIGCONT,
|
||||
SIGKILL,
|
||||
SIGSTOP,
|
||||
SIGTERM,
|
||||
SYS_AUDIO_AVAILABLE,
|
||||
SYS_AUDIO_PLAY_TONE,
|
||||
SYS_AUDIO_STOP,
|
||||
SYS_CONTEXT_SWITCHES,
|
||||
SYS_CUR_TASK,
|
||||
SYS_DL_CLOSE,
|
||||
SYS_DL_OPEN,
|
||||
SYS_DL_SYM,
|
||||
SYS_EXEC_PATH,
|
||||
SYS_EXEC_PATHV,
|
||||
SYS_EXEC_PATHV_IO,
|
||||
SYS_EXEC_REQUESTS,
|
||||
SYS_EXEC_SUCCESS,
|
||||
SYS_EXIT,
|
||||
SYS_GETPID,
|
||||
SYS_PROC_ARGC,
|
||||
SYS_PROC_ARGV,
|
||||
SYS_PROC_ENVC,
|
||||
SYS_PROC_ENV,
|
||||
SYS_PROC_FAULT_ERROR,
|
||||
SYS_PROC_FAULT_RIP,
|
||||
SYS_PROC_FAULT_VECTOR,
|
||||
SYS_PROC_LAST_SIGNAL,
|
||||
SYS_SLEEP_TICKS,
|
||||
SYS_SPAWN_PATH,
|
||||
SYS_SPAWN_PATHV,
|
||||
SYS_WAITPID,
|
||||
SYS_YIELD,
|
||||
SYS_SHUTDOWN,
|
||||
SYS_RESTART,
|
||||
SYS_FD_CLOSE,
|
||||
SYS_FD_DUP,
|
||||
SYS_FD_OPEN,
|
||||
SYS_FD_READ,
|
||||
SYS_FD_WRITE,
|
||||
SYS_FS_APPEND,
|
||||
SYS_FS_CHILD_COUNT,
|
||||
SYS_FS_GET_CHILD_NAME,
|
||||
@@ -50,6 +58,7 @@ from .constants import (
|
||||
SYS_FS_STAT_SIZE,
|
||||
SYS_FS_STAT_TYPE,
|
||||
SYS_FS_WRITE,
|
||||
SYS_GETPID,
|
||||
SYS_KBD_BUFFERED,
|
||||
SYS_KBD_DROPPED,
|
||||
SYS_KBD_GET_CHAR,
|
||||
@@ -61,8 +70,29 @@ from .constants import (
|
||||
SYS_LOG_JOURNAL_COUNT,
|
||||
SYS_LOG_JOURNAL_READ,
|
||||
SYS_LOG_WRITE,
|
||||
SYS_PROC_ARGC,
|
||||
SYS_PROC_ARGV,
|
||||
SYS_PROC_COUNT,
|
||||
SYS_PROC_ENVC,
|
||||
SYS_PROC_ENV,
|
||||
SYS_PROC_FAULT_ERROR,
|
||||
SYS_PROC_FAULT_RIP,
|
||||
SYS_PROC_FAULT_VECTOR,
|
||||
SYS_PROC_KILL,
|
||||
SYS_PROC_LAST_SIGNAL,
|
||||
SYS_PROC_PID_AT,
|
||||
SYS_PROC_SNAPSHOT,
|
||||
SYS_RESTART,
|
||||
SYS_SERVICE_COUNT,
|
||||
SYS_SERVICE_READY_COUNT,
|
||||
SYS_SHUTDOWN,
|
||||
SYS_SLEEP_TICKS,
|
||||
SYS_SPAWN_PATH,
|
||||
SYS_SPAWN_PATHV,
|
||||
SYS_STATS_ID_COUNT,
|
||||
SYS_STATS_RECENT_ID,
|
||||
SYS_STATS_RECENT_WINDOW,
|
||||
SYS_STATS_TOTAL,
|
||||
SYS_TASK_COUNT,
|
||||
SYS_TIMER_TICKS,
|
||||
SYS_TTY_ACTIVE,
|
||||
@@ -75,6 +105,8 @@ from .constants import (
|
||||
SYS_USER_LAUNCH_OK,
|
||||
SYS_USER_LAUNCH_TRIES,
|
||||
SYS_USER_SHELL_READY,
|
||||
SYS_WAITPID,
|
||||
SYS_YIELD,
|
||||
page_ceil,
|
||||
page_floor,
|
||||
u64,
|
||||
@@ -124,6 +156,15 @@ class ELFImage:
|
||||
segments: List[ELFSegment]
|
||||
|
||||
|
||||
@dataclass
|
||||
class FDEntry:
|
||||
kind: str
|
||||
flags: int
|
||||
offset: int = 0
|
||||
path: str = ""
|
||||
tty_index: int = 0
|
||||
|
||||
|
||||
EXEC_PATH_MAX = 192
|
||||
EXEC_ARG_LINE_MAX = 256
|
||||
EXEC_ENV_LINE_MAX = 512
|
||||
@@ -131,6 +172,8 @@ EXEC_MAX_ARGS = 24
|
||||
EXEC_MAX_ENVS = 24
|
||||
EXEC_ITEM_MAX = 128
|
||||
EXEC_STATUS_SIGNAL_FLAG = 1 << 63
|
||||
PROC_PATH_MAX = 192
|
||||
FD_MAX = 64
|
||||
|
||||
|
||||
class CLeonOSWineNative:
|
||||
@@ -150,6 +193,7 @@ class CLeonOSWineNative:
|
||||
ppid: int = 0,
|
||||
argv_items: Optional[List[str]] = None,
|
||||
env_items: Optional[List[str]] = None,
|
||||
inherited_fds: Optional[Dict[int, FDEntry]] = None,
|
||||
) -> None:
|
||||
self.elf_path = elf_path
|
||||
self.rootfs = rootfs
|
||||
@@ -175,9 +219,97 @@ class CLeonOSWineNative:
|
||||
self._stack_size = 0x0000000000020000
|
||||
self._ret_sentinel = 0x00007FFF10000000
|
||||
self._mapped_ranges: List[Tuple[int, int]] = []
|
||||
self._tty_index = int(self.state.tty_active)
|
||||
self._fds: Dict[int, FDEntry] = {}
|
||||
self._fd_inherited = inherited_fds if inherited_fds is not None else {}
|
||||
|
||||
default_path = self._normalize_guest_path(self.guest_path_hint or f"/{self.elf_path.name}")
|
||||
self.argv_items, self.env_items = self._prepare_exec_items(default_path, self.argv_items, self.env_items)
|
||||
self._init_default_fds()
|
||||
|
||||
@staticmethod
|
||||
def _clone_fd_entry(entry: FDEntry) -> FDEntry:
|
||||
return FDEntry(kind=entry.kind, flags=int(entry.flags), offset=int(entry.offset), path=str(entry.path), tty_index=int(entry.tty_index))
|
||||
|
||||
@staticmethod
|
||||
def _fd_access_mode(flags: int) -> int:
|
||||
return int(flags) & 0x3
|
||||
|
||||
@classmethod
|
||||
def _fd_access_mode_valid(cls, flags: int) -> bool:
|
||||
mode = cls._fd_access_mode(flags)
|
||||
return mode in (O_RDONLY, O_WRONLY, O_RDWR)
|
||||
|
||||
@classmethod
|
||||
def _fd_can_read(cls, flags: int) -> bool:
|
||||
mode = cls._fd_access_mode(flags)
|
||||
return mode in (O_RDONLY, O_RDWR)
|
||||
|
||||
@classmethod
|
||||
def _fd_can_write(cls, flags: int) -> bool:
|
||||
mode = cls._fd_access_mode(flags)
|
||||
return mode in (O_WRONLY, O_RDWR)
|
||||
|
||||
def _init_default_fds(self) -> None:
|
||||
self._fds = {
|
||||
0: FDEntry(kind="tty", flags=O_RDONLY, offset=0, tty_index=self._tty_index),
|
||||
1: FDEntry(kind="tty", flags=O_WRONLY, offset=0, tty_index=self._tty_index),
|
||||
2: FDEntry(kind="tty", flags=O_WRONLY, offset=0, tty_index=self._tty_index),
|
||||
}
|
||||
|
||||
for target in (0, 1, 2):
|
||||
inherited = self._fd_inherited.get(target)
|
||||
if inherited is not None:
|
||||
self._fds[target] = self._clone_fd_entry(inherited)
|
||||
|
||||
for target in (0, 1, 2):
|
||||
entry = self._fds.get(target)
|
||||
if entry is not None and entry.kind == "tty":
|
||||
self._tty_index = int(entry.tty_index)
|
||||
break
|
||||
|
||||
def _fd_lookup(self, fd: int) -> Optional[FDEntry]:
|
||||
if fd < 0 or fd >= FD_MAX:
|
||||
return None
|
||||
return self._fds.get(int(fd))
|
||||
|
||||
def _fd_find_free(self) -> int:
|
||||
for fd in range(FD_MAX):
|
||||
if fd not in self._fds:
|
||||
return fd
|
||||
return -1
|
||||
|
||||
def _stdio_entry_for_child(self, target_fd: int, override_fd: int, require_read: bool, require_write: bool) -> Optional[FDEntry]:
|
||||
if override_fd == FD_INHERIT:
|
||||
src = self._fd_lookup(target_fd)
|
||||
else:
|
||||
src = self._fd_lookup(override_fd)
|
||||
|
||||
if src is None:
|
||||
return None
|
||||
|
||||
if require_read and not self._fd_can_read(src.flags):
|
||||
return None
|
||||
|
||||
if require_write and not self._fd_can_write(src.flags):
|
||||
return None
|
||||
|
||||
return self._clone_fd_entry(src)
|
||||
|
||||
def _build_child_stdio_map(self, stdin_fd: int, stdout_fd: int, stderr_fd: int) -> Optional[Dict[int, FDEntry]]:
|
||||
child_map: Dict[int, FDEntry] = {}
|
||||
|
||||
in_entry = self._stdio_entry_for_child(0, stdin_fd, require_read=True, require_write=False)
|
||||
out_entry = self._stdio_entry_for_child(1, stdout_fd, require_read=False, require_write=True)
|
||||
err_entry = self._stdio_entry_for_child(2, stderr_fd, require_read=False, require_write=True)
|
||||
|
||||
if in_entry is None or out_entry is None or err_entry is None:
|
||||
return None
|
||||
|
||||
child_map[0] = in_entry
|
||||
child_map[1] = out_entry
|
||||
child_map[2] = err_entry
|
||||
return child_map
|
||||
|
||||
def run(self) -> Optional[int]:
|
||||
if self.pid == 0:
|
||||
@@ -187,6 +319,7 @@ class CLeonOSWineNative:
|
||||
self.state.set_current_pid(self.pid)
|
||||
self.state.set_proc_cmdline(self.pid, self.argv_items, self.env_items)
|
||||
self.state.set_proc_fault(self.pid, 0, 0, 0, 0)
|
||||
self.state.set_proc_running(self.pid, self.argv_items[0] if self.argv_items else self.guest_path_hint, self._tty_index)
|
||||
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
self._install_hooks(uc)
|
||||
@@ -252,6 +385,7 @@ class CLeonOSWineNative:
|
||||
arg1 = self._reg_read(uc, UC_X86_REG_RCX)
|
||||
arg2 = self._reg_read(uc, UC_X86_REG_RDX)
|
||||
|
||||
self.state.record_syscall(syscall_id)
|
||||
self.state.context_switches = u64(self.state.context_switches + 1)
|
||||
ret = self._dispatch_syscall(uc, syscall_id, arg0, arg1, arg2)
|
||||
self._reg_write(uc, UC_X86_REG_RAX, u64(ret))
|
||||
@@ -291,6 +425,8 @@ class CLeonOSWineNative:
|
||||
return self._exec_path(uc, arg0)
|
||||
if sid == SYS_EXEC_PATHV:
|
||||
return self._exec_pathv(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_EXEC_PATHV_IO:
|
||||
return self._exec_pathv_io(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_SPAWN_PATH:
|
||||
return self._spawn_path(uc, arg0)
|
||||
if sid == SYS_SPAWN_PATHV:
|
||||
@@ -315,6 +451,14 @@ class CLeonOSWineNative:
|
||||
return self._proc_fault_error()
|
||||
if sid == SYS_PROC_FAULT_RIP:
|
||||
return self._proc_fault_rip()
|
||||
if sid == SYS_PROC_COUNT:
|
||||
return self._proc_count()
|
||||
if sid == SYS_PROC_PID_AT:
|
||||
return self._proc_pid_at(uc, arg0, arg1)
|
||||
if sid == SYS_PROC_SNAPSHOT:
|
||||
return self._proc_snapshot(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_PROC_KILL:
|
||||
return self._proc_kill(uc, arg0, arg1)
|
||||
if sid == SYS_EXIT:
|
||||
return self._request_exit(uc, arg0)
|
||||
if sid == SYS_SLEEP_TICKS:
|
||||
@@ -400,6 +544,30 @@ class CLeonOSWineNative:
|
||||
return self.state.kbd_drop_count
|
||||
if sid == SYS_KBD_HOTKEY_SWITCHES:
|
||||
return self.state.kbd_hotkey_switches
|
||||
if sid == SYS_STATS_TOTAL:
|
||||
return self.state.stats_total()
|
||||
if sid == SYS_STATS_ID_COUNT:
|
||||
return self.state.stats_id_count(arg0)
|
||||
if sid == SYS_STATS_RECENT_WINDOW:
|
||||
return self.state.stats_recent_window()
|
||||
if sid == SYS_STATS_RECENT_ID:
|
||||
return self.state.stats_recent_id_count(arg0)
|
||||
if sid == SYS_FD_OPEN:
|
||||
return self._fd_open(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_FD_READ:
|
||||
return self._fd_read(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_FD_WRITE:
|
||||
return self._fd_write(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_FD_CLOSE:
|
||||
return self._fd_close(arg0)
|
||||
if sid == SYS_FD_DUP:
|
||||
return self._fd_dup(arg0)
|
||||
if sid == SYS_DL_OPEN:
|
||||
return u64_neg1()
|
||||
if sid == SYS_DL_CLOSE:
|
||||
return 0
|
||||
if sid == SYS_DL_SYM:
|
||||
return 0
|
||||
|
||||
return u64_neg1()
|
||||
|
||||
@@ -409,6 +577,15 @@ class CLeonOSWineNative:
|
||||
sys.stdout.write(text)
|
||||
sys.stdout.flush()
|
||||
|
||||
def _host_write_bytes(self, data: bytes) -> None:
|
||||
if not data:
|
||||
return
|
||||
if hasattr(sys.stdout, "buffer"):
|
||||
sys.stdout.buffer.write(data)
|
||||
sys.stdout.flush()
|
||||
return
|
||||
self._host_write(data.decode("utf-8", errors="replace"))
|
||||
|
||||
def _load_segments(self, uc: Uc) -> None:
|
||||
for seg in self.image.segments:
|
||||
start = page_floor(seg.vaddr)
|
||||
@@ -504,6 +681,30 @@ class CLeonOSWineNative:
|
||||
except UcError:
|
||||
return b""
|
||||
|
||||
def _read_guest_bytes_exact(self, uc: Uc, addr: int, size: int) -> Optional[bytes]:
|
||||
if size < 0 or addr == 0:
|
||||
return None
|
||||
if size == 0:
|
||||
return b""
|
||||
|
||||
out = bytearray()
|
||||
cursor = int(addr)
|
||||
left = int(size)
|
||||
|
||||
while left > 0:
|
||||
chunk = min(left, MAX_IO_READ)
|
||||
try:
|
||||
data = uc.mem_read(cursor, chunk)
|
||||
except UcError:
|
||||
return None
|
||||
if len(data) != chunk:
|
||||
return None
|
||||
out.extend(data)
|
||||
cursor += chunk
|
||||
left -= chunk
|
||||
|
||||
return bytes(out)
|
||||
|
||||
def _write_guest_bytes(self, uc: Uc, addr: int, data: bytes) -> bool:
|
||||
if addr == 0:
|
||||
return False
|
||||
@@ -743,16 +944,86 @@ class CLeonOSWineNative:
|
||||
return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0
|
||||
|
||||
def _exec_path(self, uc: Uc, path_ptr: int) -> int:
|
||||
return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=False)
|
||||
return self._spawn_path_common(
|
||||
uc,
|
||||
path_ptr,
|
||||
0,
|
||||
0,
|
||||
return_pid=False,
|
||||
env_line_override=None,
|
||||
stdin_fd=FD_INHERIT,
|
||||
stdout_fd=FD_INHERIT,
|
||||
stderr_fd=FD_INHERIT,
|
||||
)
|
||||
|
||||
def _exec_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int:
|
||||
return self._spawn_path_common(uc, path_ptr, argv_ptr, env_ptr, return_pid=False)
|
||||
return self._spawn_path_common(
|
||||
uc,
|
||||
path_ptr,
|
||||
argv_ptr,
|
||||
env_ptr,
|
||||
return_pid=False,
|
||||
env_line_override=None,
|
||||
stdin_fd=FD_INHERIT,
|
||||
stdout_fd=FD_INHERIT,
|
||||
stderr_fd=FD_INHERIT,
|
||||
)
|
||||
|
||||
def _exec_pathv_io(self, uc: Uc, path_ptr: int, argv_ptr: int, req_ptr: int) -> int:
|
||||
req_data: Optional[bytes]
|
||||
env_ptr: int
|
||||
stdin_fd: int
|
||||
stdout_fd: int
|
||||
stderr_fd: int
|
||||
env_line: str
|
||||
|
||||
if req_ptr == 0:
|
||||
return u64_neg1()
|
||||
|
||||
req_data = self._read_guest_bytes_exact(uc, req_ptr, 32)
|
||||
if req_data is None or len(req_data) != 32:
|
||||
return u64_neg1()
|
||||
|
||||
env_ptr, stdin_fd, stdout_fd, stderr_fd = struct.unpack("<QQQQ", req_data)
|
||||
env_line = self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else ""
|
||||
|
||||
return self._spawn_path_common(
|
||||
uc,
|
||||
path_ptr,
|
||||
argv_ptr,
|
||||
0,
|
||||
return_pid=False,
|
||||
env_line_override=env_line,
|
||||
stdin_fd=stdin_fd,
|
||||
stdout_fd=stdout_fd,
|
||||
stderr_fd=stderr_fd,
|
||||
)
|
||||
|
||||
def _spawn_path(self, uc: Uc, path_ptr: int) -> int:
|
||||
return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=True)
|
||||
return self._spawn_path_common(
|
||||
uc,
|
||||
path_ptr,
|
||||
0,
|
||||
0,
|
||||
return_pid=True,
|
||||
env_line_override=None,
|
||||
stdin_fd=FD_INHERIT,
|
||||
stdout_fd=FD_INHERIT,
|
||||
stderr_fd=FD_INHERIT,
|
||||
)
|
||||
|
||||
def _spawn_pathv(self, uc: Uc, path_ptr: int, argv_ptr: int, env_ptr: int) -> int:
|
||||
return self._spawn_path_common(uc, path_ptr, argv_ptr, env_ptr, return_pid=True)
|
||||
return self._spawn_path_common(
|
||||
uc,
|
||||
path_ptr,
|
||||
argv_ptr,
|
||||
env_ptr,
|
||||
return_pid=True,
|
||||
env_line_override=None,
|
||||
stdin_fd=FD_INHERIT,
|
||||
stdout_fd=FD_INHERIT,
|
||||
stderr_fd=FD_INHERIT,
|
||||
)
|
||||
|
||||
def _spawn_path_common(
|
||||
self,
|
||||
@@ -762,17 +1033,30 @@ class CLeonOSWineNative:
|
||||
env_ptr: int,
|
||||
*,
|
||||
return_pid: bool,
|
||||
env_line_override: Optional[str],
|
||||
stdin_fd: int,
|
||||
stdout_fd: int,
|
||||
stderr_fd: int,
|
||||
) -> int:
|
||||
path = self._read_guest_cstring(uc, path_ptr, EXEC_PATH_MAX)
|
||||
guest_path = self._normalize_guest_path(path)
|
||||
argv_line = self._read_guest_cstring(uc, argv_ptr, EXEC_ARG_LINE_MAX) if argv_ptr != 0 else ""
|
||||
env_line = self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else ""
|
||||
env_line = (
|
||||
env_line_override
|
||||
if env_line_override is not None
|
||||
else (self._read_guest_cstring(uc, env_ptr, EXEC_ENV_LINE_MAX) if env_ptr != 0 else "")
|
||||
)
|
||||
host_path = self._guest_to_host(guest_path, must_exist=True)
|
||||
child_stdio = self._build_child_stdio_map(int(stdin_fd), int(stdout_fd), int(stderr_fd))
|
||||
|
||||
self.state.exec_requests = u64(self.state.exec_requests + 1)
|
||||
self.state.user_exec_requested = 1
|
||||
self.state.user_launch_tries = u64(self.state.user_launch_tries + 1)
|
||||
|
||||
if child_stdio is None:
|
||||
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
|
||||
return u64_neg1()
|
||||
|
||||
if host_path is None or not host_path.is_file():
|
||||
self.state.user_launch_fail = u64(self.state.user_launch_fail + 1)
|
||||
return u64_neg1()
|
||||
@@ -802,6 +1086,7 @@ class CLeonOSWineNative:
|
||||
ppid=parent_pid,
|
||||
argv_items=argv_items,
|
||||
env_items=env_items,
|
||||
inherited_fds=child_stdio,
|
||||
)
|
||||
child_ret = child.run()
|
||||
|
||||
@@ -854,6 +1139,97 @@ class CLeonOSWineNative:
|
||||
def _proc_fault_rip(self) -> int:
|
||||
return self.state.proc_fault_rip_value(self.state.get_current_pid())
|
||||
|
||||
def _proc_count(self) -> int:
|
||||
return self.state.proc_count()
|
||||
|
||||
def _proc_pid_at(self, uc: Uc, index: int, out_ptr: int) -> int:
|
||||
if out_ptr == 0:
|
||||
return 0
|
||||
|
||||
pid = self.state.proc_pid_at(int(index))
|
||||
if pid is None:
|
||||
return 0
|
||||
|
||||
return 1 if self._write_guest_bytes(uc, out_ptr, struct.pack("<Q", u64(pid))) else 0
|
||||
|
||||
def _proc_snapshot(self, uc: Uc, pid: int, out_ptr: int, out_size: int) -> int:
|
||||
if out_ptr == 0 or out_size < (13 * 8 + PROC_PATH_MAX):
|
||||
return 0
|
||||
|
||||
target = int(pid)
|
||||
state_value = self.state.proc_state_value(target)
|
||||
if state_value == 0:
|
||||
return 0
|
||||
|
||||
path = self.state.proc_path_value(target)
|
||||
encoded_path = path.encode("utf-8", errors="replace")
|
||||
if len(encoded_path) >= PROC_PATH_MAX:
|
||||
encoded_path = encoded_path[: PROC_PATH_MAX - 1]
|
||||
path_buf = encoded_path + b"\x00" + (b"\x00" * (PROC_PATH_MAX - len(encoded_path) - 1))
|
||||
|
||||
blob = struct.pack(
|
||||
"<13Q",
|
||||
u64(target),
|
||||
u64(self.state.proc_ppid(target)),
|
||||
u64(state_value),
|
||||
u64(self.state.proc_started_tick_value(target)),
|
||||
u64(self.state.proc_exited_tick_value(target)),
|
||||
u64(self.state.proc_exit_status_value(target)),
|
||||
u64(self.state.proc_runtime_ticks(target)),
|
||||
u64(self.state.proc_mem_bytes_value(target)),
|
||||
u64(self.state.proc_tty_index_value(target)),
|
||||
u64(self.state.proc_signal(target)),
|
||||
u64(self.state.proc_fault_vector_value(target)),
|
||||
u64(self.state.proc_fault_error_value(target)),
|
||||
u64(self.state.proc_fault_rip_value(target)),
|
||||
) + path_buf
|
||||
|
||||
return 1 if self._write_guest_bytes(uc, out_ptr, blob) else 0
|
||||
|
||||
def _proc_kill(self, uc: Uc, pid: int, signal: int) -> int:
|
||||
target = int(pid)
|
||||
if target <= 0:
|
||||
return u64_neg1()
|
||||
|
||||
current_state = self.state.proc_state_value(target)
|
||||
if current_state == 0:
|
||||
return u64_neg1()
|
||||
|
||||
effective_signal = int(signal) & 0xFF
|
||||
if effective_signal == 0:
|
||||
effective_signal = SIGTERM
|
||||
|
||||
self.state.set_proc_fault(target, effective_signal, 0, 0, 0)
|
||||
|
||||
if current_state == PROC_STATE_EXITED:
|
||||
return 1
|
||||
|
||||
if effective_signal == SIGCONT:
|
||||
if current_state == PROC_STATE_STOPPED:
|
||||
self.state.set_proc_pending(target)
|
||||
return 1
|
||||
|
||||
if effective_signal == SIGSTOP and current_state in (PROC_STATE_PENDING, PROC_STATE_STOPPED):
|
||||
self.state.set_proc_stopped(target)
|
||||
return 1
|
||||
|
||||
status = self._encode_signal_status(effective_signal, 0, 0)
|
||||
|
||||
if target == self.state.get_current_pid():
|
||||
self._exit_requested = True
|
||||
self._exit_status = u64(status)
|
||||
if effective_signal == SIGSTOP:
|
||||
self.state.set_proc_stopped(target)
|
||||
uc.emu_stop()
|
||||
return 1
|
||||
|
||||
if effective_signal == SIGSTOP:
|
||||
self.state.set_proc_stopped(target)
|
||||
return 1
|
||||
|
||||
self.state.mark_exited(target, status)
|
||||
return 1
|
||||
|
||||
def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int:
|
||||
wait_ret, status = self.state.wait_pid(int(pid))
|
||||
|
||||
@@ -885,6 +1261,190 @@ class CLeonOSWineNative:
|
||||
time.sleep(0)
|
||||
return self.state.timer_ticks()
|
||||
|
||||
def _fd_open(self, uc: Uc, path_ptr: int, flags: int, mode: int) -> int:
|
||||
_ = mode
|
||||
guest_path = self._normalize_guest_path(self._read_guest_cstring(uc, path_ptr, EXEC_PATH_MAX))
|
||||
open_flags = int(u64(flags))
|
||||
lower_path = guest_path.lower()
|
||||
fd_slot: int
|
||||
entry: FDEntry
|
||||
|
||||
if not guest_path.startswith("/"):
|
||||
return u64_neg1()
|
||||
|
||||
if not self._fd_access_mode_valid(open_flags):
|
||||
return u64_neg1()
|
||||
|
||||
if ((open_flags & O_TRUNC) != 0 or (open_flags & O_APPEND) != 0) and not self._fd_can_write(open_flags):
|
||||
return u64_neg1()
|
||||
|
||||
fd_slot = self._fd_find_free()
|
||||
if fd_slot < 0:
|
||||
return u64_neg1()
|
||||
|
||||
if lower_path == "/dev/tty":
|
||||
entry = FDEntry(kind="tty", flags=open_flags, offset=0, tty_index=self._tty_index)
|
||||
self._fds[fd_slot] = entry
|
||||
return fd_slot
|
||||
|
||||
if lower_path == "/dev/null":
|
||||
entry = FDEntry(kind="dev_null", flags=open_flags, offset=0, tty_index=self._tty_index)
|
||||
self._fds[fd_slot] = entry
|
||||
return fd_slot
|
||||
|
||||
if lower_path == "/dev/zero":
|
||||
entry = FDEntry(kind="dev_zero", flags=open_flags, offset=0, tty_index=self._tty_index)
|
||||
self._fds[fd_slot] = entry
|
||||
return fd_slot
|
||||
|
||||
if lower_path == "/dev/random":
|
||||
entry = FDEntry(kind="dev_random", flags=open_flags, offset=0, tty_index=self._tty_index)
|
||||
self._fds[fd_slot] = entry
|
||||
return fd_slot
|
||||
|
||||
host_path = self._guest_to_host(guest_path, must_exist=False)
|
||||
if host_path is None:
|
||||
return u64_neg1()
|
||||
|
||||
try:
|
||||
if not host_path.exists():
|
||||
if (open_flags & O_CREAT) == 0 or not self._fd_can_write(open_flags):
|
||||
return u64_neg1()
|
||||
host_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
host_path.write_bytes(b"")
|
||||
|
||||
if host_path.is_dir():
|
||||
return u64_neg1()
|
||||
|
||||
if (open_flags & O_TRUNC) != 0:
|
||||
host_path.write_bytes(b"")
|
||||
|
||||
offset = int(host_path.stat().st_size) if (open_flags & O_APPEND) != 0 else 0
|
||||
except Exception:
|
||||
return u64_neg1()
|
||||
|
||||
entry = FDEntry(kind="file", flags=open_flags, offset=offset, path=str(host_path), tty_index=self._tty_index)
|
||||
self._fds[fd_slot] = entry
|
||||
return fd_slot
|
||||
|
||||
def _fd_read(self, uc: Uc, fd: int, out_ptr: int, size: int) -> int:
|
||||
req = int(u64(size))
|
||||
entry = self._fd_lookup(int(fd))
|
||||
data: bytes
|
||||
|
||||
if req == 0:
|
||||
return 0
|
||||
|
||||
if out_ptr == 0:
|
||||
return u64_neg1()
|
||||
|
||||
if entry is None or not self._fd_can_read(entry.flags):
|
||||
return u64_neg1()
|
||||
|
||||
req = min(req, MAX_IO_READ)
|
||||
|
||||
if entry.kind == "tty":
|
||||
out = bytearray()
|
||||
while len(out) < req:
|
||||
key = self.state.pop_key()
|
||||
if key is None:
|
||||
break
|
||||
out.append(key & 0xFF)
|
||||
data = bytes(out)
|
||||
elif entry.kind == "dev_null":
|
||||
return 0
|
||||
elif entry.kind == "dev_zero":
|
||||
data = b"\x00" * req
|
||||
elif entry.kind == "dev_random":
|
||||
data = os.urandom(req)
|
||||
elif entry.kind == "file":
|
||||
try:
|
||||
with open(entry.path, "rb") as fh:
|
||||
fh.seek(entry.offset)
|
||||
data = fh.read(req)
|
||||
except Exception:
|
||||
return u64_neg1()
|
||||
else:
|
||||
return u64_neg1()
|
||||
|
||||
if len(data) == 0:
|
||||
return 0
|
||||
|
||||
if not self._write_guest_bytes(uc, int(out_ptr), data):
|
||||
return u64_neg1()
|
||||
|
||||
entry.offset += len(data)
|
||||
return len(data)
|
||||
|
||||
def _fd_write(self, uc: Uc, fd: int, buf_ptr: int, size: int) -> int:
|
||||
req = int(u64(size))
|
||||
entry = self._fd_lookup(int(fd))
|
||||
data: Optional[bytes]
|
||||
write_pos: int
|
||||
|
||||
if req == 0:
|
||||
return 0
|
||||
|
||||
if buf_ptr == 0:
|
||||
return u64_neg1()
|
||||
|
||||
if entry is None or not self._fd_can_write(entry.flags):
|
||||
return u64_neg1()
|
||||
|
||||
req = min(req, MAX_IO_READ)
|
||||
data = self._read_guest_bytes_exact(uc, int(buf_ptr), req)
|
||||
if data is None:
|
||||
return u64_neg1()
|
||||
|
||||
if entry.kind == "tty":
|
||||
self._host_write_bytes(data)
|
||||
entry.offset += len(data)
|
||||
return len(data)
|
||||
|
||||
if entry.kind in ("dev_null", "dev_zero", "dev_random"):
|
||||
entry.offset += len(data)
|
||||
return len(data)
|
||||
|
||||
if entry.kind != "file":
|
||||
return u64_neg1()
|
||||
|
||||
try:
|
||||
host_path = Path(entry.path)
|
||||
if not host_path.exists():
|
||||
if (entry.flags & O_CREAT) == 0 or not self._fd_can_write(entry.flags):
|
||||
return u64_neg1()
|
||||
host_path.parent.mkdir(parents=True, exist_ok=True)
|
||||
host_path.write_bytes(b"")
|
||||
|
||||
with open(host_path, "r+b") as fh:
|
||||
write_pos = int(entry.offset)
|
||||
fh.seek(write_pos)
|
||||
fh.write(data)
|
||||
except Exception:
|
||||
return u64_neg1()
|
||||
|
||||
entry.offset += len(data)
|
||||
return len(data)
|
||||
|
||||
def _fd_close(self, fd: int) -> int:
|
||||
key = int(fd)
|
||||
if key not in self._fds:
|
||||
return u64_neg1()
|
||||
del self._fds[key]
|
||||
return 0
|
||||
|
||||
def _fd_dup(self, fd: int) -> int:
|
||||
src = self._fd_lookup(int(fd))
|
||||
if src is None:
|
||||
return u64_neg1()
|
||||
|
||||
slot = self._fd_find_free()
|
||||
if slot < 0:
|
||||
return u64_neg1()
|
||||
|
||||
self._fds[slot] = self._clone_fd_entry(src)
|
||||
return slot
|
||||
|
||||
@staticmethod
|
||||
def _truncate_item_text(text: str, max_bytes: int = EXEC_ITEM_MAX) -> str:
|
||||
if max_bytes <= 1:
|
||||
|
||||
@@ -6,7 +6,7 @@ import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Deque, Dict, List, Optional, Tuple
|
||||
|
||||
from .constants import u64
|
||||
from .constants import PROC_STATE_EXITED, PROC_STATE_PENDING, PROC_STATE_RUNNING, PROC_STATE_STOPPED, u64
|
||||
|
||||
|
||||
@dataclass
|
||||
@@ -37,13 +37,27 @@ class SharedKernelState:
|
||||
kbd_hotkey_switches: int = 0
|
||||
log_journal_cap: int = 256
|
||||
log_journal: Deque[str] = field(default_factory=lambda: collections.deque(maxlen=256))
|
||||
fs_write_max: int = 65536
|
||||
fs_write_max: int = 16 * 1024 * 1024
|
||||
|
||||
# syscall stats
|
||||
stats_lock: threading.Lock = field(default_factory=threading.Lock)
|
||||
stats_total_calls: int = 0
|
||||
stats_id_total: Dict[int, int] = field(default_factory=dict)
|
||||
stats_recent_window_cap: int = 256
|
||||
stats_recent_ring: Deque[int] = field(default_factory=lambda: collections.deque(maxlen=256))
|
||||
|
||||
# process table
|
||||
proc_lock: threading.Lock = field(default_factory=threading.Lock)
|
||||
proc_next_pid: int = 1
|
||||
proc_current_pid: int = 0
|
||||
proc_parents: Dict[int, int] = field(default_factory=dict)
|
||||
proc_status: Dict[int, Optional[int]] = field(default_factory=dict)
|
||||
proc_state: Dict[int, int] = field(default_factory=dict)
|
||||
proc_started_tick: Dict[int, int] = field(default_factory=dict)
|
||||
proc_exited_tick: Dict[int, int] = field(default_factory=dict)
|
||||
proc_mem_bytes: Dict[int, int] = field(default_factory=dict)
|
||||
proc_tty_index: Dict[int, int] = field(default_factory=dict)
|
||||
proc_path: Dict[int, str] = field(default_factory=dict)
|
||||
proc_argv: Dict[int, List[str]] = field(default_factory=dict)
|
||||
proc_env: Dict[int, List[str]] = field(default_factory=dict)
|
||||
proc_last_signal: Dict[int, int] = field(default_factory=dict)
|
||||
@@ -54,6 +68,32 @@ class SharedKernelState:
|
||||
def timer_ticks(self) -> int:
|
||||
return (time.monotonic_ns() - self.start_ns) // 1_000_000
|
||||
|
||||
def record_syscall(self, sid: int) -> None:
|
||||
key = int(u64(sid))
|
||||
|
||||
with self.stats_lock:
|
||||
self.stats_total_calls = int(u64(self.stats_total_calls + 1))
|
||||
self.stats_id_total[key] = int(u64(self.stats_id_total.get(key, 0) + 1))
|
||||
self.stats_recent_ring.append(key)
|
||||
|
||||
def stats_total(self) -> int:
|
||||
with self.stats_lock:
|
||||
return int(self.stats_total_calls)
|
||||
|
||||
def stats_id_count(self, sid: int) -> int:
|
||||
key = int(u64(sid))
|
||||
with self.stats_lock:
|
||||
return int(self.stats_id_total.get(key, 0))
|
||||
|
||||
def stats_recent_window(self) -> int:
|
||||
with self.stats_lock:
|
||||
return len(self.stats_recent_ring)
|
||||
|
||||
def stats_recent_id_count(self, sid: int) -> int:
|
||||
key = int(u64(sid))
|
||||
with self.stats_lock:
|
||||
return sum(1 for item in self.stats_recent_ring if item == key)
|
||||
|
||||
def push_key(self, key: int) -> None:
|
||||
with self.kbd_lock:
|
||||
if len(self.kbd_queue) >= self.kbd_queue_cap:
|
||||
@@ -94,6 +134,8 @@ class SharedKernelState:
|
||||
return list(self.log_journal)[index_from_oldest]
|
||||
|
||||
def alloc_pid(self, ppid: int) -> int:
|
||||
now = self.timer_ticks()
|
||||
|
||||
with self.proc_lock:
|
||||
pid = int(self.proc_next_pid)
|
||||
|
||||
@@ -107,6 +149,12 @@ class SharedKernelState:
|
||||
|
||||
self.proc_parents[pid] = int(ppid)
|
||||
self.proc_status[pid] = None
|
||||
self.proc_state[pid] = PROC_STATE_PENDING
|
||||
self.proc_started_tick[pid] = now
|
||||
self.proc_exited_tick[pid] = 0
|
||||
self.proc_mem_bytes[pid] = 0
|
||||
self.proc_tty_index[pid] = int(self.tty_active)
|
||||
self.proc_path[pid] = ""
|
||||
self.proc_argv[pid] = []
|
||||
self.proc_env[pid] = []
|
||||
self.proc_last_signal[pid] = 0
|
||||
@@ -123,12 +171,51 @@ class SharedKernelState:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_current_pid)
|
||||
|
||||
def set_proc_running(self, pid: int, path: Optional[str], tty_index: int) -> None:
|
||||
if pid <= 0:
|
||||
return
|
||||
|
||||
now = self.timer_ticks()
|
||||
|
||||
with self.proc_lock:
|
||||
if pid not in self.proc_status:
|
||||
return
|
||||
|
||||
self.proc_state[pid] = PROC_STATE_RUNNING
|
||||
if self.proc_started_tick.get(pid, 0) == 0:
|
||||
self.proc_started_tick[pid] = now
|
||||
self.proc_tty_index[pid] = int(tty_index)
|
||||
if path:
|
||||
self.proc_path[pid] = str(path)
|
||||
|
||||
def mark_exited(self, pid: int, status: int) -> None:
|
||||
if pid <= 0:
|
||||
return
|
||||
|
||||
with self.proc_lock:
|
||||
self.proc_status[int(pid)] = int(u64(status))
|
||||
self.proc_state[int(pid)] = PROC_STATE_EXITED
|
||||
self.proc_exited_tick[int(pid)] = self.timer_ticks()
|
||||
|
||||
def set_proc_stopped(self, pid: int) -> None:
|
||||
if pid <= 0:
|
||||
return
|
||||
|
||||
with self.proc_lock:
|
||||
if pid not in self.proc_status:
|
||||
return
|
||||
if self.proc_state.get(pid, PROC_STATE_PENDING) != PROC_STATE_EXITED:
|
||||
self.proc_state[pid] = PROC_STATE_STOPPED
|
||||
|
||||
def set_proc_pending(self, pid: int) -> None:
|
||||
if pid <= 0:
|
||||
return
|
||||
|
||||
with self.proc_lock:
|
||||
if pid not in self.proc_status:
|
||||
return
|
||||
if self.proc_state.get(pid, PROC_STATE_PENDING) != PROC_STATE_EXITED:
|
||||
self.proc_state[pid] = PROC_STATE_PENDING
|
||||
|
||||
def wait_pid(self, pid: int) -> Tuple[int, int]:
|
||||
with self.proc_lock:
|
||||
@@ -151,6 +238,8 @@ class SharedKernelState:
|
||||
return
|
||||
self.proc_argv[pid] = [str(item) for item in argv]
|
||||
self.proc_env[pid] = [str(item) for item in env]
|
||||
if argv:
|
||||
self.proc_path[pid] = str(argv[0])
|
||||
|
||||
def set_proc_fault(self, pid: int, signal: int, vector: int, error_code: int, rip: int) -> None:
|
||||
if pid <= 0:
|
||||
@@ -164,6 +253,68 @@ class SharedKernelState:
|
||||
self.proc_fault_error[pid] = int(u64(error_code))
|
||||
self.proc_fault_rip[pid] = int(u64(rip))
|
||||
|
||||
def proc_count(self) -> int:
|
||||
with self.proc_lock:
|
||||
return len(self.proc_status)
|
||||
|
||||
def proc_pid_at(self, index: int) -> Optional[int]:
|
||||
if index < 0:
|
||||
return None
|
||||
|
||||
with self.proc_lock:
|
||||
ordered = sorted(self.proc_status.keys())
|
||||
if index >= len(ordered):
|
||||
return None
|
||||
return int(ordered[index])
|
||||
|
||||
def proc_state_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_state.get(int(pid), 0))
|
||||
|
||||
def proc_ppid(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_parents.get(int(pid), 0))
|
||||
|
||||
def proc_started_tick_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_started_tick.get(int(pid), 0))
|
||||
|
||||
def proc_exited_tick_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_exited_tick.get(int(pid), 0))
|
||||
|
||||
def proc_exit_status_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
value = self.proc_status.get(int(pid))
|
||||
return int(value) if value is not None else 0
|
||||
|
||||
def proc_runtime_ticks(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
start = int(self.proc_started_tick.get(int(pid), 0))
|
||||
state = int(self.proc_state.get(int(pid), 0))
|
||||
end = int(self.proc_exited_tick.get(int(pid), 0))
|
||||
|
||||
if start == 0:
|
||||
return 0
|
||||
|
||||
if state == PROC_STATE_EXITED and end >= start:
|
||||
return end - start
|
||||
|
||||
now = self.timer_ticks()
|
||||
return 0 if now < start else now - start
|
||||
|
||||
def proc_mem_bytes_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_mem_bytes.get(int(pid), 0))
|
||||
|
||||
def proc_tty_index_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_tty_index.get(int(pid), 0))
|
||||
|
||||
def proc_path_value(self, pid: int) -> str:
|
||||
with self.proc_lock:
|
||||
return str(self.proc_path.get(int(pid), ""))
|
||||
|
||||
def proc_argc(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return len(self.proc_argv.get(int(pid), []))
|
||||
|
||||
Reference in New Issue
Block a user