blob: 408f0abe72d4cdac1000ffe8e95cc2e5b4a16ec3 [file] [log] [blame]
Todd Fialae77fce02016-09-04 00:18:56 +00001//
2// DarwinProcessLauncher.cpp
3// lldb
4//
5// Created by Todd Fiala on 8/30/16.
6//
7//
8
9#include "DarwinProcessLauncher.h"
10
11// C includes
12#include <spawn.h>
13#include <sys/ptrace.h>
14#include <sys/stat.h>
15#include <sys/sysctl.h>
16
17#ifndef _POSIX_SPAWN_DISABLE_ASLR
Kate Stoneb9c1b512016-09-06 20:57:50 +000018#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
Todd Fialae77fce02016-09-04 00:18:56 +000019#endif
20
21// LLDB includes
22#include "lldb/lldb-enumerations.h"
23
24#include "lldb/Core/Error.h"
25#include "lldb/Core/Log.h"
26#include "lldb/Core/StreamString.h"
27#include "lldb/Target/ProcessLaunchInfo.h"
28#include "lldb/Utility/PseudoTerminal.h"
29
30#include "CFBundle.h"
31#include "CFString.h"
32
33using namespace lldb;
34using namespace lldb_private;
35using namespace lldb_private::process_darwin;
36using namespace lldb_private::darwin_process_launcher;
37
Kate Stoneb9c1b512016-09-06 20:57:50 +000038namespace {
39static LaunchFlavor g_launch_flavor = LaunchFlavor::Default;
Todd Fialae77fce02016-09-04 00:18:56 +000040}
41
Kate Stoneb9c1b512016-09-06 20:57:50 +000042namespace lldb_private {
43namespace darwin_process_launcher {
Todd Fialae77fce02016-09-04 00:18:56 +000044
Kate Stoneb9c1b512016-09-06 20:57:50 +000045static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) {
46 int mib[CTL_MAXNAME] = {
47 0,
48 };
49 size_t len = CTL_MAXNAME;
50 if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
51 return 0;
Todd Fialae77fce02016-09-04 00:18:56 +000052
Kate Stoneb9c1b512016-09-06 20:57:50 +000053 mib[len] = pid;
54 len++;
Todd Fialae77fce02016-09-04 00:18:56 +000055
Kate Stoneb9c1b512016-09-06 20:57:50 +000056 cpu_type_t cpu;
57 size_t cpu_len = sizeof(cpu);
58 if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
59 cpu = 0;
60 return cpu;
Todd Fialae77fce02016-09-04 00:18:56 +000061}
62
Kate Stoneb9c1b512016-09-06 20:57:50 +000063static bool ResolveExecutablePath(const char *path, char *resolved_path,
64 size_t resolved_path_size) {
65 if (path == NULL || path[0] == '\0')
Todd Fialae77fce02016-09-04 00:18:56 +000066 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000067
68 char max_path[PATH_MAX];
69 std::string result;
70 CFString::GlobPath(path, result);
71
72 if (result.empty())
73 result = path;
74
75 struct stat path_stat;
76 if (::stat(path, &path_stat) == 0) {
77 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
78 CFBundle bundle(path);
79 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
80 if (url.get()) {
81 if (::CFURLGetFileSystemRepresentation(
82 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
83 return true;
84 }
85 }
86 }
87
88 if (realpath(path, max_path)) {
89 // Found the path relatively...
90 ::strncpy(resolved_path, max_path, resolved_path_size);
91 return strlen(resolved_path) + 1 < resolved_path_size;
92 } else {
93 // Not a relative path, check the PATH environment variable if the
94 const char *PATH = getenv("PATH");
95 if (PATH) {
96 const char *curr_path_start = PATH;
97 const char *curr_path_end;
98 while (curr_path_start && *curr_path_start) {
99 curr_path_end = strchr(curr_path_start, ':');
100 if (curr_path_end == NULL) {
101 result.assign(curr_path_start);
102 curr_path_start = NULL;
103 } else if (curr_path_end > curr_path_start) {
104 size_t len = curr_path_end - curr_path_start;
105 result.assign(curr_path_start, len);
106 curr_path_start += len + 1;
107 } else
108 break;
109
110 result += '/';
111 result += path;
112 struct stat s;
113 if (stat(result.c_str(), &s) == 0) {
114 ::strncpy(resolved_path, result.c_str(), resolved_path_size);
115 return result.size() + 1 < resolved_path_size;
116 }
117 }
118 }
119 }
120 return false;
Todd Fialae77fce02016-09-04 00:18:56 +0000121}
122
123// TODO check if we have a general purpose fork and exec. We may be
124// able to get rid of this entirely.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000125static Error ForkChildForPTraceDebugging(const char *path, char const *argv[],
126 char const *envp[], ::pid_t *pid,
127 int *pty_fd) {
128 Error error;
129 if (!path || !argv || !envp || !pid || !pty_fd) {
130 error.SetErrorString("invalid arguments");
Todd Fialae77fce02016-09-04 00:18:56 +0000131 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000132 }
133
134 // Use a fork that ties the child process's stdin/out/err to a pseudo
135 // terminal so we can read it in our MachProcess::STDIOThread
136 // as unbuffered io.
137 lldb_utility::PseudoTerminal pty;
138 char fork_error[256];
139 memset(fork_error, 0, sizeof(fork_error));
140 *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error)));
141 if (*pid < 0) {
142 //--------------------------------------------------------------
143 // Error during fork.
144 //--------------------------------------------------------------
145 *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
146 error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__,
147 fork_error);
148 return error;
149 } else if (pid == 0) {
150 //--------------------------------------------------------------
151 // Child process
152 //--------------------------------------------------------------
153
154 // Debug this process.
155 ::ptrace(PT_TRACE_ME, 0, 0, 0);
156
157 // Get BSD signals as mach exceptions.
158 ::ptrace(PT_SIGEXC, 0, 0, 0);
159
160 // If our parent is setgid, lets make sure we don't inherit those
161 // extra powers due to nepotism.
162 if (::setgid(getgid()) == 0) {
163 // Let the child have its own process group. We need to execute
164 // this call in both the child and parent to avoid a race
165 // condition between the two processes.
166
167 // Set the child process group to match its pid.
168 ::setpgid(0, 0);
169
170 // Sleep a bit to before the exec call.
171 ::sleep(1);
172
173 // Turn this process into the given executable.
174 ::execv(path, (char *const *)argv);
175 }
176 // Exit with error code. Child process should have taken
177 // over in above exec call and if the exec fails it will
178 // exit the child process below.
179 ::exit(127);
180 } else {
181 //--------------------------------------------------------------
182 // Parent process
183 //--------------------------------------------------------------
184 // Let the child have its own process group. We need to execute
185 // this call in both the child and parent to avoid a race condition
186 // between the two processes.
187
188 // Set the child process group to match its pid
189 ::setpgid(*pid, *pid);
190 if (pty_fd) {
191 // Release our master pty file descriptor so the pty class doesn't
192 // close it and so we can continue to use it in our STDIO thread
193 *pty_fd = pty.ReleaseMasterFileDescriptor();
194 }
195 }
196 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000197}
198
199static Error
200CreatePosixSpawnFileAction(const FileAction &action,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 posix_spawn_file_actions_t *file_actions) {
202 Error error;
Todd Fialae77fce02016-09-04 00:18:56 +0000203
Kate Stoneb9c1b512016-09-06 20:57:50 +0000204 // Log it.
205 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
206 if (log) {
207 StreamString stream;
208 stream.PutCString("converting file action for posix_spawn(): ");
209 action.Dump(stream);
210 stream.Flush();
211 log->PutCString(stream.GetString().c_str());
212 }
Todd Fialae77fce02016-09-04 00:18:56 +0000213
Kate Stoneb9c1b512016-09-06 20:57:50 +0000214 // Validate args.
215 if (!file_actions) {
216 error.SetErrorString("mandatory file_actions arg is null");
Todd Fialae77fce02016-09-04 00:18:56 +0000217 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000218 }
219
220 // Build the posix file action.
221 switch (action.GetAction()) {
222 case FileAction::eFileActionOpen: {
223 const int error_code = ::posix_spawn_file_actions_addopen(
224 file_actions, action.GetFD(), action.GetPath(),
225 action.GetActionArgument(), 0);
226 if (error_code != 0) {
227 error.SetError(error_code, eErrorTypePOSIX);
228 return error;
229 }
230 break;
231 }
232
233 case FileAction::eFileActionClose: {
234 const int error_code =
235 ::posix_spawn_file_actions_addclose(file_actions, action.GetFD());
236 if (error_code != 0) {
237 error.SetError(error_code, eErrorTypePOSIX);
238 return error;
239 }
240 break;
241 }
242
243 case FileAction::eFileActionDuplicate: {
244 const int error_code = ::posix_spawn_file_actions_adddup2(
245 file_actions, action.GetFD(), action.GetActionArgument());
246 if (error_code != 0) {
247 error.SetError(error_code, eErrorTypePOSIX);
248 return error;
249 }
250 break;
251 }
252
253 case FileAction::eFileActionNone:
254 default:
255 if (log)
256 log->Printf("%s(): unsupported file action %u", __FUNCTION__,
257 action.GetAction());
258 break;
259 }
260
261 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000262}
263
Kate Stoneb9c1b512016-09-06 20:57:50 +0000264static Error PosixSpawnChildForPTraceDebugging(const char *path,
265 ProcessLaunchInfo &launch_info,
266 ::pid_t *pid,
267 cpu_type_t *actual_cpu_type) {
268 Error error;
269 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000270
Kate Stoneb9c1b512016-09-06 20:57:50 +0000271 if (!pid) {
272 error.SetErrorStringWithFormat("%s(): pid arg cannot be null",
273 __FUNCTION__);
274 return error;
275 }
Todd Fialae77fce02016-09-04 00:18:56 +0000276
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 posix_spawnattr_t attr;
278 short flags;
279 if (log) {
280 StreamString stream;
281 stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path);
282 launch_info.Dump(stream, nullptr);
283 stream.Flush();
284 log->PutCString(stream.GetString().c_str());
285 }
286
287 int error_code;
288 if ((error_code = ::posix_spawnattr_init(&attr)) != 0) {
Todd Fialae77fce02016-09-04 00:18:56 +0000289 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000290 log->Printf("::posix_spawnattr_init(&attr) failed");
291 error.SetError(error_code, eErrorTypePOSIX);
292 return error;
293 }
Todd Fialae77fce02016-09-04 00:18:56 +0000294
Kate Stoneb9c1b512016-09-06 20:57:50 +0000295 // Ensure we clean up the spawnattr structure however we exit this
296 // function.
297 std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up(
298 &attr, ::posix_spawnattr_destroy);
Todd Fialae77fce02016-09-04 00:18:56 +0000299
Kate Stoneb9c1b512016-09-06 20:57:50 +0000300 flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
301 POSIX_SPAWN_SETSIGMASK;
302 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
303 flags |= _POSIX_SPAWN_DISABLE_ASLR;
Todd Fialae77fce02016-09-04 00:18:56 +0000304
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 sigset_t no_signals;
306 sigset_t all_signals;
307 sigemptyset(&no_signals);
308 sigfillset(&all_signals);
309 ::posix_spawnattr_setsigmask(&attr, &no_signals);
310 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
Todd Fialae77fce02016-09-04 00:18:56 +0000311
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312 if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
313 if (log)
314 log->Printf("::posix_spawnattr_setflags(&attr, "
315 "POSIX_SPAWN_START_SUSPENDED%s) failed: %s",
316 flags & _POSIX_SPAWN_DISABLE_ASLR
317 ? " | _POSIX_SPAWN_DISABLE_ASLR"
318 : "",
319 strerror(error_code));
320 error.SetError(error_code, eErrorTypePOSIX);
321 return error;
322 }
Todd Fialae77fce02016-09-04 00:18:56 +0000323
324#if !defined(__arm__)
325
Kate Stoneb9c1b512016-09-06 20:57:50 +0000326 // We don't need to do this for ARM, and we really shouldn't now that we
327 // have multiple CPU subtypes and no posix_spawnattr call that allows us
328 // to set which CPU subtype to launch...
329 cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType();
330 if (desired_cpu_type != LLDB_INVALID_CPUTYPE) {
331 size_t ocount = 0;
332 error_code =
333 ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
334 if (error_code != 0) {
335 if (log)
336 log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, "
337 "cpu_type = 0x%8.8x, count => %llu): %s",
338 desired_cpu_type, (uint64_t)ocount, strerror(error_code));
339 error.SetError(error_code, eErrorTypePOSIX);
340 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000341 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000342 if (ocount != 1) {
343 error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np "
344 "did not set the expected number "
345 "of cpu_type entries: expected 1 "
346 "but was %zu",
347 ocount);
348 return error;
349 }
350 }
Todd Fialae77fce02016-09-04 00:18:56 +0000351#endif
352
Kate Stoneb9c1b512016-09-06 20:57:50 +0000353 posix_spawn_file_actions_t file_actions;
354 if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
355 if (log)
356 log->Printf("::posix_spawn_file_actions_init(&file_actions) "
357 "failed: %s",
358 strerror(error_code));
359 error.SetError(error_code, eErrorTypePOSIX);
Todd Fialae77fce02016-09-04 00:18:56 +0000360 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000361 }
362
363 // Ensure we clean up file actions however we exit this. When the
364 // file_actions_up below goes out of scope, we'll get our file action
365 // cleanup.
366 std::unique_ptr<posix_spawn_file_actions_t,
367 int (*)(posix_spawn_file_actions_t *)>
368 file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy);
369
370 // We assume the caller has setup the file actions appropriately. We
371 // are not in the business of figuring out what we really need here.
372 // lldb-server will have already called FinalizeFileActions() as well
373 // to button these up properly.
374 const size_t num_actions = launch_info.GetNumFileActions();
375 for (size_t action_index = 0; action_index < num_actions; ++action_index) {
376 const FileAction *const action =
377 launch_info.GetFileActionAtIndex(action_index);
378 if (!action)
379 continue;
380
381 error = CreatePosixSpawnFileAction(*action, &file_actions);
382 if (!error.Success()) {
383 if (log)
384 log->Printf("%s(): error converting FileAction to posix_spawn "
385 "file action: %s",
386 __FUNCTION__, error.AsCString());
387 return error;
388 }
389 }
390
391 // TODO: Verify if we can set the working directory back immediately
392 // after the posix_spawnp call without creating a race condition???
393 const char *const working_directory =
394 launch_info.GetWorkingDirectory().GetCString();
395 if (working_directory && working_directory[0])
396 ::chdir(working_directory);
397
398 auto argv = launch_info.GetArguments().GetArgumentVector();
399 auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
400 error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
401 (char *const *)argv, (char *const *)envp);
402 if (error_code != 0) {
403 if (log)
404 log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions "
405 "= %p, attr = %p, argv = %p, envp = %p) failed: %s",
406 pid, path, &file_actions, &attr, argv, envp,
407 strerror(error_code));
408 error.SetError(error_code, eErrorTypePOSIX);
409 return error;
410 }
411
412 // Validate we got a pid.
413 if (pid == LLDB_INVALID_PROCESS_ID) {
414 error.SetErrorString("posix_spawn() did not indicate a failure but it "
415 "failed to return a pid, aborting.");
416 return error;
417 }
418
419 if (actual_cpu_type) {
420 *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
421 if (log)
422 log->Printf("%s(): cpu type for launched process pid=%i: "
423 "cpu_type=0x%8.8x",
424 __FUNCTION__, *pid, *actual_cpu_type);
425 }
426
427 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000428}
429
Kate Stoneb9c1b512016-09-06 20:57:50 +0000430Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
431 LaunchFlavor *launch_flavor) {
432 Error error;
433 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000434
Kate Stoneb9c1b512016-09-06 20:57:50 +0000435 if (!launch_flavor) {
436 error.SetErrorString("mandatory launch_flavor field was null");
437 return error;
438 }
Todd Fialae77fce02016-09-04 00:18:56 +0000439
Kate Stoneb9c1b512016-09-06 20:57:50 +0000440 if (log) {
441 StreamString stream;
442 stream.Printf("NativeProcessDarwin::%s(): launching with the "
443 "following launch info:",
444 __FUNCTION__);
445 launch_info.Dump(stream, nullptr);
446 stream.Flush();
447 log->PutCString(stream.GetString().c_str());
448 }
Todd Fialae77fce02016-09-04 00:18:56 +0000449
Kate Stoneb9c1b512016-09-06 20:57:50 +0000450 // Retrieve the binary name given to us.
451 char given_path[PATH_MAX];
452 given_path[0] = '\0';
453 launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path));
Todd Fialae77fce02016-09-04 00:18:56 +0000454
Kate Stoneb9c1b512016-09-06 20:57:50 +0000455 // Determine the manner in which we'll launch.
456 *launch_flavor = g_launch_flavor;
457 if (*launch_flavor == LaunchFlavor::Default) {
458 // Our default launch method is posix spawn
459 *launch_flavor = LaunchFlavor::PosixSpawn;
Todd Fialae77fce02016-09-04 00:18:56 +0000460#if defined WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000461 // Check if we have an app bundle, if so launch using BackBoard Services.
462 if (strstr(given_path, ".app")) {
463 *launch_flavor = eLaunchFlavorFBS;
464 }
Todd Fialae77fce02016-09-04 00:18:56 +0000465#elif defined WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000466 // Check if we have an app bundle, if so launch using BackBoard Services.
467 if (strstr(given_path, ".app")) {
468 *launch_flavor = eLaunchFlavorBKS;
469 }
Todd Fialae77fce02016-09-04 00:18:56 +0000470#elif defined WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000471 // Check if we have an app bundle, if so launch using SpringBoard.
472 if (strstr(given_path, ".app")) {
473 *launch_flavor = eLaunchFlavorSpringBoard;
474 }
Todd Fialae77fce02016-09-04 00:18:56 +0000475#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000476 }
Todd Fialae77fce02016-09-04 00:18:56 +0000477
Kate Stoneb9c1b512016-09-06 20:57:50 +0000478 // Attempt to resolve the binary name to an absolute path.
479 char resolved_path[PATH_MAX];
480 resolved_path[0] = '\0';
Todd Fialae77fce02016-09-04 00:18:56 +0000481
Kate Stoneb9c1b512016-09-06 20:57:50 +0000482 if (log)
483 log->Printf("%s(): attempting to resolve given binary path: \"%s\"",
484 __FUNCTION__, given_path);
485
486 // If we fail to resolve the path to our executable, then just use what we
487 // were given and hope for the best
488 if (!ResolveExecutablePath(given_path, resolved_path,
489 sizeof(resolved_path))) {
Todd Fialae77fce02016-09-04 00:18:56 +0000490 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000491 log->Printf("%s(): failed to resolve binary path, using "
492 "what was given verbatim and hoping for the best",
493 __FUNCTION__);
494 ::strncpy(resolved_path, given_path, sizeof(resolved_path));
495 } else {
496 if (log)
497 log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__,
498 resolved_path);
499 }
Todd Fialae77fce02016-09-04 00:18:56 +0000500
Kate Stoneb9c1b512016-09-06 20:57:50 +0000501 char launch_err_str[PATH_MAX];
502 launch_err_str[0] = '\0';
503
504 // TODO figure out how to handle QSetProcessEvent
505 // const char *process_event = ctx.GetProcessEvent();
506
507 // Ensure the binary is there.
508 struct stat path_stat;
509 if (::stat(resolved_path, &path_stat) == -1) {
510 error.SetErrorToErrno();
511 return error;
512 }
513
514 // Fork a child process for debugging
515 // state_callback(eStateLaunching);
516
517 const auto argv = launch_info.GetArguments().GetConstArgumentVector();
518 const auto envp =
519 launch_info.GetEnvironmentEntries().GetConstArgumentVector();
520
521 switch (*launch_flavor) {
522 case LaunchFlavor::ForkExec: {
523 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
524 error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid,
525 pty_master_fd);
526 if (error.Success()) {
527 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
528 } else {
529 // Reset any variables that might have been set during a failed
530 // launch attempt.
531 if (pty_master_fd)
532 *pty_master_fd = -1;
533
534 // We're done.
535 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000536 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000537 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000538
539#ifdef WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000540 case LaunchFlavor::FBS: {
541 const char *app_ext = strstr(path, ".app");
542 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
543 std::string app_bundle_path(path, app_ext + strlen(".app"));
544 m_flags |= eMachProcessFlagsUsingFBS;
545 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
546 no_stdio, disable_aslr, event_data,
547 launch_err) != 0)
548 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
549 // non-zero m_pid.
550 else
551 break; // We tried a FBS launch, but didn't succeed lets get out
552 }
553 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000554#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000555
Todd Fialae77fce02016-09-04 00:18:56 +0000556#ifdef WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000557 case LaunchFlavor::BKS: {
558 const char *app_ext = strstr(path, ".app");
559 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
560 std::string app_bundle_path(path, app_ext + strlen(".app"));
561 m_flags |= eMachProcessFlagsUsingBKS;
562 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
563 no_stdio, disable_aslr, event_data,
564 launch_err) != 0)
565 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
566 // non-zero m_pid.
567 else
568 break; // We tried a BKS launch, but didn't succeed lets get out
569 }
570 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000571#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000572
Todd Fialae77fce02016-09-04 00:18:56 +0000573#ifdef WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000574 case LaunchFlavor::SpringBoard: {
575 // .../whatever.app/whatever ?
576 // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in
577 // "com.apple.whatever" here
578 const char *app_ext = strstr(path, ".app/");
579 if (app_ext == NULL) {
580 // .../whatever.app ?
581 int len = strlen(path);
582 if (len > 5) {
583 if (strcmp(path + len - 4, ".app") == 0) {
584 app_ext = path + len - 4;
Todd Fialae77fce02016-09-04 00:18:56 +0000585 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000586 }
587 }
588 if (app_ext) {
589 std::string app_bundle_path(path, app_ext + strlen(".app"));
590 if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
591 disable_aslr, launch_err) != 0)
592 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
593 // non-zero m_pid.
594 else
595 break; // We tried a springboard launch, but didn't succeed lets get out
596 }
597 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000598#endif
Todd Fialae77fce02016-09-04 00:18:56 +0000599
Kate Stoneb9c1b512016-09-06 20:57:50 +0000600 case LaunchFlavor::PosixSpawn: {
601 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
Todd Fialae77fce02016-09-04 00:18:56 +0000602
Kate Stoneb9c1b512016-09-06 20:57:50 +0000603 // Retrieve paths for stdin/stdout/stderr.
604 cpu_type_t actual_cpu_type = 0;
605 error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid,
606 &actual_cpu_type);
607 if (error.Success()) {
608 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
609 if (pty_master_fd)
610 *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
611 } else {
612 // Reset any variables that might have been set during a failed
613 // launch attempt.
614 if (pty_master_fd)
615 *pty_master_fd = -1;
616
617 // We're done.
618 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000619 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000620 break;
621 }
Todd Fialae77fce02016-09-04 00:18:56 +0000622
Kate Stoneb9c1b512016-09-06 20:57:50 +0000623 default:
624 // Invalid launch flavor.
625 error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown "
626 "launch flavor %d",
627 __FUNCTION__, (int)*launch_flavor);
Todd Fialae77fce02016-09-04 00:18:56 +0000628 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000629 }
630
631 if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
632 // If we don't have a valid process ID and no one has set the error,
633 // then return a generic error.
634 if (error.Success())
635 error.SetErrorStringWithFormat("%s(): failed to launch, no reason "
636 "specified",
637 __FUNCTION__);
638 }
639
640 // We're done with the launch side of the operation.
641 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000642}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000643}
644} // namespaces