<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/57591>57591</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            lldb stepping fails in macOS processes with a 32-bit/custom LDT installed
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          mrpippy
      </td>
    </tr>
</table>

<pre>
    macOS 10.15 added support for processes to set a custom LDT, allowing a 64-bit process to set up and far jump to a 32-bit code segment. Wine (specifically CrossOver by CodeWeavers) uses this functionality to run 32-bit Windows EXEs.

However, lldb is not able to correctly step when in the non-64-bit code segment. Stepping resets `%cs` back to the 64-bit segment, generally causing a crash soon after (because 32-bit instructions are being executed as 64-bit).

I've attached a sample executable derived from an [XNU test](https://github.com/apple-oss-distributions/xnu/blob/main/tests/ldt.c) which tests the custom LDT functionality. It's pretty easy to reproduce the bug. Also note that although Rosetta 2 implements the custom LDT functionality, I wasn't able to reproduce this bug there. Run this on an Intel Mac:

[lldb-32bit-ldt.zip](https://github.com/llvm/llvm-project/files/9501026/lldb-32bit-ldt.zip)

```
% sw_vers
ProductName:    macOS
ProductVersion: 12.5
BuildVersion:   21G72
% uname -a
Darwin Brendans-Mac-mini.local 21.6.0 Darwin Kernel Version 21.6.0: Sat Jun 18 17:07:25 PDT 2022; root:xnu-8020.140.41~1/RELEASE_X86_64 x86_64

% cd lldb-32bit-ldt
% make
cc -arch x86_64 -g3 -o ldt ldt.c ldt_code32.s -Wall -Wextra -Wl,-pagezero_size,0x1000 -DDEBUG

% lldb ./ldt
(lldb) target create "./ldt"
Current executable set to '/Users/pip/lldb-32bit-ldt/ldt' (x86_64).
(lldb) version
lldb-1316.0.9.46
Apple Swift version 5.6.1 (swiftlang-5.6.0.323.66 clang-1316.0.20.12)
(lldb) break set -n code_32
Breakpoint 1: where = ldt`code_32, address = 0x000000000000b000
(lldb) run
Process 82565 launched: '/Users/pip/lldb-32bit-ldt/ldt' (x86_64)
32-bit code is at 0xb000
lowstack addr = 0x210ff0
size = 8192, szlimit = 32768
Mapping code @0xa000..0xb04b => 0xf0000..0xf104b
i386_get_ldt returned 3
i386_set_ldt returned 3
base 0x0 lim 0x0 type 0x0 dpl 0 present 0 opsz 0 granular 0
base 0x0 lim 0xfffff type 0x12 dpl 3 present 1 opsz 1 granular 1
base 0x0 lim 0x0 type 0x0 dpl 0 present 0 opsz 0 granular 0
base 0x0 lim 0xfffff type 0x1a dpl 3 present 1 opsz 1 granular 1
Updated gsbase for stack at 0x201000..0x211000 to 0x7000033880e0
[thread 0x700003388000] tsd base => 0x7000033880e0
Setting new GS base: 0x1008200
Process 82565 stopped
* thread #2, stop reason = EXC_BREAKPOINT (code=EXC_I386_BPT, subcode=0x0)
    frame #0: 0x00000000000f1001
->  0xf1001: movl   %esp, %ebp
    0xf1003: pushq  %rbx
    0xf1004: callq  0xf1009
    0xf1009: popq   %rbx
Target 0: (ldt) stopped.
(lldb) reg read $cs
      cs = 0x000000000000001f                           < ------ 32-bit code segment
(lldb) stepi
Process 82565 stopped
* thread #2, stop reason = instruction step into
    frame #0: 0x00000000000f1003
->  0xf1003: pushq  %rbx
    0xf1004: callq  0xf1009
    0xf1009: popq   %rbx
    0xf100a: subl   $0x8, %esp
Target 0: (ldt) stopped.
(lldb) reg read $cs
      cs = 0x000000000000002b                            < ------ after one step, %cs is now the 64-bit code segment
(lldb) reg read $rsp
     rsp = 0x0000000000210f98
(lldb) stepi
Process 82565 stopped
* thread #2, stop reason = instruction step into
    frame #0: 0x00000000000f1004
->  0xf1004: callq  0xf1009
    0xf1009: popq   %rbx
    0xf100a: subl   $0x8, %esp
    0xf100d: movl   0x1c(%rbp), %eax
Target 0: (ldt) stopped.
(lldb) reg read $rsp
     rsp = 0x0000000000210f90                            < ------ the processor really is in 64-bit mode now, $rsp decreased by 0x8
```


I'm not sure, but this bug might be related to macOS adding a 'full' thread state flavor (`x86_THREAD_FULL_STATE64`). I believe it's only (and I think must be) used for processes that have set a custom LDT. This flavor contains the normal x86_64 thread state, but also `ds, `es`, `ss`, and `GSbase`. Maybe lldb needs to use the full thread state flavor when it's available to avoid `%gs` being reset?

```
_STRUCT_X86_THREAD_FULL_STATE64
{
        _STRUCT_X86_THREAD_STATE64      __ss64;
        __uint64_t                      __ds;
        __uint64_t                      __es;
        __uint64_t                      __ss;
        __uint64_t                      __gsbase;
};
```
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzNWN9zm0gS_mvwSxfUABKSHvRgWUrWt9kkFduXvKkGGCQ2CAgzWLL_-vt6AEuyvbls7i51KluI6Z7--U3P9MRV-jDfyeTDDfnC88ck01SlpNu6rhpDWdVQ3VSJ0lppMhVpZUhS0mpT7ejd8tYJrkgWRbXPyw0I0ciNczNMGSa0NckypUw29Ge7q3lYUhhY1qRKFZg2O1Uajz7npSInmOpaJXmWJxD9QFdNpfWHe9VQjBfwf1YSb9oJZtRau7a5pqwtE5NXpSxy88AqmrYclEBsWu01rb6stOeIpSMuu-_fqr2CKPaiKNKYIKes4GFcKBaRVE2jEgMbtFE17beqpLyEPgW20u29PXfhBpw1R6NR8F2TEwknGCcaT4pl8pXlsoB-cj-PLdioUjXW40S2ugto0ki9JV1VJcnMIAQITqyYrgbn8lKbprW-a5KNoljxXHVQSWuQS6l7XYjXmfPXTjC5VySNkcmWGUnLXQ3Pu6k2CKlq8nvQsgb5liU548WX93dklDbOeAljtsbU2gkvneAN_ja52baxl1Q7vMgawlzkzk1zmJjHrbURlEPZ4jsuqhiPncxLPFgk04rUeAmndr_Nk63VpG3AjqA7z7VH13BtooE6ZZB6JXWXfwUYpm2i7Oy43Xh0WeiKE8xDEmkuzLZqN1v6VCFVRlJAOQeAE_J9nZyua9pLDcsnR7ycqgSUoJOlNMqjT23ZjXEiS7oujSroD5lw5E5SgvAyDt0wQL5cDsVjXv_bQBfF_fBwYcCfgCxes7xQHNDZWPgiiCzDC9HB7Ew9sNr9da_BmPR-bdeaHfhovTPv5U5Zw2e2cpzR_glmRKkj-4E37qiLNi_SM1rgv50ERz1tCaHkym5kKRtUFFo0qkxlqV1Eyt3lZe4VFWoCBb4XeYJ6rt9VUyKavfSeCCV0gxz_A4H3p-RPMCD4C7o-Ip2BCAInXFBTVQajQKQ7FQFK4Eh4I9-ZrHwE7NPq3eryZrX-Mo3W0YgO9nEWMEhLUjoP7JG0k19V95Yk8K0BnjsZ5G5CcisCN1nA8_eaC0kYeJrczygD-FYH00g8C-DNreVGPaqmWuv8UWFAHHwhBLnL5Wpx9_a5Vbaced16GkanPMhLy8hmg7qcNEoarrfBwBj0GblqUfhKc1oJuJAD4sA7eO-0rb9vaobQM1wNoiZcq_qQHSvP0Yj7Hg123IrwQx-Z82beKOpGL7mC0M0-z8zATmNk17d7BA8Xsty4PCS8MAi9KKLEDvWiOKHBEeRH5TFc_2p9cktbwNdh7_qCKXWVw3ufQbTnBUxOuOQUYWkMzLzxpWnD2xwTxUGcfGL8v9CJDelpqdjtcRqMI2RKorKg_rKyn41uJ_d0S0WpAfrF4WgJNmlteANis3ubA19kWU9nWNnhqT-z7unHIt9BHo-FwSSadnx_yG5_s2qckRAHCR2ex7pGMXM74QqyM9EPZz7Gu7l5CIsBvTUDH-W6xcpNKTwh6r8gxhI7HoJMsMk-zUPdDaR1QYKLv2bECqpq_YjHppFlW-DIIV4VkPFnEOIHVkr4JMXvpPhHKf6vMEP-qBl3dSp5b99oK4-PaX1uOeeB8PvQB76tEVi34jDhfIThdCrUgM3xwmwB9_SMCryMl2R0Slb2Uz5fzr_BpslIKNWe3t5YdgaxLUzTYMDdOdqxn9Y1wN4vjkvqLXCCbk0xHcmXGkudgbf6crVefFpd_v7xw_X7WwY94w4UJlwzYhYf7SlUt3FPQXSflgThkzW8tUCB6Kw7WaeApuhD6rKXZNEq7MLfVfcFZqOYKl2zBv4V10e5HW_IvHWrt98sbxMfnnOMmIOPst-GkdlzlpkVUtXf6FzIbVeoRVcbpnblz4YYviypjeJjp43mKNFHJUTJa1UKjmb01x8nvCLXfl47rL9Qzkfk_L-R8pMDbXfuRi2ufjid4ct0_k9TdOSQzAEYdqgZicN0QI2uf006g_g76TzNZ9dLVGi2OMC9mRBq-5_9aX_y3ZSfGtjok6VBeHthIW82s-n_K25GL3Hzi1Bx5E1P6g6qKNqgqRVqz-n9LPmfl4YfTJX4QTAxWvqOH_sQlHALCyThaN6DaMcgArA6H1g_Gks-fWrsYWjqOSivNiDPutWd7c512_D5F-2VOfZZu3yzNWh9ob-wWyP2vO5eA8edrpeGgKwtCj479UjCnonzb1bI-8p21lDMR6rb37DhLNdv7t69W9_cXt6ucMbiLn6GVhMqilyhbc67prMq4Sym8gXHNZtTfqUdukbw9fcT6fNbFG49t_JevbhM8ejW3mR09iRVadAa6_66odmh8em7h1Pzh0hI7m1hZqptlCOhtDXa_tbDbzYTP9_e2M06Eh6a0AdEzbYLpVKpvbTh2wXWyuF6NVbdTUgXAXkv82LogEHN0_7OY9PdeainyxAnfPOdbhOh_nR3dWubrdcy0M2ZLE7rINErs_oJPX2tNSaHz6etW1SHaLQ2r8N7vUYc__4k9TOT9M9M6k5-TxOdyfL4e4jrhZr7URSMhRiH4UU6D9NZOJMXJjeFmtuM6-GyKkMO7Yrt1swRrfvcbJ9u69B8nNyIcL3FWlfpRdsU8799P5Fr3doLivFkPPMvtvOxVJPMHyVZGIWJlJNIzEZ-AvPD2TQOZHIBlKlCz3FsRaPKh04rgpvW8fIin3NLL2YiCvxR4IdeIEd-moZKxmM_ziKJVkXt4KbHdnhVs7lo5tYklA8NYpFro49EqXW-wYqw6iBftmZbNfNdg66sfriwqufW9H8BPd872w">