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

    <tr>
        <th>Summary</th>
        <td>
            lldb test suite fails to JIT expressions after update to Ubuntu Jammy ubuntu3.3
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            lldb
      </td>
    </tr>

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

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

<pre>
    TLDR: Long report for background, I'll add the important follow up questions in a comment after this.

Since I updated our 32 bit Arm lldb bot container from:
```
$ ldd --version
ldd (Ubuntu GLIBC 2.35-0ubuntu3.1) 2.35
```
To:
```
$ ldd --version
ldd (Ubuntu GLIBC 2.35-0ubuntu3.3) 2.35
```

The Arm lldb bot has been failing with:
```
Testing Time: 493.49s
  Unsupported      :  485
 Passed           : 2264
  Expectedly Failed:   25
  Unresolved       : 1
  Failed           :  101
```
  
Tests fail with various things along the theme of:
```
error: Can't evaluate the expression without a running target due to: Interpreter doesn't handle one of the expression's opcodes
```

First happened here, the changes are unrelated:
https://lab.llvm.org/buildbot/#/builders/17/builds/44298

For reasons I still cannot explain, the fixing of this Ubuntu issue (realted to gdb) on Jammy, caused this failure:
https://bugs.launchpad.net/ubuntu/+source/gdb/+bug/1927192

The funny thing is, back when this was fixed on Bionic we also saw this and figured it was a bug there and moved the bot to Jammy. Now the GDB issue is fixed on Jammy too but and lldb has broken again. So clearly we are in the wrong here.

The background of that bug is not so important once I explain what lldb is doing. Though it is along the same lines,
it was preventing gdb from putting breakpoints in ld-linux.

Reproducer:
```
$ cat /tmp/test.c
int fn() { return 99; }

int main() { return 0; }
```
```
./bin/lldb /tmp/test.o -o "process launch -m" -o "expr -- fn()"
```
```
Process 275137 launched: '/tmp/test.o' (arm)
(lldb) expr -- fn()
error: Can't evaluate the expression without a running target due to: Interpreter doesn't handle one of the expression's opcodes
```

Here's what happens.
* LLDB wants to run an expression, the first choice is to JIT it.
* To JIT it we need to allocate some memory to JIT into.
* First choice for that is the _M packet sent to lldb-server.
* This packet is only implemented for x86_64.
* We fall back to instead doing a direct call to `mmap`.
* mmap is looked up, we pick one of the symbols found and call PrepareTrivialCall.
* PrepareTrivialCall must set up the PC to point to the entry of the function,
  setup the arguments according to the ABI and possibly change the CPSR (program status register) for ARM and Thumb modes.
  
And here is where the fun starts.

On 32 bit Arm we have ARM and Thumb code modes, Thumb is the compressed set. If we look at the mmap symbol
that lldb chooses, it's in ./arm-linux-gnueabihf/ld-linux-armhf.so.3.

```
0001686c <__mmap>:
   1686c:       b530            push    {r4, r5, lr}
 1686e:       9d04            ldr     r5, [sp, #16]
   16870:       f3c5 040b       ubfx    r4, r5, #0, #12
   16874:       b954            cbnz r4, 1688c <__mmap+0x20>
```

See that start address? 2 byte alignment which means a Thumb mode function. At least, it not being 4 byte aligned means it's not ARM. I'm not 100% sure what Thumb requires.

Anyway, point is that the usual trick of "bit 0 or 1 is set means Thumb" doesn't work here. Since the symbol doesn't
have the bottom bits set. This should be fine because we can look up the function's type from the symbol, or the type of the section (it is not important which here).

Great, do we do that? We try to, but it doesn't work. There are no loaded sections for ld-linux for us to find the mmap in.

```
(lldb) memory region --all
[0x0000000000000000-0x0000000000400000) ---
[0x0000000000400000-0x0000000000401000) r-x /tmp/test.o PT_LOAD[0]
[0x0000000000401000-0x0000000000410000) ---
[0x0000000000410000-0x0000000000411000) r-- /tmp/test.o
[0x0000000000411000-0x0000000000412000) rw- /tmp/test.o PT_LOAD[1]
[0x0000000000412000-0x00000000f7e90000) ---
[0x00000000f7e90000-0x00000000f7f9c000) r-x /usr/lib/arm-linux-gnueabihf/libc.so.6 PT_LOAD[0]
[0x00000000f7f9c000-0x00000000f7fac000) --- /usr/lib/arm-linux-gnueabihf/libc.so.6
[0x00000000f7fac000-0x00000000f7fae000) r-- /usr/lib/arm-linux-gnueabihf/libc.so.6
[0x00000000f7fae000-0x00000000f7faf000) rw- /usr/lib/arm-linux-gnueabihf/libc.so.6
[0x00000000f7faf000-0x00000000f7fb9000) rw-
[0x00000000f7fb9000-0x00000000f7fbf000) ---
[0x00000000f7fbf000-0x00000000f7fde000) r-x /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3
[0x00000000f7fde000-0x00000000f7fe2000) ---
[0x00000000f7fe2000-0x00000000f7fe4000) rw-
[0x00000000f7fe4000-0x00000000f7fec000) ---
[0x00000000f7fec000-0x00000000f7fed000) r-x [sigpage]
[0x00000000f7fed000-0x00000000f7fef000) r-- /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3
[0x00000000f7fef000-0x00000000f7ff0000) rw- /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3
[0x00000000f7ff0000-0x00000000fffcf000) ---
[0x00000000fffcf000-0x00000000ffff0000) rw- [stack]
[0x00000000ffff0000-0x00000000ffff1000) r-x [vectors]
[0x00000000ffff1000-0xffffffffffffffff) ---
```

In the output above, anything with a name after the file name is a section we know about.
So we have some for test.o and libc.so.6 but nothing for ld-linux.

This is why we are able to resolve the fake return address we give for mmap. Which is the symbol
`_start` from the libc. This we do have a section for therefore when we resolve it, the thumb bit is placed correctly.

mmap we have no idea so the address comes back unchanged and PrepareTrivialCall decides well it must
be ARM then. Doesn't set the T bit in CPSR, jumps to mmap and immediately SIGILLs because we're trying run Thumb in Arm mode.

So, let's just load the sections for ld-linux, right?

Well, it turns out we actually do, then we throw them away. This patch fixes the whole issue (for Arm at least):
```
diff --git a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
index 85d7ae9dac75..7a228d0d9ebf 100644
--- a/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
+++ b/lldb/source/Plugins/DynamicLoader/POSIX-DYLD/DynamicLoaderPOSIXDYLD.cpp
@@ -459,15 +459,6 @@ void DynamicLoaderPOSIXDYLD::RefreshModules() {
 } else if (module_sp == interpreter_sp) {
           // Module already loaded.
           continue;
-        } else {
-          // If this is a duplicate instance of ld.so, unload it.  We may end
-          // up with it if we load it via a different path than before
-          // (symlink vs real path).
-          // TODO: remove this once we either fix library matching or avoid
-          // loading the interpreter when setting the rendezvous breakpoint.
- UnloadSections(module_sp);
- loaded_modules.Remove(module_sp);
-          continue;
         }
 }
```

Now you can run expressions succesfully. If we look at the memory regions again:
```
(lldb) memory region --all
[0x0000000000000000-0x0000000000400000) ---
[0x0000000000400000-0x0000000000401000) r-x /tmp/test.o PT_LOAD[0]
[0x0000000000401000-0x0000000000410000) ---
[0x0000000000410000-0x0000000000411000) r-- /tmp/test.o
[0x0000000000411000-0x0000000000412000) rw- /tmp/test.o PT_LOAD[1]
[0x0000000000412000-0x00000000f7e90000) ---
[0x00000000f7e90000-0x00000000f7f9c000) r-x /usr/lib/arm-linux-gnueabihf/libc.so.6 PT_LOAD[0]
[0x00000000f7f9c000-0x00000000f7fac000) --- /usr/lib/arm-linux-gnueabihf/libc.so.6
[0x00000000f7fac000-0x00000000f7fae000) r-- /usr/lib/arm-linux-gnueabihf/libc.so.6
[0x00000000f7fae000-0x00000000f7faf000) rw- /usr/lib/arm-linux-gnueabihf/libc.so.6
[0x00000000f7faf000-0x00000000f7fb9000) rw-
[0x00000000f7fb9000-0x00000000f7fbf000) ---
[0x00000000f7fbf000-0x00000000f7fde000) r-x /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 PT_LOAD[0]
[0x00000000f7fde000-0x00000000f7fe2000) ---
[0x00000000f7fe2000-0x00000000f7fe4000) rw-
[0x00000000f7fe4000-0x00000000f7fe8000) ---
[0x00000000f7fe8000-0x00000000f7fe9000) r-- objc_imageinfo
[0x00000000f7fe9000-0x00000000f7fea000) rw- .bss
[0x00000000f7fea000-0x00000000f7feb000) r-x .text
[0x00000000f7feb000-0x00000000f7fec000) rwx
[0x00000000f7fec000-0x00000000f7fed000) r-x [sigpage]
[0x00000000f7fed000-0x00000000f7fef000) r-- /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3
[0x00000000f7fef000-0x00000000f7ff0000) rw- /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 PT_LOAD[1]
[0x00000000f7ff0000-0x00000000fffcf000) ---
[0x00000000fffcf000-0x00000000ffff0000) rw- [stack]
[0x00000000ffff0000-0x00000000ffff1000) r-x [vectors]
[0x00000000ffff1000-0xffffffffffffffff) ---
```
Now we have a region at 0x00000000f7fef000 that has a section associated with it. mmap is at 0xf7fd586c.

Before patch:
```
(lldb) memory region 0xf7fd586c
[0x00000000f7fbf000-0x00000000f7fde000) r-x /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3
```
After patch:
```
(lldb) memory region 0xf7fd586c
[0x00000000f7fbf000-0x00000000f7fde000) r-x /usr/lib/arm-linux-gnueabihf/ld-linux-armhf.so.3 PT_LOAD[0]
```

Having a section allows us to resolve the address and set the correct mode. Its AddressClass goes from eUnknown to eCodeAlternateISA (alternate being Thumb here). PrepareTrivialCall sets CPSR.T correctly and it all works.

I have no idea why the test suite ever passed on previous versions of Jammy, and am unable to test it because lldb appears to try to treat the older Jammy's ld-linux as ARM code, meaning I can't start a program because breaking inside of it doesn't work (again, no idea how the test suite managed to run).

This unloading of ld-linux happens on AArch64 also but there we have no reason to need the details of the mmap symbol. It's enough to know its address.

This unloading was added by https://github.com/llvm/llvm-project/commit/553558292eaef8867940856bd5272478cc51f4e0

"The change in RefreshModules ensures we don't broadcast the loaded
notification for the dynamic loader (ld.so) module more than once."

The reason lldb believes it has already loaded the ld-linux (or at least, told the user it has) is that m_interpreter_address in Dyld is set from AUXV_AT_BASE in DynamicLoaderPOSIXDYLD::EvalSpecialModulesStatus. This happens before any shared objects have been looked at.

I also confirmed that there is only one point at which ld-linux is added. So at least for this distro, there are not multiple copies of it that we have to ignore.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzse91y4ziu8NOob1B22fL_RS6cZDJfvsrsdHUyZ_ZcpSgRsjihSC1J2fE-_SmAki3bcfd07Zna2jrt6nJbIgmA-CMAIsJ7tTGIN8nsNknTe7FV8rlW-RuGkKRpMrv_JJpQWndzMvQps3J_8_J0_yWZrOHJmg04rK0LUFgHmcjfNs42RibpHTwm6UJrEFJCKBFURfOEoala2x00NfyjQR-UNR6UAQG5rSo0AUQR0EEolR8mo_tktI7fz8rkCI_Q1FIElGAbB5MUMhVg7SrQWmaQ2QC5NUEogw4KZ6tk0i5P5qP2X3xMp6ClhMFgi84ra-JrepWky9-yxoQGfn56vL2DdDiZDUYNv5oMx0m64lcfgn2x_-sIJ19F2KIt8ZQJpfCQIRoohNLKbGCnQnmNtBcSg9nAi6qQBDtdTYbTlY-DAL8Z39QkPZTAH5oD02VLEHwW3ndDh_E0nU87AD-915gHlHoPD0JplAwA0tkRg0Nv9fYAhSaMu9G45gw-jEfjDzcDcNyU5-3z3mErnLKNJ70yGw9Ck_aSZoYSKwRbXOMOOmcdobwTJkkXAXArdCMCrwR8rx16kiejsU0AAa4xhhgahNtgANkgBFIMeDQBXe2QFFxa9BFgKYzUCNYQGWdQk3Thwda5lei_ogAPynkCVNdoUEKJDskICVZeCrNBD8IhNMahJus5bLYMofb0lD4k6YMW2VDrbTW0bpOkD1mjtMxs4MFJ9wKdT9KH8aJ7pqfpNF0tTwiyDhwKT9b9CD4orSEXxthAm9NCmY6-Qr0Tr3jnykNrCcr7BskyHApNmhcsbGRGtmAN_H9RVXsCkIuGdI9Xkqwbh1e2ljUbP9SiMXlZCzk0SLuKNsYTbr1tXI5J-sBo6E3WEBPGq3QxXqXn5lY0xuyjNoHyRAv5P9iVaCI5O-Fpb-SpDNwqa1QOOwShvQUvdnGSMBIKtWkcSlCB1wjIGtZMhzxc2S1GH0qGHWzc_BD-Znf89uf725ZbqoeQJ0GwFjJSSSOjb2C_4OwbGhAbocwQni3kGoXTe6bOITljgrtzZCFExvB870dPH8UmAtOsPJB8ve15exudditz2NFcpkR5kFaZzRBeSttsStq-6tulFxWCVgaJuRF3y6Ha4RYNu6yNzNjNQ90EfpE5FG-1VSbwqaLlQCvTvJ9s4QvWzsomR_c1Z52LAEn6EKqavtGHYd5SQYeYSdIlKWOyuAWHoXEGVqtkcgvJ4r6PiyZXrO3n00ens88IOH0ckgITkAfm3SlZFgYWkjStnc3Re4hKDoMqSdN2iPwJDAYHsumM_xNoP7cQ08VsPFm0gKP7TtLFGRVJuiB7Fa4iBC0bl0QvbfyCgv8c3_r_2JkufFTe6GMPoUm6hqen-1vYCdK4YIk-EOYES-fnyEXnpVU5mypZ8uMLqNAD9dK9I1s0GN2e0NrmxBNvK4QKK-v2h9Um2N76hz4OisnYNglZifD6C9SC4jjwFGYFy4Y48Oi26PpEkGNqZyoP1ug9GbRGis5QMtz35fx1Pu0t-h2hEFpHJxgsKOMDChltHARI5TAPkNOcYCGZj6pK1Ml81INBbwijtvYNJTQ1sW6HQNFnX4J-X2VWeyjYA5FvY7CfHdbC4YtTWyX0ndC6B_tyEKrGEysChaIE9vMdUca-g36wrpjg9h3aojF5iALtQg2PoV0s3KYh_ngQeW6dZBWNQNa3j0xkbb1Xmd63JzKP3X1-_kJWUzu7caICH0RoPDjcKB_QkeUQu9dffmEQL2VTZVCRwg5Pw521iac-8W_HP1qSCaQLp6H0r6YfOe8QSrHFMyRkFRETSSG-axUptxUrN0piwBAeC4JBUgMReAZLMoopYgwHv5-X1voIVAU2K2WA_JtwVfTVg41pUGSqLMjftQ58IFxVFkNvh5OTrZxZ7Gg0Gs-X8xySyd3rK6vY5KeDlwcAHo3xJ32y2WTUiyyhbnzJIebi1k2JRjejb-0Ojpoh4BHCSo6mfQhaOv4_Lkxmt57VOEkn43kyu-8TshgdwRSTfAaj6Shrn5useGcwPSqSdDLqYKUngKa9Ha1mJ_TkmflnC2U8Xy77nElvR-_piBh03fk9I0YnwmpE6RxJPpk8QArZPlA8ozaG87ZdqfISKhSGgpijqh4MZwjrABqFD1H6HC1kSKYy7QFD2QJp9YNmrb_8MuSUsuLH8WiUpDPwjcPolSM2h_9olMNTZV-b_U5wsBhNm5W41dPGN0JDcOxgCjopyShGYB2MaSJ5h0gLI6AD9Xi07Kx7i_ERxNz06JuOs9pQlOyrDeGCrcj0fLQddra-tI2WkNEhYRAy5LCWjCoXJhpW62aOPmjhIexrjNHPETPtk_0-xuHOZSIvI1cT4yzi4jFKi6KLWcPqhHs_OxQsLmmJHmmZeST_3xECH0Qc-zaBBHrKHNodR7EOwVjQVkh2GXlM-smxdebNDw0fioUy8uhElPmaufcCjPZcJM9pDQwGQreuJ5ndjt5HZ59B_9WUvwnIYDD4cNH0o0XjdpEbvF9EZJ9fXp9-Xd8TmIPRX8AcX8Acf5OQ8SUh4yMhg3NCrgD5AHPaAdldAOntZnx1NwygB7NY4Orru-lmnCwqVvkpWxvv6BhQ2fUjQmU5HQzzb3O9g3-KUuRHOr8T5cc4xAc48FRI_zoOvMRRnMrwX8dRXODIVkccHy_iGWeLim8oQpxxukjidyvCZazwMTZ5yTtMv0UiXih4gdNvMYNnnC3Kv4npUn1Q9pkxu_VqU4sNXtVynn8GovhuDfyz_MRL6dGb79TFP4uNQfexFUX-DQVrZ5wuOiVxduuDyN-ucLT4CGsxPhXKFvNgnb8OonW7xdnnlPCPorDHWJKxTagpCc7slst7wuxjAYornAKMqPBQPqdgQmN8pygi62KAHcKbsTsC03TJ57M9pAGcZXLuGJ0_144OLpYOemMj1v4BflYjUj4mIoeiksg0cnocC72RPvGGXTWkDSxp-kZtIwEUAAzhd45N2tSjn1Mk89ErR6XJfHQMg5jUGFbFeIU3ddx9zIrRYWE5eERmSEeWCl26HjiizGK0VGuRo4TcOspi9f5ktxyndNwzFpREAT7mft22cluhj8lxY2L-FzPXD_JSibmSSORrTUEV5akRUxaTtFCiGcL9IdaiKJWQvURyDWeVtI8_mqrmmIpJJHSqqlAqEVDv4fnx58enJ98LN5N04TiqI-m6xnRpn-E8kWL50xsZDv00xjD9D0qnKcbrB5ynUR6nMmpTUvzYB_Q7at2mBKQMnhSdFScPjdB6D9K2YmFhhdLF2mcFYif2w65iEfKSC6BRVXal1XisI3Ma7SrKUNsUZHWt-idVUcBgsFEBRFtyS9KHQ334s242yvgkfbjfG1Gp_IkCW3Jvn399fvz74P6_n-7PB3mEBoZ5XUP2V0Dt6o0S32E5kwuBKynyxWw4XIg0XcqRXGFWUOo0n7ZXMxTv_CU77KLz2_jvr9xwMh0l0xEMprNVkt6NZ5Ckt_H3HNqxrVUSPoZDKjBZf8HCoS9_sbLR6I-l2jbHThb3gNojKEoRlxVPe_U1JJP7ZHIP6lh5fKVsv7-2d2vF1xAQkYDQDoXct0nR8GJ2bk1QpsFk0kIaHOB01ByQDC6QPLaXKez3ZVNrxQVEZXwQlKnaArQceraqxrDRqjAEyukqsQc08hrkpo6HDTmatuzDi2GrBJf5igIdmkDmWFKuaCBjV3sNYJIu_b7SyrzB1oNDoXnpMQ-9XPLy6_2vyWQNDivLRwlXKXNOmFGRcyc3QCeBE24PFTkGvmJyIEgXrsGlraj29qEn03hIeIwXDDTo0Ej859Y2vnffcCD3N2boc-sA-wrDPucgtCj61zjqh194N9enX1cN6KnGUWW_Ek78ze5gbxuuLpCbPxarPfgmz9EXjdb7Dyt7_TTbx0uk67coP7LzH9n5j-z8R3Z-Jb_7Uyrx703Wl9_EtLxctOppk83-yF9VJTaoTPGRxXcLzmCInrYMM--vrBSXK7OeZIYB38OVpdn10oTbvf8oTfxZ1b3idf-vVSooqOiyYNGd9CLApTji_Usp-kUJ4b3NFTf2tfHl8HAfzEDIE8yW8_wkA72NWTynft8dhRxh_ltqkqdUrrlq85-1kY_d94ctFGIb2wAO4tba7nx749OvCXUFE2Hkoa7Rll1iAQIeg4d1nHWnhfewsehj_Qd_M2_G7gwBxTsrca0DOiMCPj6vuTmle26vHWN9o7v3-qgY4zF4rqcMX47ln1hKCbQLvug6vXB8PK0E7cp9LCihD-AbFRBwy7LmG3RruJ-JexPbzlBP-dmhxY1wiQoa05XQGJAKh7oNX6uLukbhmJ3xVg6CwzZmt1qi6wAu_PHSTXiuJ-VWcjmxQsGtNY-UGMTKUrz0ha49oUPJWQ93vhmvJOeTF7d_zO9N2-jXMaNsm9Z6zKiEEZvY6eIac37_yKWdmKK2XYIH6ttOHOLgeu3ycj6NzXVZE9r2uV5RLvYiEpLYVlMiSAxCad9dkfZ6FkjJmFNouDUt2FgxVcF3Cvo1IrmLT0qUkO3htAtxo0LZZMPcVlwR2Xb_DWpn_8A8JOlDbqtK0Y_ZbDKbLdNVigKL5XK-WE1Hy9k8k7N0kU4XyzyfjYspnhhakqYvh55PUAZOSxuAxjcO29JolFXmrJC58FFXYlIagRkbVKFy0a-bgox1lDjRkZDbSsIKYuIKleXuE2E4KR8ee81aXmEnjNitjFrhFj0pEB8JJ4WRSFMn8SRdUg7fayIIVsv2Jh9dC4JI6S75q9d-caZzLsrA_V7L7oaffcf6t7__1-v65fV2_fxTnHC9XvTTVujnGnMldMvYZ-7baSuRnWLGwgcIswdfCkfGnpGQfdRK7s9ue51EOHMhrMm5NYVyFbNBdErdtWRZg21Hg-gu8A-MUq0Ccntnx69WhMqDVD64rqR6uKAPUDU6qFqTx60V-tasGXdnSsGC2hjrcPhJ3kzkarISn_BmPF8t0lE6mS8-lTezfJGtinGR5avxYr5EscqWcoHz0UTM8-Vy8knd0NzxaDwZT0bz0Xy4mK9GC1nMs1Exlas8S6YjrITSh17kT1zGvZkvV8vFJy0y1L7904V4IvJfLLgbtqSs2fhkOtLKB38EEFTQeMMa1_M9BTuAtpeuXwWJlyjxTw1ovO1Kjl21h878T43TN99t4LwXn6QPvJ3_CQAA___9Osyy">