mirror of
https://github.com/Leonmmcoset/cleonos.git
synced 2026-04-21 10:40:00 +00:00
ABI
This commit is contained in:
@@ -37,15 +37,31 @@ python wine/cleonos_wine.py build/x86_64/ramdisk_root/shell/shell.elf --rootfs b
|
||||
## 支持
|
||||
|
||||
- ELF64 (x86_64) PT_LOAD 段装载
|
||||
- CLeonOS `int 0x80` syscall 0..45
|
||||
- CLeonOS `int 0x80` syscall 0..60
|
||||
- TTY 输出与键盘输入队列
|
||||
- rootfs 文件/目录访问(`FS_*`)
|
||||
- `/temp` 写入限制(`FS_MKDIR/WRITE/APPEND/REMOVE`)
|
||||
- `EXEC_PATH` 递归执行 ELF(带深度限制)
|
||||
- 进程生命周期 syscall(`GETPID/SPAWN_PATH/WAITPID/EXIT/SLEEP_TICKS/YIELD`)
|
||||
- `EXEC_PATH/EXEC_PATHV` 执行 ELF(带深度限制)
|
||||
- `SPAWN_PATH/SPAWN_PATHV/WAITPID/EXIT/SLEEP_TICKS/YIELD`
|
||||
- 进程 `argv/env` 查询(`PROC_ARGC/PROC_ARGV/PROC_ENVC/PROC_ENV`)
|
||||
- 异常退出状态编码与故障元信息(`PROC_LAST_SIGNAL/PROC_FAULT_*`)
|
||||
|
||||
## 参数
|
||||
|
||||
- `--no-kbd`:关闭输入线程
|
||||
- `--max-exec-depth N`:设置 exec 嵌套深度上限
|
||||
- `--verbose`:打印更多日志`n
|
||||
- `--verbose`:打印更多日志
|
||||
|
||||
## `execv/spawnv` 参数格式
|
||||
|
||||
- `argv_line`:按空白字符分词(与内核当前实现一致,不支持引号转义)。
|
||||
- `env_line`:按 `;` 或换行切分环境变量项,会去掉每项末尾空白。
|
||||
- 子进程 `argv[0]` 固定为目标程序路径(如 `/shell/ls.elf`)。
|
||||
|
||||
## 退出状态说明
|
||||
|
||||
- 正常退出:返回普通退出码。
|
||||
- 异常退出:最高位为 `1`,并编码:
|
||||
- bits `7:0` = signal
|
||||
- bits `15:8` = CPU exception vector
|
||||
- bits `31:16` = error code 低 16 位
|
||||
|
||||
BIN
wine/__pycache__/cleonos_wine.cpython-313.pyc
Normal file
BIN
wine/__pycache__/cleonos_wine.cpython-313.pyc
Normal file
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -56,6 +56,19 @@ SYS_SLEEP_TICKS = 44
|
||||
SYS_YIELD = 45
|
||||
SYS_SHUTDOWN = 46
|
||||
SYS_RESTART = 47
|
||||
SYS_AUDIO_AVAILABLE = 48
|
||||
SYS_AUDIO_PLAY_TONE = 49
|
||||
SYS_AUDIO_STOP = 50
|
||||
SYS_EXEC_PATHV = 51
|
||||
SYS_SPAWN_PATHV = 52
|
||||
SYS_PROC_ARGC = 53
|
||||
SYS_PROC_ARGV = 54
|
||||
SYS_PROC_ENVC = 55
|
||||
SYS_PROC_ENV = 56
|
||||
SYS_PROC_LAST_SIGNAL = 57
|
||||
SYS_PROC_FAULT_VECTOR = 58
|
||||
SYS_PROC_FAULT_ERROR = 59
|
||||
SYS_PROC_FAULT_RIP = 60
|
||||
|
||||
|
||||
def u64(value: int) -> int:
|
||||
@@ -71,4 +84,4 @@ def page_floor(addr: int) -> int:
|
||||
|
||||
|
||||
def page_ceil(addr: int) -> int:
|
||||
return (addr + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)
|
||||
return (addr + PAGE_SIZE - 1) & ~(PAGE_SIZE - 1)
|
||||
|
||||
@@ -7,12 +7,22 @@ try:
|
||||
from unicorn import UC_ARCH_X86, UC_MODE_64
|
||||
from unicorn import UC_HOOK_CODE, UC_HOOK_INTR
|
||||
from unicorn import UC_PROT_ALL, UC_PROT_EXEC, UC_PROT_READ, UC_PROT_WRITE
|
||||
from unicorn import (
|
||||
UC_ERR_FETCH_PROT,
|
||||
UC_ERR_FETCH_UNMAPPED,
|
||||
UC_ERR_INSN_INVALID,
|
||||
UC_ERR_READ_PROT,
|
||||
UC_ERR_READ_UNMAPPED,
|
||||
UC_ERR_WRITE_PROT,
|
||||
UC_ERR_WRITE_UNMAPPED,
|
||||
)
|
||||
from unicorn.x86_const import (
|
||||
UC_X86_REG_RAX,
|
||||
UC_X86_REG_RBX,
|
||||
UC_X86_REG_RCX,
|
||||
UC_X86_REG_RDX,
|
||||
UC_X86_REG_RBP,
|
||||
UC_X86_REG_RIP,
|
||||
UC_X86_REG_RSP,
|
||||
)
|
||||
except Exception as exc:
|
||||
@@ -32,10 +42,18 @@ __all__ = [
|
||||
"UC_PROT_EXEC",
|
||||
"UC_PROT_READ",
|
||||
"UC_PROT_WRITE",
|
||||
"UC_ERR_FETCH_PROT",
|
||||
"UC_ERR_FETCH_UNMAPPED",
|
||||
"UC_ERR_INSN_INVALID",
|
||||
"UC_ERR_READ_PROT",
|
||||
"UC_ERR_READ_UNMAPPED",
|
||||
"UC_ERR_WRITE_PROT",
|
||||
"UC_ERR_WRITE_UNMAPPED",
|
||||
"UC_X86_REG_RAX",
|
||||
"UC_X86_REG_RBX",
|
||||
"UC_X86_REG_RCX",
|
||||
"UC_X86_REG_RDX",
|
||||
"UC_X86_REG_RBP",
|
||||
"UC_X86_REG_RIP",
|
||||
"UC_X86_REG_RSP",
|
||||
]
|
||||
]
|
||||
|
||||
@@ -14,15 +14,28 @@ from .constants import (
|
||||
MAX_CSTR,
|
||||
MAX_IO_READ,
|
||||
PAGE_SIZE,
|
||||
SYS_AUDIO_AVAILABLE,
|
||||
SYS_AUDIO_PLAY_TONE,
|
||||
SYS_AUDIO_STOP,
|
||||
SYS_CONTEXT_SWITCHES,
|
||||
SYS_CUR_TASK,
|
||||
SYS_EXEC_PATH,
|
||||
SYS_EXEC_PATHV,
|
||||
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,
|
||||
@@ -72,6 +85,13 @@ from .platform import (
|
||||
Uc,
|
||||
UcError,
|
||||
UC_ARCH_X86,
|
||||
UC_ERR_FETCH_PROT,
|
||||
UC_ERR_FETCH_UNMAPPED,
|
||||
UC_ERR_INSN_INVALID,
|
||||
UC_ERR_READ_PROT,
|
||||
UC_ERR_READ_UNMAPPED,
|
||||
UC_ERR_WRITE_PROT,
|
||||
UC_ERR_WRITE_UNMAPPED,
|
||||
UC_HOOK_CODE,
|
||||
UC_HOOK_INTR,
|
||||
UC_MODE_64,
|
||||
@@ -85,6 +105,7 @@ from .platform import (
|
||||
UC_X86_REG_RCX,
|
||||
UC_X86_REG_RDX,
|
||||
UC_X86_REG_RSP,
|
||||
UC_X86_REG_RIP,
|
||||
)
|
||||
from .state import SharedKernelState
|
||||
|
||||
@@ -103,6 +124,15 @@ class ELFImage:
|
||||
segments: List[ELFSegment]
|
||||
|
||||
|
||||
EXEC_PATH_MAX = 192
|
||||
EXEC_ARG_LINE_MAX = 256
|
||||
EXEC_ENV_LINE_MAX = 512
|
||||
EXEC_MAX_ARGS = 24
|
||||
EXEC_MAX_ENVS = 24
|
||||
EXEC_ITEM_MAX = 128
|
||||
EXEC_STATUS_SIGNAL_FLAG = 1 << 63
|
||||
|
||||
|
||||
class CLeonOSWineNative:
|
||||
def __init__(
|
||||
self,
|
||||
@@ -118,6 +148,8 @@ class CLeonOSWineNative:
|
||||
top_level: bool = True,
|
||||
pid: int = 0,
|
||||
ppid: int = 0,
|
||||
argv_items: Optional[List[str]] = None,
|
||||
env_items: Optional[List[str]] = None,
|
||||
) -> None:
|
||||
self.elf_path = elf_path
|
||||
self.rootfs = rootfs
|
||||
@@ -130,6 +162,8 @@ class CLeonOSWineNative:
|
||||
self.top_level = top_level
|
||||
self.pid = int(pid)
|
||||
self.ppid = int(ppid)
|
||||
self.argv_items = list(argv_items) if argv_items is not None else []
|
||||
self.env_items = list(env_items) if env_items is not None else []
|
||||
self._exit_requested = False
|
||||
self._exit_status = 0
|
||||
|
||||
@@ -142,12 +176,17 @@ class CLeonOSWineNative:
|
||||
self._ret_sentinel = 0x00007FFF10000000
|
||||
self._mapped_ranges: List[Tuple[int, int]] = []
|
||||
|
||||
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)
|
||||
|
||||
def run(self) -> Optional[int]:
|
||||
if self.pid == 0:
|
||||
self.pid = self.state.alloc_pid(self.ppid)
|
||||
|
||||
prev_pid = self.state.get_current_pid()
|
||||
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)
|
||||
|
||||
uc = Uc(UC_ARCH_X86, UC_MODE_64)
|
||||
self._install_hooks(uc)
|
||||
@@ -158,27 +197,31 @@ class CLeonOSWineNative:
|
||||
self._input_pump = InputPump(self.state)
|
||||
self._input_pump.start()
|
||||
|
||||
run_failed = False
|
||||
interrupted = False
|
||||
runtime_fault_status: Optional[int] = None
|
||||
|
||||
try:
|
||||
uc.emu_start(self.image.entry, 0)
|
||||
except KeyboardInterrupt:
|
||||
run_failed = True
|
||||
interrupted = True
|
||||
if self.top_level:
|
||||
print("\n[WINE] interrupted by user", file=sys.stderr)
|
||||
except UcError as exc:
|
||||
run_failed = True
|
||||
runtime_fault_status = self._status_from_uc_error(uc, exc)
|
||||
if self.verbose or self.top_level:
|
||||
print(f"[WINE][ERROR] runtime crashed: {exc}", file=sys.stderr)
|
||||
finally:
|
||||
if self.top_level and self._input_pump is not None:
|
||||
self._input_pump.stop()
|
||||
|
||||
if run_failed:
|
||||
if interrupted:
|
||||
self.state.mark_exited(self.pid, u64_neg1())
|
||||
self.state.set_current_pid(prev_pid)
|
||||
return None
|
||||
|
||||
if runtime_fault_status is not None:
|
||||
self.exit_code = runtime_fault_status
|
||||
|
||||
if self.exit_code is None:
|
||||
self.exit_code = self._reg_read(uc, UC_X86_REG_RAX)
|
||||
|
||||
@@ -246,18 +289,44 @@ class CLeonOSWineNative:
|
||||
return self._fs_read(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_EXEC_PATH:
|
||||
return self._exec_path(uc, arg0)
|
||||
if sid == SYS_EXEC_PATHV:
|
||||
return self._exec_pathv(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_SPAWN_PATH:
|
||||
return self._spawn_path(uc, arg0)
|
||||
if sid == SYS_SPAWN_PATHV:
|
||||
return self._spawn_pathv(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_WAITPID:
|
||||
return self._wait_pid(uc, arg0, arg1)
|
||||
if sid == SYS_GETPID:
|
||||
return self.state.get_current_pid()
|
||||
if sid == SYS_PROC_ARGC:
|
||||
return self._proc_argc()
|
||||
if sid == SYS_PROC_ARGV:
|
||||
return self._proc_argv(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_PROC_ENVC:
|
||||
return self._proc_envc()
|
||||
if sid == SYS_PROC_ENV:
|
||||
return self._proc_env(uc, arg0, arg1, arg2)
|
||||
if sid == SYS_PROC_LAST_SIGNAL:
|
||||
return self._proc_last_signal()
|
||||
if sid == SYS_PROC_FAULT_VECTOR:
|
||||
return self._proc_fault_vector()
|
||||
if sid == SYS_PROC_FAULT_ERROR:
|
||||
return self._proc_fault_error()
|
||||
if sid == SYS_PROC_FAULT_RIP:
|
||||
return self._proc_fault_rip()
|
||||
if sid == SYS_EXIT:
|
||||
return self._request_exit(uc, arg0)
|
||||
if sid == SYS_SLEEP_TICKS:
|
||||
return self._sleep_ticks(arg0)
|
||||
if sid == SYS_YIELD:
|
||||
return self._yield_once()
|
||||
if sid == SYS_AUDIO_AVAILABLE:
|
||||
return 0
|
||||
if sid == SYS_AUDIO_PLAY_TONE:
|
||||
return 0
|
||||
if sid == SYS_AUDIO_STOP:
|
||||
return 1
|
||||
if sid == SYS_SHUTDOWN:
|
||||
self._host_write("\n[WINE] shutdown requested by guest\n")
|
||||
self._exit_requested = True
|
||||
@@ -674,14 +743,30 @@ 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, return_pid=False)
|
||||
return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=False)
|
||||
|
||||
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)
|
||||
|
||||
def _spawn_path(self, uc: Uc, path_ptr: int) -> int:
|
||||
return self._spawn_path_common(uc, path_ptr, return_pid=True)
|
||||
return self._spawn_path_common(uc, path_ptr, 0, 0, return_pid=True)
|
||||
|
||||
def _spawn_path_common(self, uc: Uc, path_ptr: int, *, return_pid: bool) -> int:
|
||||
path = self._read_guest_cstring(uc, path_ptr)
|
||||
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)
|
||||
|
||||
def _spawn_path_common(
|
||||
self,
|
||||
uc: Uc,
|
||||
path_ptr: int,
|
||||
argv_ptr: int,
|
||||
env_ptr: int,
|
||||
*,
|
||||
return_pid: bool,
|
||||
) -> 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 ""
|
||||
host_path = self._guest_to_host(guest_path, must_exist=True)
|
||||
|
||||
self.state.exec_requests = u64(self.state.exec_requests + 1)
|
||||
@@ -699,6 +784,9 @@ class CLeonOSWineNative:
|
||||
|
||||
parent_pid = self.state.get_current_pid()
|
||||
child_pid = self.state.alloc_pid(parent_pid)
|
||||
argv_items, env_items = self._build_child_exec_items(guest_path, argv_line, env_line)
|
||||
self.state.set_proc_cmdline(child_pid, argv_items, env_items)
|
||||
self.state.set_proc_fault(child_pid, 0, 0, 0, 0)
|
||||
|
||||
child = CLeonOSWineNative(
|
||||
elf_path=host_path,
|
||||
@@ -712,6 +800,8 @@ class CLeonOSWineNative:
|
||||
top_level=False,
|
||||
pid=child_pid,
|
||||
ppid=parent_pid,
|
||||
argv_items=argv_items,
|
||||
env_items=env_items,
|
||||
)
|
||||
child_ret = child.run()
|
||||
|
||||
@@ -728,7 +818,41 @@ class CLeonOSWineNative:
|
||||
if return_pid:
|
||||
return child_pid
|
||||
|
||||
return 0
|
||||
return u64(child_ret)
|
||||
|
||||
def _proc_argc(self) -> int:
|
||||
return self.state.proc_argc(self.state.get_current_pid())
|
||||
|
||||
def _proc_argv(self, uc: Uc, index: int, out_ptr: int, out_size: int) -> int:
|
||||
return self._copy_proc_item_to_guest(
|
||||
uc,
|
||||
self.state.proc_argv_item(self.state.get_current_pid(), int(index)),
|
||||
out_ptr,
|
||||
out_size,
|
||||
)
|
||||
|
||||
def _proc_envc(self) -> int:
|
||||
return self.state.proc_envc(self.state.get_current_pid())
|
||||
|
||||
def _proc_env(self, uc: Uc, index: int, out_ptr: int, out_size: int) -> int:
|
||||
return self._copy_proc_item_to_guest(
|
||||
uc,
|
||||
self.state.proc_env_item(self.state.get_current_pid(), int(index)),
|
||||
out_ptr,
|
||||
out_size,
|
||||
)
|
||||
|
||||
def _proc_last_signal(self) -> int:
|
||||
return self.state.proc_signal(self.state.get_current_pid())
|
||||
|
||||
def _proc_fault_vector(self) -> int:
|
||||
return self.state.proc_fault_vector_value(self.state.get_current_pid())
|
||||
|
||||
def _proc_fault_error(self) -> int:
|
||||
return self.state.proc_fault_error_value(self.state.get_current_pid())
|
||||
|
||||
def _proc_fault_rip(self) -> int:
|
||||
return self.state.proc_fault_rip_value(self.state.get_current_pid())
|
||||
|
||||
def _wait_pid(self, uc: Uc, pid: int, out_ptr: int) -> int:
|
||||
wait_ret, status = self.state.wait_pid(int(pid))
|
||||
@@ -761,6 +885,157 @@ class CLeonOSWineNative:
|
||||
time.sleep(0)
|
||||
return self.state.timer_ticks()
|
||||
|
||||
@staticmethod
|
||||
def _truncate_item_text(text: str, max_bytes: int = EXEC_ITEM_MAX) -> str:
|
||||
if max_bytes <= 1:
|
||||
return ""
|
||||
encoded = (text or "").encode("utf-8", errors="replace")
|
||||
if len(encoded) >= max_bytes:
|
||||
encoded = encoded[: max_bytes - 1]
|
||||
return encoded.decode("utf-8", errors="ignore")
|
||||
|
||||
@staticmethod
|
||||
def _parse_whitespace_items(line: str, max_count: int) -> List[str]:
|
||||
out: List[str] = []
|
||||
i = 0
|
||||
text = line or ""
|
||||
length = len(text)
|
||||
|
||||
while i < length:
|
||||
while i < length and text[i] in (" ", "\t", "\r", "\n"):
|
||||
i += 1
|
||||
if i >= length:
|
||||
break
|
||||
start = i
|
||||
while i < length and text[i] not in (" ", "\t", "\r", "\n"):
|
||||
i += 1
|
||||
out.append(text[start:i])
|
||||
if len(out) >= max_count:
|
||||
break
|
||||
|
||||
return out
|
||||
|
||||
@staticmethod
|
||||
def _parse_env_items(line: str, max_count: int) -> List[str]:
|
||||
out: List[str] = []
|
||||
i = 0
|
||||
text = line or ""
|
||||
length = len(text)
|
||||
|
||||
while i < length:
|
||||
while i < length and text[i] in (" ", "\t", ";", "\r", "\n"):
|
||||
i += 1
|
||||
if i >= length:
|
||||
break
|
||||
|
||||
start = i
|
||||
while i < length and text[i] not in (";", "\r", "\n"):
|
||||
i += 1
|
||||
value = text[start:i].rstrip(" \t")
|
||||
if value:
|
||||
out.append(value)
|
||||
if len(out) >= max_count:
|
||||
break
|
||||
|
||||
return out
|
||||
|
||||
@classmethod
|
||||
def _prepare_exec_items(cls, path: str, argv_items: List[str], env_items: List[str]) -> Tuple[List[str], List[str]]:
|
||||
normalized_path = cls._normalize_guest_path(path)
|
||||
|
||||
prepared_argv: List[str] = []
|
||||
for item in argv_items[:EXEC_MAX_ARGS]:
|
||||
value = cls._truncate_item_text(item)
|
||||
if value:
|
||||
prepared_argv.append(value)
|
||||
|
||||
if not prepared_argv:
|
||||
prepared_argv = [cls._truncate_item_text(normalized_path)]
|
||||
elif prepared_argv[0] == "":
|
||||
prepared_argv[0] = cls._truncate_item_text(normalized_path)
|
||||
|
||||
prepared_env: List[str] = []
|
||||
for item in env_items[:EXEC_MAX_ENVS]:
|
||||
value = cls._truncate_item_text(item)
|
||||
if value:
|
||||
prepared_env.append(value)
|
||||
|
||||
return prepared_argv[:EXEC_MAX_ARGS], prepared_env[:EXEC_MAX_ENVS]
|
||||
|
||||
@classmethod
|
||||
def _build_child_exec_items(cls, guest_path: str, argv_line: str, env_line: str) -> Tuple[List[str], List[str]]:
|
||||
argv_items = [guest_path]
|
||||
argv_items.extend(cls._parse_whitespace_items(argv_line or "", EXEC_MAX_ARGS - 1))
|
||||
env_items = cls._parse_env_items(env_line or "", EXEC_MAX_ENVS)
|
||||
return cls._prepare_exec_items(guest_path, argv_items, env_items)
|
||||
|
||||
def _copy_proc_item_to_guest(self, uc: Uc, item: Optional[str], out_ptr: int, out_size: int) -> int:
|
||||
if out_ptr == 0 or out_size == 0 or item is None:
|
||||
return 0
|
||||
|
||||
max_out = int(min(int(out_size), EXEC_ITEM_MAX))
|
||||
if max_out <= 0:
|
||||
return 0
|
||||
|
||||
encoded = self._truncate_item_text(item, max_out + 1).encode("utf-8", errors="replace")
|
||||
if len(encoded) >= max_out:
|
||||
encoded = encoded[: max_out - 1]
|
||||
|
||||
return 1 if self._write_guest_bytes(uc, out_ptr, encoded + b"\x00") else 0
|
||||
|
||||
@staticmethod
|
||||
def _signal_from_vector(vector: int) -> int:
|
||||
if vector in (0, 16, 19):
|
||||
return 8
|
||||
if vector == 6:
|
||||
return 4
|
||||
if vector == 3:
|
||||
return 5
|
||||
if vector in (10, 11, 12, 13, 14, 17):
|
||||
return 11
|
||||
return 6
|
||||
|
||||
@staticmethod
|
||||
def _encode_signal_status(signal: int, vector: int, error_code: int) -> int:
|
||||
return u64(
|
||||
EXEC_STATUS_SIGNAL_FLAG
|
||||
| (int(signal) & 0xFF)
|
||||
| ((int(vector) & 0xFF) << 8)
|
||||
| ((int(error_code) & 0xFFFF) << 16)
|
||||
)
|
||||
|
||||
def _status_from_uc_error(self, uc: Uc, exc: UcError) -> int:
|
||||
errno = int(getattr(exc, "errno", 0))
|
||||
vector = 13
|
||||
error_code = 0
|
||||
|
||||
if errno in (UC_ERR_READ_UNMAPPED, UC_ERR_WRITE_UNMAPPED, UC_ERR_FETCH_UNMAPPED):
|
||||
vector = 14
|
||||
if errno == UC_ERR_WRITE_UNMAPPED:
|
||||
error_code = 0x2
|
||||
elif errno == UC_ERR_FETCH_UNMAPPED:
|
||||
error_code = 0x10
|
||||
elif errno in (UC_ERR_READ_PROT, UC_ERR_WRITE_PROT, UC_ERR_FETCH_PROT):
|
||||
vector = 14
|
||||
error_code = 0x1
|
||||
if errno == UC_ERR_WRITE_PROT:
|
||||
error_code |= 0x2
|
||||
elif errno == UC_ERR_FETCH_PROT:
|
||||
error_code |= 0x10
|
||||
elif errno == UC_ERR_INSN_INVALID:
|
||||
vector = 6
|
||||
error_code = 0
|
||||
|
||||
rip = 0
|
||||
try:
|
||||
rip = self._reg_read(uc, UC_X86_REG_RIP)
|
||||
except Exception:
|
||||
rip = 0
|
||||
|
||||
signal = self._signal_from_vector(vector)
|
||||
self.state.set_proc_fault(self.pid, signal, vector, error_code, rip)
|
||||
return self._encode_signal_status(signal, vector, error_code)
|
||||
|
||||
def _guest_to_host(self, guest_path: str, *, must_exist: bool) -> Optional[Path]:
|
||||
norm = self._normalize_guest_path(guest_path)
|
||||
if norm == "/":
|
||||
|
||||
@@ -4,7 +4,7 @@ import collections
|
||||
import threading
|
||||
import time
|
||||
from dataclasses import dataclass, field
|
||||
from typing import Deque, Dict, Optional, Tuple
|
||||
from typing import Deque, Dict, List, Optional, Tuple
|
||||
|
||||
from .constants import u64
|
||||
|
||||
@@ -44,6 +44,12 @@ class SharedKernelState:
|
||||
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_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)
|
||||
proc_fault_vector: Dict[int, int] = field(default_factory=dict)
|
||||
proc_fault_error: Dict[int, int] = field(default_factory=dict)
|
||||
proc_fault_rip: Dict[int, int] = field(default_factory=dict)
|
||||
|
||||
def timer_ticks(self) -> int:
|
||||
return (time.monotonic_ns() - self.start_ns) // 1_000_000
|
||||
@@ -101,6 +107,12 @@ class SharedKernelState:
|
||||
|
||||
self.proc_parents[pid] = int(ppid)
|
||||
self.proc_status[pid] = None
|
||||
self.proc_argv[pid] = []
|
||||
self.proc_env[pid] = []
|
||||
self.proc_last_signal[pid] = 0
|
||||
self.proc_fault_vector[pid] = 0
|
||||
self.proc_fault_error[pid] = 0
|
||||
self.proc_fault_rip[pid] = 0
|
||||
return pid
|
||||
|
||||
def set_current_pid(self, pid: int) -> None:
|
||||
@@ -128,4 +140,64 @@ class SharedKernelState:
|
||||
if status is None:
|
||||
return 0, 0
|
||||
|
||||
return 1, int(status)
|
||||
return 1, int(status)
|
||||
|
||||
def set_proc_cmdline(self, pid: int, argv: List[str], env: List[str]) -> None:
|
||||
if pid <= 0:
|
||||
return
|
||||
|
||||
with self.proc_lock:
|
||||
if pid not in self.proc_status:
|
||||
return
|
||||
self.proc_argv[pid] = [str(item) for item in argv]
|
||||
self.proc_env[pid] = [str(item) for item in env]
|
||||
|
||||
def set_proc_fault(self, pid: int, signal: int, vector: int, error_code: int, rip: int) -> None:
|
||||
if pid <= 0:
|
||||
return
|
||||
|
||||
with self.proc_lock:
|
||||
if pid not in self.proc_status:
|
||||
return
|
||||
self.proc_last_signal[pid] = int(u64(signal))
|
||||
self.proc_fault_vector[pid] = int(u64(vector))
|
||||
self.proc_fault_error[pid] = int(u64(error_code))
|
||||
self.proc_fault_rip[pid] = int(u64(rip))
|
||||
|
||||
def proc_argc(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return len(self.proc_argv.get(int(pid), []))
|
||||
|
||||
def proc_argv_item(self, pid: int, index: int) -> Optional[str]:
|
||||
with self.proc_lock:
|
||||
values = self.proc_argv.get(int(pid), [])
|
||||
if index < 0 or index >= len(values):
|
||||
return None
|
||||
return values[index]
|
||||
|
||||
def proc_envc(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return len(self.proc_env.get(int(pid), []))
|
||||
|
||||
def proc_env_item(self, pid: int, index: int) -> Optional[str]:
|
||||
with self.proc_lock:
|
||||
values = self.proc_env.get(int(pid), [])
|
||||
if index < 0 or index >= len(values):
|
||||
return None
|
||||
return values[index]
|
||||
|
||||
def proc_signal(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_last_signal.get(int(pid), 0))
|
||||
|
||||
def proc_fault_vector_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_fault_vector.get(int(pid), 0))
|
||||
|
||||
def proc_fault_error_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_fault_error.get(int(pid), 0))
|
||||
|
||||
def proc_fault_rip_value(self, pid: int) -> int:
|
||||
with self.proc_lock:
|
||||
return int(self.proc_fault_rip.get(int(pid), 0))
|
||||
|
||||
Reference in New Issue
Block a user