https://github.com/royitaqi updated https://github.com/llvm/llvm-project/pull/139174
>From d98210b81f7b49f5384e968b1a18e00e432aaf2c Mon Sep 17 00:00:00 2001 From: Roy Shi <roy...@meta.com> Date: Thu, 8 May 2025 16:21:53 -0700 Subject: [PATCH 1/6] Fix macOS FindProcessImpl() --- lldb/source/Host/macosx/objcxx/Host.mm | 25 +++++++++++++++---------- 1 file changed, 15 insertions(+), 10 deletions(-) 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; } } >From 8377bc3b61fb30c003d1d188d6e8d879baea58ab Mon Sep 17 00:00:00 2001 From: Roy Shi <roy...@meta.com> Date: Mon, 16 Jun 2025 11:06:47 -0700 Subject: [PATCH 2/6] Add test --- lldb/test/API/macosx/simulator/TestSimulatorPlatform.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py index 74ba0ee6c83bb..8406ee45479fd 100644 --- a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py +++ b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py @@ -39,7 +39,7 @@ def check_debugserver(self, log, expected_platform, expected_version): if expected_version: self.assertEqual(aout_info["min_version_os_sdk"], expected_version) - def run_with(self, arch, os, vers, env, expected_load_command): + def run_with(self, arch, os, vers, env, expected_load_command, expected_platform=None): env_list = [env] if env else [] triple = "-".join([arch, "apple", os + vers] + env_list) sdk = lldbutil.get_xcode_sdk(os, env) @@ -75,6 +75,11 @@ def run_with(self, arch, os, vers, env, expected_load_command): self, "break here", lldb.SBFileSpec("hello.c") ) triple_re = "-".join([arch, "apple", os + vers + ".*"] + env_list) + if expected_platform is not None: + # The current platform should be expected + self.expect("platform status", patterns=[r"Platform: " + expected_platform]) + # Should be able to list processes on the current platform + self.expect("platform process list", patterns=[r"\d+ matching processes were found on \"%s\"" % expected_platform]) self.expect("image list -b -t", patterns=[r"a\.out " + triple_re]) self.check_debugserver(log, os + env, vers) @@ -90,6 +95,7 @@ def test_ios(self): vers="", env="simulator", expected_load_command="LC_BUILD_VERSION", + expected_platform="ios-simulator", ) @skipIfAsan >From 2c31b44d01a7a8bc0fece27fed8162c599aa8387 Mon Sep 17 00:00:00 2001 From: Roy Shi <roy...@meta.com> Date: Mon, 16 Jun 2025 15:02:56 -0700 Subject: [PATCH 3/6] Fix format --- .../API/macosx/simulator/TestSimulatorPlatform.py | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py index 8406ee45479fd..44a5a942ab513 100644 --- a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py +++ b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py @@ -39,7 +39,9 @@ def check_debugserver(self, log, expected_platform, expected_version): if expected_version: self.assertEqual(aout_info["min_version_os_sdk"], expected_version) - def run_with(self, arch, os, vers, env, expected_load_command, expected_platform=None): + def run_with( + self, arch, os, vers, env, expected_load_command, expected_platform=None + ): env_list = [env] if env else [] triple = "-".join([arch, "apple", os + vers] + env_list) sdk = lldbutil.get_xcode_sdk(os, env) @@ -79,7 +81,12 @@ def run_with(self, arch, os, vers, env, expected_load_command, expected_platform # The current platform should be expected self.expect("platform status", patterns=[r"Platform: " + expected_platform]) # Should be able to list processes on the current platform - self.expect("platform process list", patterns=[r"\d+ matching processes were found on \"%s\"" % expected_platform]) + self.expect( + "platform process list", + patterns=[ + r"\d+ matching processes were found on \"%s\"" % expected_platform + ], + ) self.expect("image list -b -t", patterns=[r"a\.out " + triple_re]) self.check_debugserver(log, os + env, vers) >From 3d6715699007bb22bda26cf196bee91f24ef9e91 Mon Sep 17 00:00:00 2001 From: Roy Shi <roy...@meta.com> Date: Tue, 17 Jun 2025 07:39:17 -0700 Subject: [PATCH 4/6] Minor updates to code and comments --- lldb/source/Host/macosx/objcxx/Host.mm | 4 ++-- .../API/macosx/simulator/TestSimulatorPlatform.py | 11 ++++++++--- 2 files changed, 10 insertions(+), 5 deletions(-) diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index e8a1c597eea53..66e7741fc53e7 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -746,8 +746,8 @@ static bool GetMacOSXProcessUserAndGroup(ProcessInstanceInfo &process_info) { !match_info.ProcessIDsMatch(process_info)) continue; - // Get CPU type first so we can know to look for iOS simulator is we have - // x86 or x86_64 + // Get CPU type first so we can know to look for iOS simulator if we have + // a compatible type. if (GetMacOSXProcessCPUType(process_info)) { if (GetMacOSXProcessArgs(&match_info, process_info)) { if (match_info.Matches(process_info)) diff --git a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py index 44a5a942ab513..0d09bfee9b961 100644 --- a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py +++ b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py @@ -77,17 +77,22 @@ def run_with( self, "break here", lldb.SBFileSpec("hello.c") ) triple_re = "-".join([arch, "apple", os + vers + ".*"] + env_list) + self.expect("image list -b -t", patterns=[r"a\.out " + triple_re]) if expected_platform is not None: - # The current platform should be expected + # Verify the platform name. self.expect("platform status", patterns=[r"Platform: " + expected_platform]) - # Should be able to list processes on the current platform + # Verify that processes on the platform can be listed. + # + # Note: The `Host::FindProcessesImpl()` of some of the Hosts filters out processes which are being debugged. + # (e.g. code for iOS simulator linked below). So we cannot verify that `a.out` is in the process list + # (because its already being debugged by this test). + # https://github.com/llvm/llvm-project/blob/b5dbf8210a57b986b9802304745f4c5c108cf37b/lldb/source/Host/macosx/objcxx/Host.mm#L724 self.expect( "platform process list", patterns=[ r"\d+ matching processes were found on \"%s\"" % expected_platform ], ) - self.expect("image list -b -t", patterns=[r"a\.out " + triple_re]) self.check_debugserver(log, os + env, vers) @skipIfAsan >From 771febc0529af2cdab2d57c524ed9a5c8ef06c6f Mon Sep 17 00:00:00 2001 From: Roy Shi <roy...@meta.com> Date: Wed, 18 Jun 2025 17:17:39 -0700 Subject: [PATCH 5/6] A small cleanup --- lldb/source/Host/macosx/objcxx/Host.mm | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/lldb/source/Host/macosx/objcxx/Host.mm b/lldb/source/Host/macosx/objcxx/Host.mm index 66e7741fc53e7..2834a26908cf0 100644 --- a/lldb/source/Host/macosx/objcxx/Host.mm +++ b/lldb/source/Host/macosx/objcxx/Host.mm @@ -624,16 +624,12 @@ 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; - + for (llvm::StringRef env_var; + !(env_var = data.GetCStr(&offset)).empty();) { if (check_for_ios_simulator && - strncmp(cstr, "SIMULATOR_UDID=", strlen("SIMULATOR_UDID=")) == - 0) + env_var.starts_with("SIMULATOR_UDID=")) is_simulator = true; - - proc_env.insert(cstr); + proc_env.insert(env_var); } llvm::Triple &triple = process_info.GetArchitecture().GetTriple(); if (is_simulator) { >From be6580dc6a3f5169aac5b9e6035e699520424cd5 Mon Sep 17 00:00:00 2001 From: Roy Shi <roy...@meta.com> Date: Sat, 21 Jun 2025 14:19:47 -0700 Subject: [PATCH 6/6] Run a.out in simulator and find it --- .../Python/lldbsuite/test/lldbutil.py | 87 +++++++++++++++++++ lldb/test/API/macosx/simulator/Makefile | 5 +- .../macosx/simulator/TestSimulatorPlatform.py | 40 ++++++--- lldb/test/API/macosx/simulator/hello.c | 5 -- lldb/test/API/macosx/simulator/hello.cpp | 22 +++++ .../lldb-server/TestAppleSimulatorOSType.py | 72 ++++----------- 6 files changed, 158 insertions(+), 73 deletions(-) delete mode 100644 lldb/test/API/macosx/simulator/hello.c create mode 100644 lldb/test/API/macosx/simulator/hello.cpp diff --git a/lldb/packages/Python/lldbsuite/test/lldbutil.py b/lldb/packages/Python/lldbsuite/test/lldbutil.py index 27e0040034370..8112705438c1f 100644 --- a/lldb/packages/Python/lldbsuite/test/lldbutil.py +++ b/lldb/packages/Python/lldbsuite/test/lldbutil.py @@ -7,6 +7,7 @@ # System modules import errno import io +import json import os import re import sys @@ -1704,3 +1705,89 @@ def packetlog_get_dylib_info(log): expect_dylib_info_response = True return dylib_info + + +# ======================== +# Utilities for simulators +# ======================== + + +def get_latest_apple_simulator(platform_name, log=None): + # Run simctl to list all simulators + cmd = ["xcrun", "simctl", "list", "-j", "devices"] + cmd_str = " ".join(cmd) + if log: + log(cmd_str) + sim_devices_str = subprocess.check_output(cmd).decode("utf-8") + sim_devices = json.loads(sim_devices_str)["devices"] + + # Find an available simulator for the requested platform + device_uuid = None + device_runtime = None + for simulator in sim_devices: + if isinstance(simulator, dict): + runtime = simulator["name"] + devices = simulator["devices"] + else: + runtime = simulator + devices = sim_devices[simulator] + if not platform_name in runtime.lower(): + continue + for device in devices: + if "availability" in device and device["availability"] != "(available)": + continue + if "isAvailable" in device and not device["isAvailable"]: + continue + if device_runtime and runtime < device_runtime: + continue + device_uuid = device["udid"] + device_runtime = runtime + # Stop searching in this runtime + break + + return device_uuid + + +def launch_exe_in_apple_simulator( + device_uuid, + exe_path, + exe_args=[], + stderr_lines_to_read=0, + stderr_patterns=[], + log=None, +): + exe_path = os.path.realpath(exe_path) + cmd = [ + "xcrun", + "simctl", + "spawn", + "-s", + device_uuid, + exe_path, + ] + exe_args + if log: + log(" ".join(cmd)) + sim_launcher = subprocess.Popen(cmd, stderr=subprocess.PIPE) + + # Read stderr to try to find matches. + # Each pattern will return the value of group[1] of the first match in the stderr. + # Will read at most stderr_lines_to_read lines. + # Will early terminate when all matches have been found. + total_patterns = len(stderr_patterns) + matches_found = 0 + matched_strings = [None] * total_patterns + for _ in range(0, stderr_lines_to_read): + stderr = sim_launcher.stderr.readline().decode("utf-8") + if not stderr: + continue + for i, pattern in enumerate(stderr_patterns): + if matched_strings[i] is not None: + continue + match = re.match(pattern, stderr) + if match: + matched_strings[i] = str(match.group(1)) + matches_found += 1 + if matches_found == total_patterns: + break + + return exe_path, matched_strings diff --git a/lldb/test/API/macosx/simulator/Makefile b/lldb/test/API/macosx/simulator/Makefile index 421e85117613a..ce3490d28ee8e 100644 --- a/lldb/test/API/macosx/simulator/Makefile +++ b/lldb/test/API/macosx/simulator/Makefile @@ -1,3 +1,6 @@ -C_SOURCES := hello.c +CFLAGS_EXTRAS := -D__STDC_LIMIT_MACROS -D__STDC_FORMAT_MACROS +ENABLE_THREADS := YES +CXX_SOURCES := hello.cpp +MAKE_DSYM := NO include Makefile.rules diff --git a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py index 0d09bfee9b961..b17ee83ea04fe 100644 --- a/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py +++ b/lldb/test/API/macosx/simulator/TestSimulatorPlatform.py @@ -74,26 +74,46 @@ def run_with( log = self.getBuildArtifact("packets.log") self.expect("log enable gdb-remote packets -f " + log) lldbutil.run_to_source_breakpoint( - self, "break here", lldb.SBFileSpec("hello.c") + self, "break here", lldb.SBFileSpec("hello.cpp") ) triple_re = "-".join([arch, "apple", os + vers + ".*"] + env_list) self.expect("image list -b -t", patterns=[r"a\.out " + triple_re]) + self.check_debugserver(log, os + env, vers) + if expected_platform is not None: # Verify the platform name. - self.expect("platform status", patterns=[r"Platform: " + expected_platform]) + self.expect( + "platform status", + patterns=[r"Platform: " + expected_platform + "-simulator"], + ) + + # Launch exe in simulator and verify that `platform process list` can find the process. + # This separate launch is needed because the command ignores processes which are being debugged. + device_udid = lldbutil.get_latest_apple_simulator( + expected_platform, self.trace + ) + _, matched_strings = lldbutil.launch_exe_in_apple_simulator( + device_udid, + self.getBuildArtifact("a.out"), + exe_args=[], + stderr_lines_to_read=1, # in hello.cpp, the pid is printed first + stderr_patterns=[r"PID: (.*)"], + log=self.trace, + ) + + # Make sure we found the PID. + self.assertIsNotNone(matched_strings[0]) + pid = int(matched_strings[0]) + # Verify that processes on the platform can be listed. - # - # Note: The `Host::FindProcessesImpl()` of some of the Hosts filters out processes which are being debugged. - # (e.g. code for iOS simulator linked below). So we cannot verify that `a.out` is in the process list - # (because its already being debugged by this test). - # https://github.com/llvm/llvm-project/blob/b5dbf8210a57b986b9802304745f4c5c108cf37b/lldb/source/Host/macosx/objcxx/Host.mm#L724 self.expect( "platform process list", patterns=[ - r"\d+ matching processes were found on \"%s\"" % expected_platform + r"\d+ matching processes were found on \"%s-simulator\"" + % expected_platform, + r"%d .+ a.out" % pid, ], ) - self.check_debugserver(log, os + env, vers) @skipIfAsan @skipUnlessDarwin @@ -107,7 +127,7 @@ def test_ios(self): vers="", env="simulator", expected_load_command="LC_BUILD_VERSION", - expected_platform="ios-simulator", + expected_platform="ios", ) @skipIfAsan diff --git a/lldb/test/API/macosx/simulator/hello.c b/lldb/test/API/macosx/simulator/hello.c deleted file mode 100644 index 9010d0e295154..0000000000000 --- a/lldb/test/API/macosx/simulator/hello.c +++ /dev/null @@ -1,5 +0,0 @@ -void puts(char *); -int main(int argc, char **argv) { - puts("break here\n"); - return 0; -} diff --git a/lldb/test/API/macosx/simulator/hello.cpp b/lldb/test/API/macosx/simulator/hello.cpp new file mode 100644 index 0000000000000..4c697059e8f9a --- /dev/null +++ b/lldb/test/API/macosx/simulator/hello.cpp @@ -0,0 +1,22 @@ +#include <stdio.h> +#include <thread> +#if !defined(_WIN32) +#include <unistd.h> +#endif + +static void print_pid() { +#if defined(_WIN32) + fprintf(stderr, "PID: %d\n", ::GetCurrentProcessId()); +#else + fprintf(stderr, "PID: %d\n", getpid()); +#endif +} + +static void sleep() { std::this_thread::sleep_for(std::chrono::seconds(10)); } + +int main(int argc, char **argv) { + print_pid(); + puts("break here\n"); + sleep(); + return 0; +} diff --git a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py index ed47f94e9492b..4fee27823f1fa 100644 --- a/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py +++ b/lldb/test/API/tools/lldb-server/TestAppleSimulatorOSType.py @@ -14,40 +14,12 @@ class TestAppleSimulatorOSType(gdbremote_testcase.GdbRemoteTestCaseBase): READ_LINES = 10 def check_simulator_ostype(self, sdk, platform_name, arch=platform.machine()): - cmd = ["xcrun", "simctl", "list", "-j", "devices"] - cmd_str = " ".join(cmd) - self.trace(cmd_str) - sim_devices_str = subprocess.check_output(cmd).decode("utf-8") + # Get simulator + deviceUDID = None try: - sim_devices = json.loads(sim_devices_str)["devices"] + deviceUDID = lldbutil.get_latest_apple_simulator(platform_name, self.trace) except json.decoder.JSONDecodeError: - self.fail( - "Could not parse '{}' output. Authorization denied?".format(cmd_str) - ) - # Find an available simulator for the requested platform - deviceUDID = None - deviceRuntime = None - for simulator in sim_devices: - if isinstance(simulator, dict): - runtime = simulator["name"] - devices = simulator["devices"] - else: - runtime = simulator - devices = sim_devices[simulator] - if not platform_name in runtime.lower(): - continue - for device in devices: - if "availability" in device and device["availability"] != "(available)": - continue - if "isAvailable" in device and not device["isAvailable"]: - continue - if deviceRuntime and runtime < deviceRuntime: - continue - deviceUDID = device["udid"] - deviceRuntime = runtime - # Stop searching in this runtime - break - + self.fail("Could not parse output. Authorization denied?") if not deviceUDID: self.skipTest( "Could not find a simulator for {} ({})".format(platform_name, arch) @@ -78,34 +50,20 @@ def check_simulator_ostype(self, sdk, platform_name, arch=platform.machine()): }, compiler=clang, ) - exe_path = os.path.realpath(self.getBuildArtifact(exe_name)) - cmd = [ - "xcrun", - "simctl", - "spawn", - "-s", + + # Launch the executable in the simulator + exe_path, matched_groups = lldbutil.launch_exe_in_apple_simulator( deviceUDID, - exe_path, - "print-pid", - "sleep:10", - ] - self.trace(" ".join(cmd)) - sim_launcher = subprocess.Popen(cmd, stderr=subprocess.PIPE) - # Get the PID from the process output - pid = None - - # Read the first READ_LINES to try to find the PID. - for _ in range(0, self.READ_LINES): - stderr = sim_launcher.stderr.readline().decode("utf-8") - if not stderr: - continue - match = re.match(r"PID: (.*)", stderr) - if match: - pid = int(match.group(1)) - break + self.getBuildArtifact(exe_name), + ["print-pid", "sleep:10"], + self.READ_LINES, + [r"PID: (.*)"], + self.trace, + ) # Make sure we found the PID. - self.assertIsNotNone(pid) + self.assertIsNotNone(matched_groups[0]) + pid = int(matched_groups[0]) # Launch debug monitor attaching to the simulated process server = self.connect_to_debug_monitor(attach_pid=pid) _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits