lldb affecting rcx value upon EXC_SYSCALL

I noticed that upon an invalid 64bit MacOS syscall

    xor eax,eax
;lldb stops here after the syscall

When lldb stops the process on:

thread #1, stop reason = EXC_SYSCALL (code=5797, subcode=0x1)

The rcx is equal to rsp. However when lldb is not attached rcx points to expected return address after the syscall. Is this some kind of a bug / side effect?

I'm observing this on MacOS 10.14.5, lldb-1000.11.38.2

After some investigation relevant XNU code seems to be:


    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 */

     * 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 */
    je  EXT(hndl_mach_scall64)
    je  EXT(hndl_unix_scall64)
    je  EXT(hndl_mdep_scall64)
    je  EXT(hndl_diag_scall64)

    /* Syscall class unknown */
    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. But I have hard time following what happens inside and after the CCALL3 macro.

This is the sysret handling @PeterCordes mentions

     * 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 */

Which does seem to match the invalid syscall without debugger attached scenario.