Skip to content

[lldb] Fix FindProcessImpl() for iOS simulators #139174

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged

Conversation

royitaqi
Copy link
Contributor

@royitaqi royitaqi commented May 8, 2025

Benefit

This patch fixes:

  1. After platform select ios-simulator, platform process list will now print processes which are running in the iOS simulator. Previously, no process will be listed.
  2. After platform select ios-simulator, platform attach --name <name> will succeed. Previously, it will error out saying no process is found.

Several bugs that is being fixed

  1. During the process listing, add aarch64 to the list of CPU types for which iOS simulators are checked for.
  2. Given a candidate process, when checking for simulators, the original code will find the desired environment variable (SIMULATOR_UDID) and set the OS to iOS, but then the immediate next environment variable will set it back to macOS.
  3. For processes running on simulator, set the triple's Environment to Simulator, so that such processes can pass the filtering in this line. The original code leave it as the default UnknownEnvironment.

Manual test

With this patch:

royshi-mac-home ~/public_llvm/build % bin/lldb
(lldb) platform select ios-simulator

(lldb) platform process list
240 matching processes were found on "ios-simulator"

PID    PARENT USER       TRIPLE                         NAME
====== ====== ========== ============================== ============================
40511  28844  royshi     arm64-apple-ios-simulator      FocusPlayground // my toy iOS app running on simulator
... // omit
28844  1      royshi     arm64-apple-ios-simulator      launchd_sim

(lldb) process attach --name FocusPlayground
Process 40511 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x0000000104e3cb70 libsystem_kernel.dylib`mach_msg2_trap + 8
libsystem_kernel.dylib`mach_msg2_trap:
->  0x104e3cb70 <+8>: ret
... // omit

Without this patch:

$ bin/lldb
(lldb) platform select ios-simulator

(lldb) platform process list
error: no processes were found on the "ios-simulator" platform

(lldb) process attach --name FocusPlayground
error: attach failed: could not find a process named FocusPlayground

Unittest

With the patch, the test can list processes on the iOS simulator:

$ bin/llvm-lit -av ../llvm-project/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py
...
PASS: LLDB (/Users/royshi/public_llvm/build/bin/clang-arm64) :: test_ios (TestSimulatorPlatform.TestSimulatorPlatformLaunching)

Without the patch, the test cannot list processes on the iOS simulator:

$ bin/llvm-lit -av ../llvm-project/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py
...
======================================================================
FAIL: test_ios (TestSimulatorPlatform.TestSimulatorPlatformLaunching)
    Test running an iOS simulator binary
----------------------------------------------------------------------
...
AssertionError: False is not true : Command 'platform process list' did not return successfully
Error output:
error: no processes were found on the "ios-simulator" platform

@royitaqi royitaqi requested a review from JDevlieghere as a code owner May 8, 2025 23:47
@llvmbot llvmbot added the lldb label May 8, 2025
@royitaqi royitaqi requested review from clayborg and jeffreytan81 May 8, 2025 23:48
@llvmbot
Copy link
Member

llvmbot commented May 8, 2025

@llvm/pr-subscribers-lldb

Author: None (royitaqi)

Changes

Benefit

This patch fixes:

  1. After platform select ios-simulator, platform process list will now print processes which are running in the iOS simulator. Previously, no process will be listed.
  2. After platform select ios-simulator, platform attach --name &lt;name&gt; will succeed. Previously, it will error out saying no process is found.

Changes

  1. During the process listing, add aarch64 to the list of CPU types for which iOS simulators are checked for.
  2. Fix a bug in the code which checks for simulators, where for a process running on simulator, the original code will find the desired environment variable and set the OS to iOS, but then the immediate next environment variable will set it back to macOS.
  3. For processes running on simulator, set the triple's Environment to Simulator, so that such processes can pass the filtering in this line. The original code leave it as the default UnknownEnvironment.

Manual test

With this patch:

royshi-mac-home ~/public_llvm/build % bin/lldb
(lldb) platform select ios-simulator

(lldb) platform process list
240 matching processes were found on "ios-simulator"

PID    PARENT USER       TRIPLE                         NAME
====== ====== ========== ============================== ============================
40511  28844  royshi     arm64-apple-ios-simulator      FocusPlayground // my toy iOS app running on simulator
... // omit
28844  1      royshi     arm64-apple-ios-simulator      launchd_sim

(lldb) process attach --name FocusPlayground
Process 40511 stopped
* thread #<!-- -->1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #<!-- -->0: 0x0000000104e3cb70 libsystem_kernel.dylib`mach_msg2_trap + 8
libsystem_kernel.dylib`mach_msg2_trap:
-&gt;  0x104e3cb70 &lt;+8&gt;: ret
... // omit

Without this patch:

royshi-mac-home ~/public_llvm/build % bin/lldb
(lldb) platform select ios-simulator

(lldb) platform process list
error: no processes were found on the "ios-simulator" platform

(lldb) process attach --name FocusPlayground
error: attach failed: could not find a process named FocusPlayground

Unittest

I did a couple of code searches (1, 2) and didn't seem to find any existing tests.

Any suggestion about how to test this?


Full diff: https://github.com/llvm/llvm-project/pull/139174.diff

1 Files Affected:

  • (modified) lldb/source/Host/macosx/objcxx/Host.mm (+15-10)
diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm
index e187bf98188ae..e8a1c597eea53 100644
--- a/lldb/source/Host/macosx/objcxx/Host.mm
+++ b/lldb/source/Host/macosx/objcxx/Host.mm
@@ -595,7 +595,9 @@ DataExtractor data(arg_data.GetBytes(), arg_data_size,
       const llvm::Triple::ArchType triple_arch = triple.getArch();
       const bool check_for_ios_simulator =
           (triple_arch == llvm::Triple::x86 ||
-           triple_arch == llvm::Triple::x86_64);
+           triple_arch == llvm::Triple::x86_64 ||
+           triple_arch == llvm::Triple::aarch64);
+
       const char *cstr = data.GetCStr(&offset);
       if (cstr) {
         process_info.GetExecutableFile().SetFile(cstr, FileSpec::Style::native);
@@ -621,22 +623,25 @@ DataExtractor data(arg_data.GetBytes(), arg_data_size,
           }
 
           Environment &proc_env = process_info.GetEnvironment();
+          bool is_simulator = false;
           while ((cstr = data.GetCStr(&offset))) {
             if (cstr[0] == '\0')
               break;
 
-            if (check_for_ios_simulator) {
-              if (strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) ==
-                  0)
-                process_info.GetArchitecture().GetTriple().setOS(
-                    llvm::Triple::IOS);
-              else
-                process_info.GetArchitecture().GetTriple().setOS(
-                    llvm::Triple::MacOSX);
-            }
+            if (check_for_ios_simulator &&
+                strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) ==
+                    0)
+              is_simulator = true;
 
             proc_env.insert(cstr);
           }
+          llvm::Triple &triple = process_info.GetArchitecture().GetTriple();
+          if (is_simulator) {
+            triple.setOS(llvm::Triple::IOS);
+            triple.setEnvironment(llvm::Triple::Simulator);
+          } else {
+            triple.setOS(llvm::Triple::MacOSX);
+          }
           return true;
         }
       }

@JDevlieghere
Copy link
Member

Could we test this in TestSimulatorPlatform.py?

@royitaqi
Copy link
Contributor Author

royitaqi commented May 9, 2025

Could we test this in TestSimulatorPlatform.py?

@JDevlieghere Thanks for pointer. It seems the tests in that file are all skipped because of this bug number: rdar://76995109.

E.g.

UNSUPPORTED: LLDB (/Users/royshi/public_llvm/build/bin/clang-arm64) :: test_ios (TestSimulatorPlatform.TestSimulatorPlatformLaunching) (skipping unconditionally [rdar://76995109])

Did a bit internet search and couldn't find how to find more info about this bug or why these tests are all skipped. Not sure if I should un-skip them.

What's your advice on my next steps?

@JDevlieghere
Copy link
Member

Could we test this in TestSimulatorPlatform.py?

@JDevlieghere Thanks for pointer. It seems the tests in that file are all skipped because of this bug number: rdar://76995109.

E.g.

UNSUPPORTED: LLDB (/Users/royshi/public_llvm/build/bin/clang-arm64) :: test_ios (TestSimulatorPlatform.TestSimulatorPlatformLaunching) (skipping unconditionally [rdar://76995109])

Did a bit internet search and couldn't find how to find more info about this bug or why these tests are all skipped. Not sure if I should un-skip them.

Ha, that's my radar, and it's no longer relevant. I bisected an issue with the test suite to that particular test, but the last comment says that it wasn't the culprit after all, so there's no reason it should still be disabled.

@royitaqi
Copy link
Contributor Author

Could we test this in TestSimulatorPlatform.py?

@JDevlieghere Thanks for pointer. It seems the tests in that file are all skipped because of this bug number: rdar://76995109.
E.g.

UNSUPPORTED: LLDB (/Users/royshi/public_llvm/build/bin/clang-arm64) :: test_ios (TestSimulatorPlatform.TestSimulatorPlatformLaunching) (skipping unconditionally [rdar://76995109])

Did a bit internet search and couldn't find how to find more info about this bug or why these tests are all skipped. Not sure if I should un-skip them.

Ha, that's my radar, and it's no longer relevant. I bisected an issue with the test suite to that particular test, but the last comment says that it wasn't the culprit after all, so there's no reason it should still be disabled.

Hi @JDevlieghere,

I don't think the test file was very happy when I removed that skip statement (@skipIf(bugnumber="rdar://76995109")). 4 tests coudln't build and 1 had assertion error about a mach-o load command (the other 7 skipped for other reasons). See full result: https://pastebin.com/Ka7KKdkC.

When you have the time, I wonder if you could kindly try on your side and see if they work for you.

FWIW I'm using the following command to build and test:

ls ~/public_llvm/llvm-project
cd ~/public_llvm/build
cmake -G Ninja -DLLVM_ENABLE_PROJECTS="clang;lldb" -DCMAKE_BUILD_TYPE=Debug -DLLVM_ENABLE_RUNTIMES="libcxx;libcxxabi;libunwind" ~/public_llvm/llvm-project/llvm
ninja lldb-api-test-deps
bin/llvm-lit -sv ../llvm-project/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py

@JDevlieghere
Copy link
Member

Thanks for the heads up. The build issue was because we didn't pass USE_SYSTEM_STDLIB, which we need when targeting the simulators. I've revived the test in #142244.

@royitaqi
Copy link
Contributor Author

royitaqi commented Jun 16, 2025

Hi @JDevlieghere ,

Thank you very much for your #142244. I have rebased this patch on top of that and added assertions into the iOS test case to verify that we can get a list of processes on the iOS simulator.

There is something that I don't think blocks this PR but would like to understand:

  1. It seems to me the test binary a.out isn't running on the simulator (doesn't appear in platform process list). Is this expected/intentional?
  2. My original plan was to assert that we can find a.out in the process list. Because of the above, I made the assertion looser, that it verifies that we can get any process list at all. IMHO it still verifies the patch (that we can now get process list, previously completely nothing), but if we can fix 1 then my assertion can be to find a.out.

Thanks,
Roy

Copy link

github-actions bot commented Jun 16, 2025

✅ With the latest revision this PR passed the Python code formatter.

@JDevlieghere
Copy link
Member

  1. It seems to me the test binary a.out isn't running on the simulator (doesn't appear in platform process list). Is this expected/intentional?

I can definitely see the binary running:

jonas            46758   0.0  0.0 410596000  22720 s000  SX    2:43PM   0:00.09 /Users/jonas/llvm/build-ra/lldb-test-build.noindex/macosx/simulator/TestSimulatorPlatform.test_ios/a.out

If it's not showing up in the platform process list then maybe there's a bug in the implementation?

@royitaqi
Copy link
Contributor Author

royitaqi commented Jun 17, 2025

Hi @JDevlieghere,

I think I know why - it's by design: In the Host::FindProcessImpl() for iOS simulator, after getting all processes in the macOS, it filters out the processes which are being debugged (here). a.out is of course being debugged (by the test case) and got filtered out.

Now, there are a few ways we can go:

  1. Merge the patch as is. Downside is that the test isn't super convincing (I added a comment in the test to explain this).
  2. If we want to make the api test to find a.out, we can add a new argument to platform process list (e.g. --all-processes) to skip such filter, then forward such parameter all the way into Host::FindProcessImpl(). However, we will need to implement this new argument for all platforms, which seems to go beyond the scope of this patch.
  3. Instead of finding a.out, we can try to find other processes which must be running on the iOS simulator because of the test. My difficult is that I don't know any of such processes.

Looking forward to your thoughts.

Best,
Roy

@royitaqi royitaqi force-pushed the fix-ios-simulator-process-list-and-attach branch from a8fbaca to 771febc Compare June 19, 2025 00:25
@royitaqi
Copy link
Contributor Author

Hi @JDevlieghere, when you have the time, could you kindly review / see my rely to your previous comment?
#139174 (comment)

@JDevlieghere
Copy link
Member

I think I know why - it's by design: In the Host::FindProcessImpl() for iOS simulator, after getting all processes in the macOS, it filters out the processes which are being debugged (here). a.out is of course being debugged (by the test case) and got filtered out.

Ah, that's unfortunate, but good catch. In TestAppleSimulatorOSType there's a snippet that launched a binary with simctl. Could we use that to launch the binary without it being traced?

$ xcrun simctl spawn -s <device uuid> <path/to/binary>

@jasonmolenda
Copy link
Collaborator

Hi @JDevlieghere,

I think I know why - it's by design: In the Host::FindProcessImpl() for iOS simulator, after getting all processes in the macOS, it filters out the processes which are being debugged

FWIW in general this is done so that you can have multiple debug sessions debugging the same binary being run multiple times. You run one lldb and attach to inferior-process(1), then you run it again, inferior-process(2), and want to attach to it from a second lldb. We don't want to show the inferior-process(1) as an attachable process at all, because only one debugger can control a process. So we only show inferior-process(2).

I haven't followed along with the PR/code enough to know if that's applicable in this case, but that's the general thinking with lldb's process list algorithms - we are trying to show processes that you might be able to attach to. In debugserver well also filter out procsses that are zombies and such, iirc.

@royitaqi
Copy link
Contributor Author

royitaqi commented Jun 20, 2025

FWIW in general this is done so that you can have multiple debug sessions debugging the same binary being run multiple times.

Thanks for the context, @jasonmolenda . Yeah I kinda guessed that that's the reason. It's a good usability feature for sure. GJ to whoever implemented it~

--

In TestAppleSimulatorOSType there's a snippet that launched a binary with simctl. Could we use that to launch the binary without it being traced?

@JDevlieghere Thanks for the suggestion~! Will look for it and update the test. - As always, I appreciate your suggestions, which have been leading me to learnings and better patches.

Copy link

github-actions bot commented Jun 21, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

Copy link
Contributor Author

@royitaqi royitaqi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @JDevlieghere,

In TestAppleSimulatorOSType there's a snippet that launched a binary with simctl. Could we use that to launch the binary without it being traced?

Done. Kindly take a look when you have the time.

TL;DR changes:

  1. Found the snippet you were referring to in TestAppleSimulatorOSType.
  2. Refactored two functions into lldbutil.
  3. Used those two functions in TestSimulatorPlatform to launch a.out separately and find it in the output of platform process list (matching both pid and name).
  4. In order to do 3, I had to rename hello.c and add code so that it prints the pid and also wait for 10s.

I have a question regarding 4, about how to make sure that the hello.cpp builds in Windows. See inline comment.

@royitaqi royitaqi force-pushed the fix-ios-simulator-process-list-and-attach branch from 7cac42a to be6580d Compare June 21, 2025 21:51
@royitaqi
Copy link
Contributor Author

Hi @JDevlieghere and @clayborg ,

Could you kindly review when you have the chance? I think the PR is close to finish, except the "how to make sure hello.cpp builds in Windows" question.

TL;DR updates:

  1. Called xcrun simctl spawn -s <device uuid> <path/to/binary> to launch a.out and verified that its name and pid appear in platform process list.
  2. Did the small fix which @clayborg pointed out, but with a for loop (not a while).

Thanks,
Roy

@JDevlieghere
Copy link
Member

I think the PR is close to finish, except the "how to make sure hello.cpp builds in Windows" question.

Does this test need to build on Windows? That test should only run on Darwin, so if it's properly skipped, we shouldn't even try to build the inferior. The Windows-conditional parts will be dead code.

Besides that this LGTM

@royitaqi
Copy link
Contributor Author

royitaqi commented Jun 25, 2025

The Windows-conditional parts will be dead code.

Hi @JDevlieghere, I have removed the Windows related code. Should be good to go (re-running tests on the side).

FWIW, my bad, I overlooked the @skipUnlessDarwin in the test.

@royitaqi
Copy link
Contributor Author

Hi @clayborg, you want me to merge directly, or you want to take a final look?

Copy link
Collaborator

@clayborg clayborg left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

One possible nit about switching to using a while loop, but looks good.

@royitaqi royitaqi merged commit f63bc84 into llvm:main Jun 25, 2025
7 checks passed
anthonyhatran pushed a commit to anthonyhatran/llvm-project that referenced this pull request Jun 26, 2025
# Benefit

This patch fixes:
1. After `platform select ios-simulator`, `platform process list` will
now print processes which are running in the iOS simulator. Previously,
no process will be listed.
2. After `platform select ios-simulator`, `platform attach --name
<name>` will succeed. Previously, it will error out saying no process is
found.


# Several bugs that is being fixed

1. During the process listing, add `aarch64` to the list of CPU types
for which iOS simulators are checked for.
2. Given a candidate process, when checking for simulators, the original
code will find the desired environment variable (`SIMULATOR_UDID`) and
set the OS to iOS, but then the immediate next environment variable will
set it back to macOS.
3. For processes running on simulator, set the triple's `Environment` to
`Simulator`, so that such processes can pass the filtering [in this
line](https://fburl.com/8nivnrjx). The original code leave it as the
default `UnknownEnvironment`.



# Manual test

**With this patch:**
```
royshi-mac-home ~/public_llvm/build % bin/lldb
(lldb) platform select ios-simulator

(lldb) platform process list
240 matching processes were found on "ios-simulator"

PID    PARENT USER       TRIPLE                         NAME
====== ====== ========== ============================== ============================
40511  28844  royshi     arm64-apple-ios-simulator      FocusPlayground // my toy iOS app running on simulator
... // omit
28844  1      royshi     arm64-apple-ios-simulator      launchd_sim

(lldb) process attach --name FocusPlayground
Process 40511 stopped
* thread llvm#1, queue = 'com.apple.main-thread', stop reason = signal SIGSTOP
    frame #0: 0x0000000104e3cb70 libsystem_kernel.dylib`mach_msg2_trap + 8
libsystem_kernel.dylib`mach_msg2_trap:
->  0x104e3cb70 <+8>: ret
... // omit
```

**Without this patch:**
```
$ bin/lldb
(lldb) platform select ios-simulator

(lldb) platform process list
error: no processes were found on the "ios-simulator" platform

(lldb) process attach --name FocusPlayground
error: attach failed: could not find a process named FocusPlayground
```


# Unittest

See PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants