//===-- PlatformAppleSimulator.cpp ------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// #include "PlatformAppleSimulator.h" // C Includes #if defined(__APPLE__) #include #endif // C++ Includes #include #include // Other libraries and framework includes // Project includes #include "lldb/Core/Error.h" #include "lldb/Core/StreamString.h" #include "lldb/Target/Process.h" #include "lldb/Utility/LLDBAssert.h" #include "lldb/Utility/PseudoTerminal.h" using namespace lldb; using namespace lldb_private; #if !defined(__APPLE__) #define UNSUPPORTED_ERROR ("Apple simulators aren't supported on this platform") #endif //------------------------------------------------------------------ // Static Functions //------------------------------------------------------------------ void PlatformAppleSimulator::Initialize () { PlatformDarwin::Initialize (); } void PlatformAppleSimulator::Terminate () { PlatformDarwin::Terminate (); } //------------------------------------------------------------------ /// Default Constructor //------------------------------------------------------------------ PlatformAppleSimulator::PlatformAppleSimulator () : PlatformDarwin (true), m_core_simulator_framework_path() { } //------------------------------------------------------------------ /// Destructor. /// /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. //------------------------------------------------------------------ PlatformAppleSimulator::~PlatformAppleSimulator() { } lldb_private::Error PlatformAppleSimulator::LaunchProcess (lldb_private::ProcessLaunchInfo &launch_info) { #if defined(__APPLE__) LoadCoreSimulator(); CoreSimulatorSupport::Device device(GetSimulatorDevice()); if (device.GetState() != CoreSimulatorSupport::Device::State::Booted) { Error boot_err; device.Boot(boot_err); if (boot_err.Fail()) return boot_err; } auto spawned = device.Spawn(launch_info); if (spawned) { launch_info.SetProcessID(spawned.GetPID()); return Error(); } else return spawned.GetError(); #else Error err; err.SetErrorString(UNSUPPORTED_ERROR); return err; #endif } void PlatformAppleSimulator::GetStatus (Stream &strm) { #if defined(__APPLE__) // This will get called by subclasses, so just output status on the // current simulator PlatformAppleSimulator::LoadCoreSimulator(); CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices(); const size_t num_devices = devices.GetNumDevices(); if (num_devices) { strm.Printf("Available devices:\n"); for (size_t i=0; ioperator bool()) { strm.Printf("Current device: %s: %s", m_device->GetUDID().c_str(), m_device->GetName().c_str()); if (m_device->GetState() == CoreSimulatorSupport::Device::State::Booted) { strm.Printf(" state = booted"); } strm.Printf("\nType \"platform connect \" where is a device UDID or a device name to disconnect and connect to a different device.\n"); } else { strm.Printf("No current device is selected, \"platform connect \" where is a device UDID or a device name to connect to a specific device.\n"); } } else { strm.Printf("No devices are available.\n"); } #else strm.Printf(UNSUPPORTED_ERROR); #endif } Error PlatformAppleSimulator::ConnectRemote (Args& args) { #if defined(__APPLE__) Error error; if (args.GetArgumentCount() == 1) { if (m_device) DisconnectRemote (); PlatformAppleSimulator::LoadCoreSimulator(); const char *arg_cstr = args.GetArgumentAtIndex(0); if (arg_cstr) { std::string arg_str(arg_cstr); CoreSimulatorSupport::DeviceSet devices = CoreSimulatorSupport::DeviceSet::GetAvailableDevices(); devices.ForEach([this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool { if (arg_str == device.GetUDID() || arg_str == device.GetName()) { m_device = device; return false; // Stop iterating } else { return true; // Keep iterating } }); if (!m_device) error.SetErrorStringWithFormat("no device with UDID or name '%s' was found", arg_cstr); } } else { error.SetErrorString("this command take a single UDID argument of the device you want to connect to."); } return error; #else Error err; err.SetErrorString(UNSUPPORTED_ERROR); return err; #endif } Error PlatformAppleSimulator::DisconnectRemote () { #if defined(__APPLE__) m_device.reset(); return Error(); #else Error err; err.SetErrorString(UNSUPPORTED_ERROR); return err; #endif } lldb::ProcessSP PlatformAppleSimulator::DebugProcess (ProcessLaunchInfo &launch_info, Debugger &debugger, Target *target, // Can be NULL, if NULL create a new target, else use existing one Error &error) { #if defined(__APPLE__) ProcessSP process_sp; // Make sure we stop at the entry point launch_info.GetFlags ().Set (eLaunchFlagDebug); // We always launch the process we are going to debug in a separate process // group, since then we can handle ^C interrupts ourselves w/o having to worry // about the target getting them as well. launch_info.SetLaunchInSeparateProcessGroup(true); error = LaunchProcess (launch_info); if (error.Success()) { if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { ProcessAttachInfo attach_info (launch_info); process_sp = Attach (attach_info, debugger, target, error); if (process_sp) { launch_info.SetHijackListener(attach_info.GetHijackListener()); // Since we attached to the process, it will think it needs to detach // if the process object just goes away without an explicit call to // Process::Kill() or Process::Detach(), so let it know to kill the // process if this happens. process_sp->SetShouldDetach (false); // If we didn't have any file actions, the pseudo terminal might // have been used where the slave side was given as the file to // open for stdin/out/err after we have already opened the master // so we can read/write stdin/out/err. int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) { process_sp->SetSTDIOFileDescriptor(pty_fd); } } } } return process_sp; #else return ProcessSP(); #endif } FileSpec PlatformAppleSimulator::GetCoreSimulatorPath() { #if defined(__APPLE__) Mutex::Locker locker (m_mutex); if (!m_core_simulator_framework_path.hasValue()) { const char *developer_dir = GetDeveloperDirectory(); if (developer_dir) { StreamString cs_path; cs_path.Printf("%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator", developer_dir); const bool resolve_path = true; m_core_simulator_framework_path = FileSpec(cs_path.GetData(), resolve_path); } } return m_core_simulator_framework_path.getValue(); #else return FileSpec(); #endif } void PlatformAppleSimulator::LoadCoreSimulator () { #if defined(__APPLE__) static std::once_flag g_load_core_sim_flag; std::call_once(g_load_core_sim_flag, [this] { const std::string core_sim_path(GetCoreSimulatorPath().GetPath()); if (core_sim_path.size()) dlopen(core_sim_path.c_str(), RTLD_LAZY); }); #endif } #if defined(__APPLE__) CoreSimulatorSupport::Device PlatformAppleSimulator::GetSimulatorDevice () { if (!m_device.hasValue()) { const CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id = CoreSimulatorSupport::DeviceType::ProductFamilyID::iPhone; m_device = CoreSimulatorSupport::DeviceSet::GetAvailableDevices().GetFanciest(dev_id); } if (m_device.hasValue()) return m_device.getValue(); else return CoreSimulatorSupport::Device(); } #endif