/Users/buildslave/jenkins/workspace/coverage/llvm-project/lldb/source/Plugins/Platform/MacOSX/objcxx/PlatformiOSSimulatorCoreSimulatorSupport.mm
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- PlatformiOSSimulatorCoreSimulatorSupport.cpp ----------------------===// |
2 | | // |
3 | | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
4 | | // See https://llvm.org/LICENSE.txt for license information. |
5 | | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
6 | | // |
7 | | //===----------------------------------------------------------------------===// |
8 | | |
9 | | #include "PlatformiOSSimulatorCoreSimulatorSupport.h" |
10 | | |
11 | | // C Includes |
12 | | // C++ Includes |
13 | | // Other libraries and framework includes |
14 | | #include <CoreFoundation/CoreFoundation.h> |
15 | | #include <Foundation/Foundation.h> |
16 | | // Project includes |
17 | | #include "lldb/Host/PseudoTerminal.h" |
18 | | #include "lldb/Host/FileAction.h" |
19 | | |
20 | | #include "llvm/ADT/StringRef.h" |
21 | | |
22 | | using namespace lldb_private; |
23 | | // CoreSimulator lives as part of Xcode, which means we can't really link |
24 | | // against it, so we dlopen() |
25 | | // it at runtime, and error out nicely if that fails |
26 | | @interface SimServiceContext { |
27 | | } |
28 | | + (id)sharedServiceContextForDeveloperDir:(NSString *)dir |
29 | | error:(NSError **)error; |
30 | | @end |
31 | | // However, the drawback is that the compiler will not know about the selectors |
32 | | // we're trying to use |
33 | | // until runtime; to appease clang in this regard, define a fake protocol on |
34 | | // NSObject that exposes |
35 | | // the needed interface names for us |
36 | | @protocol LLDBCoreSimulatorSupport <NSObject> |
37 | | - (id)defaultDeviceSetWithError:(NSError **)error; |
38 | | - (NSArray *)devices; |
39 | | - (id)deviceType; |
40 | | - (NSString *)name; |
41 | | - (NSString *)identifier; |
42 | | - (NSString *)modelIdentifier; |
43 | | - (NSString *)productFamily; |
44 | | - (int32_t)productFamilyID; |
45 | | - (id)runtime; |
46 | | - (BOOL)available; |
47 | | - (NSString *)versionString; |
48 | | - (NSString *)buildVersionString; |
49 | | - (BOOL)bootWithOptions:(NSDictionary *)options error:(NSError **)error; |
50 | | - (NSUInteger)state; |
51 | | - (BOOL)shutdownWithError:(NSError **)error; |
52 | | - (NSUUID *)UDID; |
53 | | - (BOOL)spawnWithPath:(NSString *)path |
54 | | options:(nullable NSDictionary<NSString *, id> *)options |
55 | | terminationQueue:(nullable dispatch_queue_t)terminationQueue |
56 | | terminationHandler:(nullable void (^)(int status))terminationHandler |
57 | | pid:(pid_t *_Nullable)pid |
58 | | error:(NSError *__autoreleasing _Nullable *_Nullable)error; |
59 | | @end |
60 | | |
61 | 0 | CoreSimulatorSupport::Process::Process(lldb::pid_t p) : m_pid(p), m_error() {} |
62 | | |
63 | | CoreSimulatorSupport::Process::Process(Status error) |
64 | 0 | : m_pid(LLDB_INVALID_PROCESS_ID), m_error(error) {} |
65 | | |
66 | | CoreSimulatorSupport::Process::Process(lldb::pid_t p, Status error) |
67 | 0 | : m_pid(p), m_error(error) {} |
68 | | |
69 | 0 | CoreSimulatorSupport::DeviceType::DeviceType() : m_model_identifier() {} |
70 | | |
71 | | CoreSimulatorSupport::DeviceType::DeviceType(id d) |
72 | 0 | : m_dev(d), m_model_identifier() {} |
73 | | |
74 | 0 | CoreSimulatorSupport::DeviceType::operator bool() { return m_dev != nil; } |
75 | | |
76 | 0 | ConstString CoreSimulatorSupport::DeviceType::GetIdentifier() { |
77 | 0 | return ConstString([[m_dev identifier] UTF8String]); |
78 | 0 | } |
79 | | |
80 | 0 | ConstString CoreSimulatorSupport::DeviceType::GetProductFamily() { |
81 | 0 | return ConstString([[m_dev productFamily] UTF8String]); |
82 | 0 | } |
83 | | |
84 | | CoreSimulatorSupport::DeviceType::ProductFamilyID |
85 | 0 | CoreSimulatorSupport::DeviceType::GetProductFamilyID() { |
86 | 0 | return ProductFamilyID([m_dev productFamilyID]); |
87 | 0 | } |
88 | | |
89 | 0 | CoreSimulatorSupport::DeviceRuntime::DeviceRuntime() : m_os_version() {} |
90 | | |
91 | | CoreSimulatorSupport::DeviceRuntime::DeviceRuntime(id d) |
92 | 0 | : m_dev(d), m_os_version() {} |
93 | | |
94 | 0 | CoreSimulatorSupport::DeviceRuntime::operator bool() { return m_dev != nil; } |
95 | | |
96 | 0 | bool CoreSimulatorSupport::DeviceRuntime::IsAvailable() { |
97 | 0 | return [m_dev available]; |
98 | 0 | } |
99 | | |
100 | 0 | CoreSimulatorSupport::Device::Device() : m_dev_type(), m_dev_runtime() {} |
101 | | |
102 | | CoreSimulatorSupport::Device::Device(id d) |
103 | 0 | : m_dev(d), m_dev_type(), m_dev_runtime() {} |
104 | | |
105 | 0 | CoreSimulatorSupport::Device::operator bool() { return m_dev != nil; } |
106 | | |
107 | 0 | CoreSimulatorSupport::Device::State CoreSimulatorSupport::Device::GetState() { |
108 | 0 | return (State)([m_dev state]); |
109 | 0 | } |
110 | | |
111 | | CoreSimulatorSupport::ModelIdentifier::ModelIdentifier(const std::string &mi) |
112 | 0 | : m_family(), m_versions() { |
113 | 0 | bool first_digit = false; |
114 | 0 | unsigned int val = 0; |
115 | |
|
116 | 0 | for (char c : mi) { |
117 | 0 | if (::isdigit(c)) { |
118 | 0 | if (!first_digit) |
119 | 0 | first_digit = true; |
120 | 0 | val = 10 * val + (c - '0'); |
121 | 0 | } else if (c == ',') { |
122 | 0 | if (first_digit) { |
123 | 0 | m_versions.push_back(val); |
124 | 0 | val = 0; |
125 | 0 | } else |
126 | 0 | m_family.push_back(c); |
127 | 0 | } else { |
128 | 0 | if (first_digit) { |
129 | 0 | m_family.clear(); |
130 | 0 | m_versions.clear(); |
131 | 0 | return; |
132 | 0 | } else { |
133 | 0 | m_family.push_back(c); |
134 | 0 | } |
135 | 0 | } |
136 | 0 | } |
137 | | |
138 | 0 | if (first_digit) |
139 | 0 | m_versions.push_back(val); |
140 | 0 | } |
141 | | |
142 | | CoreSimulatorSupport::ModelIdentifier::ModelIdentifier() |
143 | 0 | : ModelIdentifier("") {} Unexecuted instantiation: CoreSimulatorSupport::ModelIdentifier::ModelIdentifier() Unexecuted instantiation: CoreSimulatorSupport::ModelIdentifier::ModelIdentifier() |
144 | | |
145 | | CoreSimulatorSupport::OSVersion::OSVersion(const std::string &ver, |
146 | | const std::string &build) |
147 | 0 | : m_versions(), m_build(build) { |
148 | 0 | bool any = false; |
149 | 0 | unsigned int val = 0; |
150 | 0 | for (char c : ver) { |
151 | 0 | if (c == '.') { |
152 | 0 | m_versions.push_back(val); |
153 | 0 | val = 0; |
154 | 0 | } else if (::isdigit(c)) { |
155 | 0 | val = 10 * val + (c - '0'); |
156 | 0 | any = true; |
157 | 0 | } else { |
158 | 0 | m_versions.clear(); |
159 | 0 | return; |
160 | 0 | } |
161 | 0 | } |
162 | 0 | if (any) |
163 | 0 | m_versions.push_back(val); |
164 | 0 | } |
165 | | |
166 | 0 | CoreSimulatorSupport::OSVersion::OSVersion() : OSVersion("", "") {} Unexecuted instantiation: CoreSimulatorSupport::OSVersion::OSVersion() Unexecuted instantiation: CoreSimulatorSupport::OSVersion::OSVersion() |
167 | | |
168 | | CoreSimulatorSupport::ModelIdentifier |
169 | 0 | CoreSimulatorSupport::DeviceType::GetModelIdentifier() { |
170 | 0 | if (!m_model_identifier.has_value()) { |
171 | 0 | auto utf8_model_id = [[m_dev modelIdentifier] UTF8String]; |
172 | 0 | if (utf8_model_id && *utf8_model_id) |
173 | 0 | m_model_identifier = ModelIdentifier(utf8_model_id); |
174 | 0 | } |
175 | |
|
176 | 0 | if (m_model_identifier.has_value()) |
177 | 0 | return m_model_identifier.value(); |
178 | 0 | else |
179 | 0 | return ModelIdentifier(); |
180 | 0 | } |
181 | | |
182 | | CoreSimulatorSupport::OSVersion |
183 | 0 | CoreSimulatorSupport::DeviceRuntime::GetVersion() { |
184 | 0 | if (!m_os_version.has_value()) { |
185 | 0 | auto utf8_ver_string = [[m_dev versionString] UTF8String]; |
186 | 0 | auto utf8_build_ver = [[m_dev buildVersionString] UTF8String]; |
187 | 0 | if (utf8_ver_string && *utf8_ver_string && utf8_build_ver && |
188 | 0 | *utf8_build_ver) { |
189 | 0 | m_os_version = OSVersion(utf8_ver_string, utf8_build_ver); |
190 | 0 | } |
191 | 0 | } |
192 | |
|
193 | 0 | if (m_os_version.has_value()) |
194 | 0 | return m_os_version.value(); |
195 | 0 | return OSVersion(); |
196 | 0 | } |
197 | | |
198 | 0 | std::string CoreSimulatorSupport::DeviceType::GetName() { |
199 | 0 | auto utf8_name = [[m_dev name] UTF8String]; |
200 | 0 | if (utf8_name) |
201 | 0 | return std::string(utf8_name); |
202 | 0 | return ""; |
203 | 0 | } |
204 | | |
205 | 0 | std::string CoreSimulatorSupport::Device::GetName() const { |
206 | 0 | auto utf8_name = [[m_dev name] UTF8String]; |
207 | 0 | if (utf8_name) |
208 | 0 | return std::string(utf8_name); |
209 | 0 | return ""; |
210 | 0 | } |
211 | | |
212 | 0 | std::string CoreSimulatorSupport::Device::GetUDID() const { |
213 | 0 | auto utf8_udid = [[[m_dev UDID] UUIDString] UTF8String]; |
214 | 0 | if (utf8_udid) |
215 | 0 | return std::string(utf8_udid); |
216 | 0 | else |
217 | 0 | return std::string(); |
218 | 0 | } |
219 | | |
220 | 0 | CoreSimulatorSupport::DeviceType CoreSimulatorSupport::Device::GetDeviceType() { |
221 | 0 | if (!m_dev_type.has_value()) |
222 | 0 | m_dev_type = DeviceType([m_dev deviceType]); |
223 | |
|
224 | 0 | return m_dev_type.value(); |
225 | 0 | } |
226 | | |
227 | | CoreSimulatorSupport::DeviceRuntime |
228 | 0 | CoreSimulatorSupport::Device::GetDeviceRuntime() { |
229 | 0 | if (!m_dev_runtime.has_value()) |
230 | 0 | m_dev_runtime = DeviceRuntime([m_dev runtime]); |
231 | |
|
232 | 0 | return m_dev_runtime.value(); |
233 | 0 | } |
234 | | |
235 | | bool CoreSimulatorSupport:: |
236 | | operator>(const CoreSimulatorSupport::OSVersion &lhs, |
237 | 0 | const CoreSimulatorSupport::OSVersion &rhs) { |
238 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
239 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
240 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
241 | 0 | if (l > r) |
242 | 0 | return true; |
243 | 0 | } |
244 | 0 | return false; |
245 | 0 | } |
246 | | |
247 | | bool CoreSimulatorSupport:: |
248 | | operator>(const CoreSimulatorSupport::ModelIdentifier &lhs, |
249 | 0 | const CoreSimulatorSupport::ModelIdentifier &rhs) { |
250 | 0 | if (lhs.GetFamily() != rhs.GetFamily()) |
251 | 0 | return false; |
252 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
253 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
254 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
255 | 0 | if (l > r) |
256 | 0 | return true; |
257 | 0 | } |
258 | 0 | return false; |
259 | 0 | } |
260 | | |
261 | | bool CoreSimulatorSupport:: |
262 | | operator<(const CoreSimulatorSupport::OSVersion &lhs, |
263 | 0 | const CoreSimulatorSupport::OSVersion &rhs) { |
264 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
265 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
266 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
267 | 0 | if (l < r) |
268 | 0 | return true; |
269 | 0 | } |
270 | 0 | return false; |
271 | 0 | } |
272 | | |
273 | | bool CoreSimulatorSupport:: |
274 | | operator<(const CoreSimulatorSupport::ModelIdentifier &lhs, |
275 | 0 | const CoreSimulatorSupport::ModelIdentifier &rhs) { |
276 | 0 | if (lhs.GetFamily() != rhs.GetFamily()) |
277 | 0 | return false; |
278 | | |
279 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
280 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
281 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
282 | 0 | if (l < r) |
283 | 0 | return true; |
284 | 0 | } |
285 | 0 | return false; |
286 | 0 | } |
287 | | |
288 | | bool CoreSimulatorSupport:: |
289 | | operator==(const CoreSimulatorSupport::OSVersion &lhs, |
290 | 0 | const CoreSimulatorSupport::OSVersion &rhs) { |
291 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
292 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
293 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
294 | 0 | if (l != r) |
295 | 0 | return false; |
296 | 0 | } |
297 | 0 | return true; |
298 | 0 | } |
299 | | |
300 | | bool CoreSimulatorSupport:: |
301 | | operator==(const CoreSimulatorSupport::ModelIdentifier &lhs, |
302 | 0 | const CoreSimulatorSupport::ModelIdentifier &rhs) { |
303 | 0 | if (lhs.GetFamily() != rhs.GetFamily()) |
304 | 0 | return false; |
305 | | |
306 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
307 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
308 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
309 | 0 | if (l != r) |
310 | 0 | return false; |
311 | 0 | } |
312 | 0 | return true; |
313 | 0 | } |
314 | | |
315 | | bool CoreSimulatorSupport:: |
316 | | operator!=(const CoreSimulatorSupport::OSVersion &lhs, |
317 | 0 | const CoreSimulatorSupport::OSVersion &rhs) { |
318 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
319 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
320 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
321 | 0 | if (l != r) |
322 | 0 | return true; |
323 | 0 | } |
324 | 0 | return false; |
325 | 0 | } |
326 | | |
327 | | bool CoreSimulatorSupport:: |
328 | | operator!=(const CoreSimulatorSupport::ModelIdentifier &lhs, |
329 | 0 | const CoreSimulatorSupport::ModelIdentifier &rhs) { |
330 | 0 | if (lhs.GetFamily() != rhs.GetFamily()) |
331 | 0 | return false; |
332 | | |
333 | 0 | for (size_t i = 0; i < rhs.GetNumVersions(); i++) { |
334 | 0 | unsigned int l = lhs.GetVersionAtIndex(i); |
335 | 0 | unsigned int r = rhs.GetVersionAtIndex(i); |
336 | 0 | if (l != r) |
337 | 0 | return true; |
338 | 0 | } |
339 | 0 | return false; |
340 | 0 | } |
341 | | |
342 | 0 | bool CoreSimulatorSupport::Device::Boot(Status &err) { |
343 | 0 | if (m_dev == nil) { |
344 | 0 | err.SetErrorString("no valid simulator instance"); |
345 | 0 | return false; |
346 | 0 | } |
347 | | |
348 | 0 | #define kSimDeviceBootPersist \ |
349 | 0 | @"persist" /* An NSNumber (boolean) indicating whether or not the session \ |
350 | | should outlive the calling process (default false) */ |
351 | | |
352 | 0 | NSDictionary *options = @{ |
353 | 0 | kSimDeviceBootPersist : @NO, |
354 | 0 | }; |
355 | |
|
356 | 0 | #undef kSimDeviceBootPersist |
357 | |
|
358 | 0 | NSError *nserror; |
359 | 0 | if ([m_dev bootWithOptions:options error:&nserror]) { |
360 | 0 | err.Clear(); |
361 | 0 | return true; |
362 | 0 | } else { |
363 | 0 | err.SetErrorString([[nserror description] UTF8String]); |
364 | 0 | return false; |
365 | 0 | } |
366 | 0 | } |
367 | | |
368 | 0 | bool CoreSimulatorSupport::Device::Shutdown(Status &err) { |
369 | 0 | NSError *nserror; |
370 | 0 | if ([m_dev shutdownWithError:&nserror]) { |
371 | 0 | err.Clear(); |
372 | 0 | return true; |
373 | 0 | } else { |
374 | 0 | err.SetErrorString([[nserror description] UTF8String]); |
375 | 0 | return false; |
376 | 0 | } |
377 | 0 | } |
378 | | |
379 | | static Status HandleFileAction(ProcessLaunchInfo &launch_info, |
380 | | NSMutableDictionary *options, NSString *key, |
381 | 0 | const int fd, lldb::FileSP &file) { |
382 | 0 | Status error; |
383 | 0 | const FileAction *file_action = launch_info.GetFileActionForFD(fd); |
384 | 0 | if (file_action) { |
385 | 0 | switch (file_action->GetAction()) { |
386 | 0 | case FileAction::eFileActionNone: |
387 | 0 | break; |
388 | | |
389 | 0 | case FileAction::eFileActionClose: |
390 | 0 | error.SetErrorStringWithFormat("close file action for %i not supported", |
391 | 0 | fd); |
392 | 0 | break; |
393 | | |
394 | 0 | case FileAction::eFileActionDuplicate: |
395 | 0 | error.SetErrorStringWithFormat( |
396 | 0 | "duplication file action for %i not supported", fd); |
397 | 0 | break; |
398 | | |
399 | 0 | case FileAction::eFileActionOpen: { |
400 | 0 | FileSpec file_spec = file_action->GetFileSpec(); |
401 | 0 | if (file_spec) { |
402 | 0 | const int primary_fd = launch_info.GetPTY().GetPrimaryFileDescriptor(); |
403 | 0 | if (primary_fd != PseudoTerminal::invalid_fd) { |
404 | | // Check in case our file action open wants to open the secondary |
405 | 0 | FileSpec secondary_spec(launch_info.GetPTY().GetSecondaryName()); |
406 | 0 | if (file_spec == secondary_spec) { |
407 | 0 | int secondary_fd = |
408 | 0 | launch_info.GetPTY().GetSecondaryFileDescriptor(); |
409 | 0 | if (secondary_fd == PseudoTerminal::invalid_fd) { |
410 | 0 | if (llvm::Error Err = launch_info.GetPTY().OpenSecondary(O_RDWR)) |
411 | 0 | return Status(std::move(Err)); |
412 | 0 | } |
413 | 0 | secondary_fd = launch_info.GetPTY().GetSecondaryFileDescriptor(); |
414 | 0 | assert(secondary_fd != PseudoTerminal::invalid_fd); |
415 | 0 | [options setValue:[NSNumber numberWithInteger:secondary_fd] |
416 | 0 | forKey:key]; |
417 | 0 | return error; // Success |
418 | 0 | } |
419 | 0 | } |
420 | 0 | Status posix_error; |
421 | 0 | int oflag = file_action->GetActionArgument(); |
422 | 0 | int created_fd = |
423 | 0 | open(file_spec.GetPath().c_str(), oflag, S_IRUSR | S_IWUSR); |
424 | 0 | if (created_fd >= 0) { |
425 | 0 | auto file_options = File::OpenOptions(0); |
426 | 0 | if (oflag & O_RDWR) |
427 | 0 | file_options |= File::eOpenOptionReadWrite; |
428 | 0 | else if (oflag & O_WRONLY) |
429 | 0 | file_options |= File::eOpenOptionWriteOnly; |
430 | 0 | else if (oflag & O_RDONLY) |
431 | 0 | file_options |= File::eOpenOptionReadOnly; |
432 | 0 | file = std::make_shared<NativeFile>(created_fd, file_options, true); |
433 | 0 | [options setValue:[NSNumber numberWithInteger:created_fd] forKey:key]; |
434 | 0 | return error; // Success |
435 | 0 | } else { |
436 | 0 | posix_error.SetErrorToErrno(); |
437 | 0 | error.SetErrorStringWithFormat("unable to open file '%s': %s", |
438 | 0 | file_spec.GetPath().c_str(), |
439 | 0 | posix_error.AsCString()); |
440 | 0 | } |
441 | 0 | } |
442 | 0 | } break; |
443 | 0 | } |
444 | 0 | } |
445 | 0 | return error; // Success, no file action, nothing to do |
446 | 0 | } |
447 | | |
448 | | CoreSimulatorSupport::Process |
449 | 0 | CoreSimulatorSupport::Device::Spawn(ProcessLaunchInfo &launch_info) { |
450 | 0 | #define kSimDeviceSpawnEnvironment \ |
451 | 0 | @"environment" /* An NSDictionary (NSStrings -> NSStrings) of environment \ |
452 | | key/values */ |
453 | 0 | #define kSimDeviceSpawnStdin @"stdin" /* An NSNumber corresponding to a fd */ |
454 | 0 | #define kSimDeviceSpawnStdout @"stdout" /* An NSNumber corresponding to a fd \ |
455 | | */ |
456 | 0 | #define kSimDeviceSpawnStderr @"stderr" /* An NSNumber corresponding to a fd \ |
457 | | */ |
458 | 0 | #define kSimDeviceSpawnArguments \ |
459 | 0 | @"arguments" /* An NSArray of strings to use as the argv array. If not \ |
460 | | provided, path will be argv[0] */ |
461 | 0 | #define kSimDeviceSpawnWaitForDebugger \ |
462 | 0 | @"wait_for_debugger" /* An NSNumber (bool) */ |
463 | 0 | #define kSimDeviceSpawnStandalone @"standalone" |
464 | |
|
465 | 0 | NSMutableDictionary *options = [[NSMutableDictionary alloc] init]; |
466 | |
|
467 | 0 | options[kSimDeviceSpawnStandalone] = @(YES); |
468 | |
|
469 | 0 | if (launch_info.GetFlags().Test(lldb::eLaunchFlagDebug)) |
470 | 0 | [options setObject:@YES forKey:kSimDeviceSpawnWaitForDebugger]; |
471 | |
|
472 | 0 | if (launch_info.GetArguments().GetArgumentCount()) { |
473 | 0 | const Args &args(launch_info.GetArguments()); |
474 | 0 | NSMutableArray *args_array = [[NSMutableArray alloc] init]; |
475 | 0 | for (size_t idx = 0; idx < args.GetArgumentCount(); idx++) |
476 | 0 | [args_array |
477 | 0 | addObject:[NSString |
478 | 0 | stringWithUTF8String:args.GetArgumentAtIndex(idx)]]; |
479 | |
|
480 | 0 | [options setObject:args_array forKey:kSimDeviceSpawnArguments]; |
481 | 0 | } |
482 | |
|
483 | 0 | NSMutableDictionary *env_dict = [[NSMutableDictionary alloc] init]; |
484 | |
|
485 | 0 | for (const auto &KV : launch_info.GetEnvironment()) { |
486 | 0 | NSString *key_ns = [NSString stringWithUTF8String:KV.first().str().c_str()]; |
487 | 0 | NSString *value_ns = [NSString stringWithUTF8String:KV.second.c_str()]; |
488 | |
|
489 | 0 | [env_dict setValue:value_ns forKey:key_ns]; |
490 | 0 | } |
491 | |
|
492 | 0 | [options setObject:env_dict forKey:kSimDeviceSpawnEnvironment]; |
493 | |
|
494 | 0 | Status error; |
495 | 0 | lldb::FileSP stdin_file; |
496 | 0 | lldb::FileSP stdout_file; |
497 | 0 | lldb::FileSP stderr_file; |
498 | 0 | error = HandleFileAction(launch_info, options, kSimDeviceSpawnStdin, |
499 | 0 | STDIN_FILENO, stdin_file); |
500 | |
|
501 | 0 | if (error.Fail()) |
502 | 0 | return CoreSimulatorSupport::Process(error); |
503 | | |
504 | 0 | error = HandleFileAction(launch_info, options, kSimDeviceSpawnStdout, |
505 | 0 | STDOUT_FILENO, stdout_file); |
506 | |
|
507 | 0 | if (error.Fail()) |
508 | 0 | return CoreSimulatorSupport::Process(error); |
509 | | |
510 | 0 | error = HandleFileAction(launch_info, options, kSimDeviceSpawnStderr, |
511 | 0 | STDERR_FILENO, stderr_file); |
512 | |
|
513 | 0 | if (error.Fail()) |
514 | 0 | return CoreSimulatorSupport::Process(error); |
515 | | |
516 | 0 | #undef kSimDeviceSpawnEnvironment |
517 | 0 | #undef kSimDeviceSpawnStdin |
518 | 0 | #undef kSimDeviceSpawnStdout |
519 | 0 | #undef kSimDeviceSpawnStderr |
520 | 0 | #undef kSimDeviceSpawnWaitForDebugger |
521 | 0 | #undef kSimDeviceSpawnArguments |
522 | | |
523 | 0 | NSError *nserror; |
524 | |
|
525 | 0 | pid_t pid; |
526 | 0 | BOOL success = [m_dev |
527 | 0 | spawnWithPath:[NSString stringWithUTF8String:launch_info |
528 | 0 | .GetExecutableFile() |
529 | 0 | .GetPath() |
530 | 0 | .c_str()] |
531 | 0 | options:options |
532 | 0 | terminationQueue:nil |
533 | 0 | terminationHandler:nil |
534 | 0 | pid:&pid |
535 | 0 | error:&nserror]; |
536 | |
|
537 | 0 | if (!success) { |
538 | 0 | const char *nserror_string = [[nserror description] UTF8String]; |
539 | 0 | error.SetErrorString(nserror_string ? nserror_string : "unable to launch"); |
540 | 0 | } |
541 | |
|
542 | 0 | return CoreSimulatorSupport::Process(pid, error); |
543 | 0 | } |
544 | | |
545 | | CoreSimulatorSupport::DeviceSet |
546 | 0 | CoreSimulatorSupport::DeviceSet::GetAllDevices(const char *developer_dir) { |
547 | 0 | if (!developer_dir || !developer_dir[0]) |
548 | 0 | return DeviceSet([NSArray new]); |
549 | | |
550 | 0 | Class SimServiceContextClass = NSClassFromString(@"SimServiceContext"); |
551 | 0 | NSString *dev_dir = @(developer_dir); |
552 | 0 | NSError *error = nil; |
553 | |
|
554 | 0 | id serviceContext = |
555 | 0 | [SimServiceContextClass sharedServiceContextForDeveloperDir:dev_dir |
556 | 0 | error:&error]; |
557 | 0 | if (!serviceContext) |
558 | 0 | return DeviceSet([NSArray new]); |
559 | | |
560 | 0 | return DeviceSet([[serviceContext defaultDeviceSetWithError:&error] devices]); |
561 | 0 | } |
562 | | |
563 | | CoreSimulatorSupport::DeviceSet |
564 | | CoreSimulatorSupport::DeviceSet::GetAvailableDevices( |
565 | 0 | const char *developer_dir) { |
566 | 0 | return GetAllDevices(developer_dir).GetDevicesIf([](Device d) -> bool { |
567 | 0 | return (d && d.GetDeviceType() && d.GetDeviceRuntime() && |
568 | 0 | d.GetDeviceRuntime().IsAvailable()); |
569 | 0 | }); |
570 | 0 | } |
571 | | |
572 | 0 | size_t CoreSimulatorSupport::DeviceSet::GetNumDevices() { |
573 | 0 | return [m_dev count]; |
574 | 0 | } |
575 | | |
576 | | CoreSimulatorSupport::Device |
577 | 0 | CoreSimulatorSupport::DeviceSet::GetDeviceAtIndex(size_t idx) { |
578 | 0 | if (idx < GetNumDevices()) |
579 | 0 | return Device([m_dev objectAtIndex:idx]); |
580 | 0 | return Device(); |
581 | 0 | } |
582 | | |
583 | | CoreSimulatorSupport::DeviceSet CoreSimulatorSupport::DeviceSet::GetDevicesIf( |
584 | 0 | std::function<bool(CoreSimulatorSupport::Device)> f) { |
585 | 0 | NSMutableArray *array = [[NSMutableArray alloc] init]; |
586 | 0 | for (NSUInteger i = 0; i < GetNumDevices(); i++) { |
587 | 0 | Device d(GetDeviceAtIndex(i)); |
588 | 0 | if (f(d)) |
589 | 0 | [array addObject:(id)d.m_dev]; |
590 | 0 | } |
591 | |
|
592 | 0 | return DeviceSet(array); |
593 | 0 | } |
594 | | |
595 | | void CoreSimulatorSupport::DeviceSet::ForEach( |
596 | 0 | std::function<bool(const Device &)> f) { |
597 | 0 | const size_t n = GetNumDevices(); |
598 | 0 | for (NSUInteger i = 0; i < n; ++i) { |
599 | 0 | if (!f(GetDeviceAtIndex(i))) |
600 | 0 | break; |
601 | 0 | } |
602 | 0 | } |
603 | | |
604 | | CoreSimulatorSupport::DeviceSet CoreSimulatorSupport::DeviceSet::GetDevices( |
605 | 0 | CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id) { |
606 | 0 | NSMutableArray *array = [[NSMutableArray alloc] init]; |
607 | 0 | const size_t n = GetNumDevices(); |
608 | 0 | for (NSUInteger i = 0; i < n; ++i) { |
609 | 0 | Device d(GetDeviceAtIndex(i)); |
610 | 0 | if (d && d.GetDeviceType() && |
611 | 0 | d.GetDeviceType().GetProductFamilyID() == dev_id) |
612 | 0 | [array addObject:(id)d.m_dev]; |
613 | 0 | } |
614 | |
|
615 | 0 | return DeviceSet(array); |
616 | 0 | } |
617 | | |
618 | | CoreSimulatorSupport::Device CoreSimulatorSupport::DeviceSet::GetFanciest( |
619 | 0 | CoreSimulatorSupport::DeviceType::ProductFamilyID dev_id) { |
620 | 0 | Device dev; |
621 | |
|
622 | 0 | for (NSUInteger i = 0; i < GetNumDevices(); i++) { |
623 | 0 | Device d(GetDeviceAtIndex(i)); |
624 | 0 | if (d && d.GetDeviceType() && |
625 | 0 | d.GetDeviceType().GetProductFamilyID() == dev_id) { |
626 | 0 | if (!dev) |
627 | 0 | dev = d; |
628 | 0 | else { |
629 | 0 | if ((d.GetDeviceType().GetModelIdentifier() > |
630 | 0 | dev.GetDeviceType().GetModelIdentifier()) || |
631 | 0 | d.GetDeviceRuntime().GetVersion() > |
632 | 0 | dev.GetDeviceRuntime().GetVersion()) |
633 | 0 | dev = d; |
634 | 0 | } |
635 | 0 | } |
636 | 0 | } |
637 | |
|
638 | 0 | return dev; |
639 | 0 | } |