1 //===-- PlatformAppleSimulator.cpp ------------------------------*- C++ -*-===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 #include "PlatformAppleSimulator.h"
13 #if defined(__APPLE__)
20 // Other libraries and framework includes
22 #include "lldb/Core/Error.h"
23 #include "lldb/Core/StreamString.h"
24 #include "lldb/Target/Process.h"
25 #include "lldb/Utility/LLDBAssert.h"
26 #include "lldb/Utility/PseudoTerminal.h"
29 using namespace lldb_private;
31 #if !defined(__APPLE__)
32 #define UNSUPPORTED_ERROR ("Apple simulators aren't supported on this platform")
35 //------------------------------------------------------------------
37 //------------------------------------------------------------------
38 void PlatformAppleSimulator::Initialize() { PlatformDarwin::Initialize(); }
40 void PlatformAppleSimulator::Terminate() { PlatformDarwin::Terminate(); }
42 //------------------------------------------------------------------
43 /// Default Constructor
44 //------------------------------------------------------------------
45 PlatformAppleSimulator::PlatformAppleSimulator()
46 : PlatformDarwin(true), m_core_sim_path_mutex(),
47 m_core_simulator_framework_path(), m_device() {}
49 //------------------------------------------------------------------
52 /// The destructor is virtual since this class is designed to be
53 /// inherited from by the plug-in instance.
54 //------------------------------------------------------------------
55 PlatformAppleSimulator::~PlatformAppleSimulator() {}
57 lldb_private::Error PlatformAppleSimulator::LaunchProcess(
58 lldb_private::ProcessLaunchInfo &launch_info) {
59 #if defined(__APPLE__)
61 CoreSimulatorSupport::Device device(GetSimulatorDevice());
63 if (device.GetState() != CoreSimulatorSupport::Device::State::Booted) {
65 device.Boot(boot_err);
70 auto spawned = device.Spawn(launch_info);
73 launch_info.SetProcessID(spawned.GetPID());
76 return spawned.GetError();
79 err.SetErrorString(UNSUPPORTED_ERROR);
84 void PlatformAppleSimulator::GetStatus(Stream &strm) {
85 #if defined(__APPLE__)
86 // This will get called by subclasses, so just output status on the
88 PlatformAppleSimulator::LoadCoreSimulator();
90 CoreSimulatorSupport::DeviceSet devices =
91 CoreSimulatorSupport::DeviceSet::GetAvailableDevices(
92 GetDeveloperDirectory());
93 const size_t num_devices = devices.GetNumDevices();
95 strm.Printf("Available devices:\n");
96 for (size_t i = 0; i < num_devices; ++i) {
97 CoreSimulatorSupport::Device device = devices.GetDeviceAtIndex(i);
98 strm.Printf(" %s: %s\n", device.GetUDID().c_str(),
99 device.GetName().c_str());
102 if (m_device.hasValue() && m_device->operator bool()) {
103 strm.Printf("Current device: %s: %s", m_device->GetUDID().c_str(),
104 m_device->GetName().c_str());
105 if (m_device->GetState() == CoreSimulatorSupport::Device::State::Booted) {
106 strm.Printf(" state = booted");
108 strm.Printf("\nType \"platform connect <ARG>\" where <ARG> is a device "
109 "UDID or a device name to disconnect and connect to a "
110 "different device.\n");
113 strm.Printf("No current device is selected, \"platform connect <ARG>\" "
114 "where <ARG> is a device UDID or a device name to connect to "
115 "a specific device.\n");
119 strm.Printf("No devices are available.\n");
122 strm.Printf(UNSUPPORTED_ERROR);
126 Error PlatformAppleSimulator::ConnectRemote(Args &args) {
127 #if defined(__APPLE__)
129 if (args.GetArgumentCount() == 1) {
132 PlatformAppleSimulator::LoadCoreSimulator();
133 const char *arg_cstr = args.GetArgumentAtIndex(0);
135 std::string arg_str(arg_cstr);
136 CoreSimulatorSupport::DeviceSet devices =
137 CoreSimulatorSupport::DeviceSet::GetAvailableDevices(
138 GetDeveloperDirectory());
140 [this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool {
141 if (arg_str == device.GetUDID() || arg_str == device.GetName()) {
143 return false; // Stop iterating
145 return true; // Keep iterating
149 error.SetErrorStringWithFormat(
150 "no device with UDID or name '%s' was found", arg_cstr);
153 error.SetErrorString("this command take a single UDID argument of the "
154 "device you want to connect to.");
159 err.SetErrorString(UNSUPPORTED_ERROR);
164 Error PlatformAppleSimulator::DisconnectRemote() {
165 #if defined(__APPLE__)
170 err.SetErrorString(UNSUPPORTED_ERROR);
175 lldb::ProcessSP PlatformAppleSimulator::DebugProcess(
176 ProcessLaunchInfo &launch_info, Debugger &debugger,
177 Target *target, // Can be NULL, if NULL create a new target, else use
180 #if defined(__APPLE__)
181 ProcessSP process_sp;
182 // Make sure we stop at the entry point
183 launch_info.GetFlags().Set(eLaunchFlagDebug);
184 // We always launch the process we are going to debug in a separate process
185 // group, since then we can handle ^C interrupts ourselves w/o having to worry
186 // about the target getting them as well.
187 launch_info.SetLaunchInSeparateProcessGroup(true);
189 error = LaunchProcess(launch_info);
190 if (error.Success()) {
191 if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) {
192 ProcessAttachInfo attach_info(launch_info);
193 process_sp = Attach(attach_info, debugger, target, error);
195 launch_info.SetHijackListener(attach_info.GetHijackListener());
197 // Since we attached to the process, it will think it needs to detach
198 // if the process object just goes away without an explicit call to
199 // Process::Kill() or Process::Detach(), so let it know to kill the
200 // process if this happens.
201 process_sp->SetShouldDetach(false);
203 // If we didn't have any file actions, the pseudo terminal might
204 // have been used where the slave side was given as the file to
205 // open for stdin/out/err after we have already opened the master
206 // so we can read/write stdin/out/err.
207 int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
208 if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) {
209 process_sp->SetSTDIOFileDescriptor(pty_fd);
221 FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() {
222 #if defined(__APPLE__)
223 std::lock_guard<std::mutex> guard(m_core_sim_path_mutex);
224 if (!m_core_simulator_framework_path.hasValue()) {
225 const char *developer_dir = GetDeveloperDirectory();
227 StreamString cs_path;
229 "%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator",
231 const bool resolve_path = true;
232 m_core_simulator_framework_path =
233 FileSpec(cs_path.GetData(), resolve_path);
237 return m_core_simulator_framework_path.getValue();
243 void PlatformAppleSimulator::LoadCoreSimulator() {
244 #if defined(__APPLE__)
245 static std::once_flag g_load_core_sim_flag;
246 std::call_once(g_load_core_sim_flag, [this] {
247 const std::string core_sim_path(GetCoreSimulatorPath().GetPath());
248 if (core_sim_path.size())
249 dlopen(core_sim_path.c_str(), RTLD_LAZY);
254 #if defined(__APPLE__)
255 CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice() {
256 if (!m_device.hasValue()) {
257 const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id =
258 CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone;
259 m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices(
260 GetDeveloperDirectory())
261 .GetFanciest(dev_id);
264 if (m_device.hasValue())
265 return m_device.getValue();
267 return CoreSimulatorSupport::Device();