diff options
Diffstat (limited to 'source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp')
| -rw-r--r-- | source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp | 303 | 
1 files changed, 303 insertions, 0 deletions
diff --git a/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp new file mode 100644 index 000000000000..eea2844d5649 --- /dev/null +++ b/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp @@ -0,0 +1,303 @@ +//===-- 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 <dlfcn.h> +#endif + +// C++ Includes +#include <mutex> +#include <thread> +// 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; i<num_devices; ++i) +        { +            CoreSimulatorSupport::Device device = devices.GetDeviceAtIndex(i); +            strm.Printf("   %s: %s\n", device.GetUDID().c_str(), device.GetName().c_str()); +        } + +        if (m_device.hasValue() && m_device->operator 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 <ARG>\" where <ARG> 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 <ARG>\" where <ARG> 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 +  | 
