]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp
Vendor import of lldb trunk r290819:
[FreeBSD/FreeBSD.git] / source / Plugins / Platform / MacOSX / PlatformAppleSimulator.cpp
1 //===-- PlatformAppleSimulator.cpp ------------------------------*- C++ -*-===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9
10 #include "PlatformAppleSimulator.h"
11
12 // C Includes
13 #if defined(__APPLE__)
14 #include <dlfcn.h>
15 #endif
16
17 // C++ Includes
18 #include <mutex>
19 #include <thread>
20 // Other libraries and framework includes
21 // Project 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"
27
28 using namespace lldb;
29 using namespace lldb_private;
30
31 #if !defined(__APPLE__)
32 #define UNSUPPORTED_ERROR ("Apple simulators aren't supported on this platform")
33 #endif
34
35 //------------------------------------------------------------------
36 // Static Functions
37 //------------------------------------------------------------------
38 void PlatformAppleSimulator::Initialize() { PlatformDarwin::Initialize(); }
39
40 void PlatformAppleSimulator::Terminate() { PlatformDarwin::Terminate(); }
41
42 //------------------------------------------------------------------
43 /// Default Constructor
44 //------------------------------------------------------------------
45 PlatformAppleSimulator::PlatformAppleSimulator()
46     : PlatformDarwin(true), m_core_sim_path_mutex(),
47       m_core_simulator_framework_path(), m_device() {}
48
49 //------------------------------------------------------------------
50 /// Destructor.
51 ///
52 /// The destructor is virtual since this class is designed to be
53 /// inherited from by the plug-in instance.
54 //------------------------------------------------------------------
55 PlatformAppleSimulator::~PlatformAppleSimulator() {}
56
57 lldb_private::Error PlatformAppleSimulator::LaunchProcess(
58     lldb_private::ProcessLaunchInfo &launch_info) {
59 #if defined(__APPLE__)
60   LoadCoreSimulator();
61   CoreSimulatorSupport::Device device(GetSimulatorDevice());
62
63   if (device.GetState() != CoreSimulatorSupport::Device::State::Booted) {
64     Error boot_err;
65     device.Boot(boot_err);
66     if (boot_err.Fail())
67       return boot_err;
68   }
69
70   auto spawned = device.Spawn(launch_info);
71
72   if (spawned) {
73     launch_info.SetProcessID(spawned.GetPID());
74     return Error();
75   } else
76     return spawned.GetError();
77 #else
78   Error err;
79   err.SetErrorString(UNSUPPORTED_ERROR);
80   return err;
81 #endif
82 }
83
84 void PlatformAppleSimulator::GetStatus(Stream &strm) {
85 #if defined(__APPLE__)
86   // This will get called by subclasses, so just output status on the
87   // current simulator
88   PlatformAppleSimulator::LoadCoreSimulator();
89
90   CoreSimulatorSupport::DeviceSet devices =
91       CoreSimulatorSupport::DeviceSet::GetAvailableDevices(
92           GetDeveloperDirectory());
93   const size_t num_devices = devices.GetNumDevices();
94   if (num_devices) {
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());
100     }
101
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");
107       }
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");
111
112     } else {
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");
116     }
117
118   } else {
119     strm.Printf("No devices are available.\n");
120   }
121 #else
122   strm.Printf(UNSUPPORTED_ERROR);
123 #endif
124 }
125
126 Error PlatformAppleSimulator::ConnectRemote(Args &args) {
127 #if defined(__APPLE__)
128   Error error;
129   if (args.GetArgumentCount() == 1) {
130     if (m_device)
131       DisconnectRemote();
132     PlatformAppleSimulator::LoadCoreSimulator();
133     const char *arg_cstr = args.GetArgumentAtIndex(0);
134     if (arg_cstr) {
135       std::string arg_str(arg_cstr);
136       CoreSimulatorSupport::DeviceSet devices =
137           CoreSimulatorSupport::DeviceSet::GetAvailableDevices(
138               GetDeveloperDirectory());
139       devices.ForEach(
140           [this, &arg_str](const CoreSimulatorSupport::Device &device) -> bool {
141             if (arg_str == device.GetUDID() || arg_str == device.GetName()) {
142               m_device = device;
143               return false; // Stop iterating
144             } else {
145               return true; // Keep iterating
146             }
147           });
148       if (!m_device)
149         error.SetErrorStringWithFormat(
150             "no device with UDID or name '%s' was found", arg_cstr);
151     }
152   } else {
153     error.SetErrorString("this command take a single UDID argument of the "
154                          "device you want to connect to.");
155   }
156   return error;
157 #else
158   Error err;
159   err.SetErrorString(UNSUPPORTED_ERROR);
160   return err;
161 #endif
162 }
163
164 Error PlatformAppleSimulator::DisconnectRemote() {
165 #if defined(__APPLE__)
166   m_device.reset();
167   return Error();
168 #else
169   Error err;
170   err.SetErrorString(UNSUPPORTED_ERROR);
171   return err;
172 #endif
173 }
174
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
178                     // existing one
179     Error &error) {
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);
188
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);
194       if (process_sp) {
195         launch_info.SetHijackListener(attach_info.GetHijackListener());
196
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);
202
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);
210         }
211       }
212     }
213   }
214
215   return process_sp;
216 #else
217   return ProcessSP();
218 #endif
219 }
220
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();
226     if (developer_dir) {
227       StreamString cs_path;
228       cs_path.Printf(
229           "%s/Library/PrivateFrameworks/CoreSimulator.framework/CoreSimulator",
230           developer_dir);
231       const bool resolve_path = true;
232       m_core_simulator_framework_path =
233           FileSpec(cs_path.GetData(), resolve_path);
234     }
235   }
236
237   return m_core_simulator_framework_path.getValue();
238 #else
239   return FileSpec();
240 #endif
241 }
242
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);
250   });
251 #endif
252 }
253
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);
262   }
263
264   if (m_device.hasValue())
265     return m_device.getValue();
266   else
267     return CoreSimulatorSupport::Device();
268 }
269 #endif