diff options
| author | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-26 18:55:34 +0000 |
|---|---|---|
| committer | Theofilos Augoustis <theofilos.augoustis@gmail.com> | 2025-11-26 18:55:34 +0000 |
| commit | c2d148ae047b5b502a9845bc7b0d65be5bc07c43 (patch) | |
| tree | 4e653c6d44fafcb8db7c432aaf1637b54f9e30a8 | |
| parent | 2fc64bd52c8da2c949ba6c62619ce41c71c5e976 (diff) | |
| download | focaccia-c2d148ae047b5b502a9845bc7b0d65be5bc07c43.tar.gz focaccia-c2d148ae047b5b502a9845bc7b0d65be5bc07c43.zip | |
Add support for signal handling
| -rw-r--r-- | src/focaccia/qemu/syscall.py | 4 | ||||
| -rw-r--r-- | src/focaccia/qemu/target.py | 36 | ||||
| -rw-r--r-- | src/focaccia/qemu/x86.py | 2 |
3 files changed, 37 insertions, 5 deletions
diff --git a/src/focaccia/qemu/syscall.py b/src/focaccia/qemu/syscall.py index 6f54641..34b828b 100644 --- a/src/focaccia/qemu/syscall.py +++ b/src/focaccia/qemu/syscall.py @@ -4,7 +4,8 @@ class SyscallInfo: patchup_registers: list[str] | None = None, patchup_address_registers: list[str] | None = None, creates_thread: bool = False, - return_from_signal: bool = False): + return_from_signal: bool = False, + sets_signal_restorer: bool = False): """Describes a syscall by its name and outputs. :param name: The name of a system call. @@ -18,4 +19,5 @@ class SyscallInfo: self.patchup_address_registers = patchup_address_registers self.creates_thread = creates_thread self.return_from_signal = return_from_signal + self.sets_signal_restorer = sets_signal_restorer diff --git a/src/focaccia/qemu/target.py b/src/focaccia/qemu/target.py index 3079e18..4cb6a3f 100644 --- a/src/focaccia/qemu/target.py +++ b/src/focaccia/qemu/target.py @@ -249,6 +249,7 @@ class GDBServerStateIterator(GDBServerConnector): debug(f'Skip {events[idx]}') self._signal_frames = [] + self._signal_restorers = {} first_state = self.current_state() self._events = EventMatcher(events, @@ -269,6 +270,7 @@ class GDBServerStateIterator(GDBServerConnector): def _handle_syscall(self, event: Event, post_event: Event) -> ReadableProgramState: call = event.registers.get(self.arch.get_syscall_reg()) + state = self.current_state() next_state = None syscall = emulated_system_calls[self.arch.archname].get(call, None) @@ -298,12 +300,38 @@ class GDBServerStateIterator(GDBServerConnector): self._process.write_memory(addr, data) if syscall.return_from_signal: - # TODO: restore frame frame = self._signal_frames.pop() - info(f'Handling return from signal with frame: {frame}') + debug(f'Handling return from signal with frame: {frame}') + + sc = frame.uctx.mcontext + gdb.parse_and_eval(f'$r8 ={sc.r8}') + gdb.parse_and_eval(f'$r9 ={sc.r9}') + gdb.parse_and_eval(f'$r10 ={sc.r10}') + gdb.parse_and_eval(f'$r11 ={sc.r11}') + gdb.parse_and_eval(f'$r12 ={sc.r12}') + gdb.parse_and_eval(f'$r13 ={sc.r13}') + gdb.parse_and_eval(f'$r14 ={sc.r14}') + gdb.parse_and_eval(f'$r15 ={sc.r15}') + gdb.parse_and_eval(f'$rdi ={sc.rdi}') + gdb.parse_and_eval(f'$rsi ={sc.rsi}') + gdb.parse_and_eval(f'$rbp ={sc.rbp}') + gdb.parse_and_eval(f'$rdx ={sc.rdx}') + gdb.parse_and_eval(f'$rax ={sc.rax}') + gdb.parse_and_eval(f'$rcx ={sc.rcx}') + gdb.parse_and_eval(f'$rsp ={sc.rsp}') + gdb.parse_and_eval(f'$rip ={sc.rip}') + return self.current_state() + + # TODO: restart syscall + + if syscall.sets_signal_restorer: + restorer_addr = self._process.read_memory(state.read_register('rsi') + 0x10, 8) + restorer_addr = int.from_bytes(restorer_addr, byteorder='little') + self._signal_restorers[event.registers['rdi']] = restorer_addr syscall = passthrough_system_calls[self.arch.archname].get(call, None) if syscall is not None: + assert(call is not None) info(f'System call number {hex(call)} passed through') self._step() if self.is_exited(): @@ -363,7 +391,9 @@ class GDBServerStateIterator(GDBServerConnector): si_signo, si_errno, si_code = struct.unpack_from("<iii", event.signal_number.siginfo, 0) siginfo = SigInfo(si_signo=si_signo, si_errno=si_errno, si_code=si_code, si_pid=post_event.tid, si_uid=0) - frame = SigFrame(sp_new=rsp - 0xd78, pretcode=0x401824, uctx=uctx, siginfo=siginfo) + + restorer_addr = self._signal_restorers[si_signo] + frame = SigFrame(sp_new=rsp - 0xd78, pretcode=restorer_addr, uctx=uctx, siginfo=siginfo) self._process.write_memory(rsp - 0xd78, frame.to_bytes()) gdb.execute(f'set $pc = {hex(sighandler_pc)}') diff --git a/src/focaccia/qemu/x86.py b/src/focaccia/qemu/x86.py index 25ab874..bf95492 100644 --- a/src/focaccia/qemu/x86.py +++ b/src/focaccia/qemu/x86.py @@ -14,7 +14,7 @@ emulated_system_calls = { 5: SyscallInfo('fstat', patchup_address_registers=['rsi']), 6: SyscallInfo('lstat', patchup_address_registers=['rsi']), 8: SyscallInfo('lseek'), - 13: SyscallInfo('rt_sigaction', patchup_address_registers=['rdx']), + 13: SyscallInfo('rt_sigaction', patchup_address_registers=['rdx'], sets_signal_restorer=True), 14: SyscallInfo('rt_sigprocmask', patchup_address_registers=['rdx']), 15: SyscallInfo('rt_sigreturn', return_from_signal=True), 16: SyscallInfo('ioctl', patchup_address_registers=['rdx']), |