问题
I noticed that upon an invalid 64bit MacOS syscall
xor eax,eax
syscall
;lldb stops here after the syscall
When lldb stops the process while single stepping on:
thread #1, stop reason = EXC_SYSCALL (code=5797, subcode=0x1)
The rcx
is equal to rsp
. However when lldb is not attached or is not single stepping rcx
is equal to expected return address after the syscall
(i.e. is exactly of the same value as rip
in user space). Is this some kind of a bug / side effect?
I'm observing this on MacOS 10.14.5, lldb-1000.11.38.2 also 10.14.6, lldb-1001.0.13.3
After some investigation relevant XNU code seems to be:
Entry(hndl_syscall)
TIME_TRAP_UENTRY
movq %gs:CPU_ACTIVE_THREAD,%rcx /* get current thread */
movl $-1, TH_IOTIER_OVERRIDE(%rcx) /* Reset IO tier override to -1 before handling syscall */
movq TH_TASK(%rcx),%rbx /* point to current task */
/* Check for active vtimers in the current task */
TASK_VTIMER_CHECK(%rbx,%rcx)
/*
* We can be here either for a mach, unix machdep or diag syscall,
* as indicated by the syscall class:
*/
movl R64_RAX(%r15), %eax /* syscall number/class */
movl %eax, %edx
andl $(SYSCALL_CLASS_MASK), %edx /* syscall class */
cmpl $(SYSCALL_CLASS_MACH<<SYSCALL_CLASS_SHIFT), %edx
je EXT(hndl_mach_scall64)
cmpl $(SYSCALL_CLASS_UNIX<<SYSCALL_CLASS_SHIFT), %edx
je EXT(hndl_unix_scall64)
cmpl $(SYSCALL_CLASS_MDEP<<SYSCALL_CLASS_SHIFT), %edx
je EXT(hndl_mdep_scall64)
cmpl $(SYSCALL_CLASS_DIAG<<SYSCALL_CLASS_SHIFT), %edx
je EXT(hndl_diag_scall64)
/* Syscall class unknown */
sti
CCALL3(i386_exception, $(EXC_SYSCALL), %rax, $1)
/* no return */
I do indeed get the rax
value as the (code=xxxx)
reported by lldb
. And the subcode 1 also matches.
The parts relevant for returning to user space are:
EXT(ret64_iret):
iretq /* return from interrupt */
L_sysret:
/*
* Here to restore rcx/r11/rsp and perform the sysret back to user-space.
* rcx user rip
* r11 user rflags
* rsp user stack pointer
*/
pop %rcx
add $8, %rsp
pop %r11
pop %rsp
sysretq /* return from system call */
and also
L_fast_exit:
pop %rdx /* user return eip */
pop %rcx /* pop and toss cs */
andl $(~EFL_IF), (%rsp) /* clear interrupts enable, sti below */
popf /* flags - carry denotes failure */
pop %rcx /* user return esp */
sti /* interrupts enabled after sysexit */
sysexitl /* 32-bit sysexit */
So I actually did disassemble the MacOS 10.14.6 kernel binary found at /System/Library/Kernels/kernel
.
Interestingly the sysret
variant is not there at all. Only the iret
and sysexit
.
Looking at 64bit relevant part really helps.
_ret64_iret:
ffffff800019985a iretq ; CODE XREF=_idt64_debug+38, _ks_64bit_return+118, _ret64_iret+25DATA XREF=_idt64_stack_fault+32
loc_ffffff800019985c:
ffffff800019985c cmp eax, 0x1 ; CODE XREF=_ks_64bit_return+170
ffffff800019985f je loc_ffffff8000199875
ffffff8000199861 pop rax
ffffff8000199862 pop rcx
ffffff8000199863 add rsp, 0x8
ffffff8000199867 pop r11
ffffff8000199869 pop rsp
ffffff800019986a sysret
loc_ffffff800019986d:
ffffff800019986d pop rax ; CODE XREF=_ks_64bit_return+179
ffffff800019986e verw word [rsp-0x30+arg_50]
ffffff8000199873 jmp _ret64_iret
loc_ffffff8000199875:
ffffff8000199875 pop rax ; CODE XREF=_ret64_iret+5
ffffff8000199876 pop rcx
ffffff8000199877 add rsp, 0x8
ffffff800019987b pop r11
ffffff800019987d verw word [rsp-0x20+arg_20]
ffffff8000199882 pop rsp
ffffff8000199883 sysret
来源:https://stackoverflow.com/questions/57523462/lldb-affecting-rcx-value-upon-exc-syscall