blob: cf00387d8f84f9bf3d59ea813b48a6f43a53912a [file] [log] [blame]
Alexander Shaposhnikov696bd632016-11-26 05:23:44 +00001//===-- DarwinProcessLauncher.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
Todd Fialae77fce02016-09-04 00:18:56 +000010//
11// DarwinProcessLauncher.cpp
12// lldb
13//
14// Created by Todd Fiala on 8/30/16.
15//
16//
17
18#include "DarwinProcessLauncher.h"
19
20// C includes
21#include <spawn.h>
22#include <sys/ptrace.h>
23#include <sys/stat.h>
24#include <sys/sysctl.h>
25
26#ifndef _POSIX_SPAWN_DISABLE_ASLR
Kate Stoneb9c1b512016-09-06 20:57:50 +000027#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
Todd Fialae77fce02016-09-04 00:18:56 +000028#endif
29
30// LLDB includes
31#include "lldb/lldb-enumerations.h"
32
Todd Fialae77fce02016-09-04 00:18:56 +000033#include "lldb/Core/Log.h"
Zachary Turner24ae6292017-02-16 19:38:21 +000034#include "lldb/Host/PseudoTerminal.h"
Todd Fialae77fce02016-09-04 00:18:56 +000035#include "lldb/Target/ProcessLaunchInfo.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000036#include "lldb/Utility/Error.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000037#include "lldb/Utility/StreamString.h"
Todd Fialae77fce02016-09-04 00:18:56 +000038
39#include "CFBundle.h"
40#include "CFString.h"
41
42using namespace lldb;
43using namespace lldb_private;
44using namespace lldb_private::process_darwin;
45using namespace lldb_private::darwin_process_launcher;
46
Kate Stoneb9c1b512016-09-06 20:57:50 +000047namespace {
48static LaunchFlavor g_launch_flavor = LaunchFlavor::Default;
Todd Fialae77fce02016-09-04 00:18:56 +000049}
50
Kate Stoneb9c1b512016-09-06 20:57:50 +000051namespace lldb_private {
52namespace darwin_process_launcher {
Todd Fialae77fce02016-09-04 00:18:56 +000053
Kate Stoneb9c1b512016-09-06 20:57:50 +000054static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) {
55 int mib[CTL_MAXNAME] = {
56 0,
57 };
58 size_t len = CTL_MAXNAME;
59 if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
60 return 0;
Todd Fialae77fce02016-09-04 00:18:56 +000061
Kate Stoneb9c1b512016-09-06 20:57:50 +000062 mib[len] = pid;
63 len++;
Todd Fialae77fce02016-09-04 00:18:56 +000064
Kate Stoneb9c1b512016-09-06 20:57:50 +000065 cpu_type_t cpu;
66 size_t cpu_len = sizeof(cpu);
67 if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
68 cpu = 0;
69 return cpu;
Todd Fialae77fce02016-09-04 00:18:56 +000070}
71
Kate Stoneb9c1b512016-09-06 20:57:50 +000072static bool ResolveExecutablePath(const char *path, char *resolved_path,
73 size_t resolved_path_size) {
74 if (path == NULL || path[0] == '\0')
Todd Fialae77fce02016-09-04 00:18:56 +000075 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000076
77 char max_path[PATH_MAX];
78 std::string result;
79 CFString::GlobPath(path, result);
80
81 if (result.empty())
82 result = path;
83
84 struct stat path_stat;
85 if (::stat(path, &path_stat) == 0) {
86 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
87 CFBundle bundle(path);
88 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
89 if (url.get()) {
90 if (::CFURLGetFileSystemRepresentation(
91 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
92 return true;
93 }
94 }
95 }
96
97 if (realpath(path, max_path)) {
98 // Found the path relatively...
99 ::strncpy(resolved_path, max_path, resolved_path_size);
100 return strlen(resolved_path) + 1 < resolved_path_size;
101 } else {
102 // Not a relative path, check the PATH environment variable if the
103 const char *PATH = getenv("PATH");
104 if (PATH) {
105 const char *curr_path_start = PATH;
106 const char *curr_path_end;
107 while (curr_path_start && *curr_path_start) {
108 curr_path_end = strchr(curr_path_start, ':');
109 if (curr_path_end == NULL) {
110 result.assign(curr_path_start);
111 curr_path_start = NULL;
112 } else if (curr_path_end > curr_path_start) {
113 size_t len = curr_path_end - curr_path_start;
114 result.assign(curr_path_start, len);
115 curr_path_start += len + 1;
116 } else
117 break;
118
119 result += '/';
120 result += path;
121 struct stat s;
122 if (stat(result.c_str(), &s) == 0) {
123 ::strncpy(resolved_path, result.c_str(), resolved_path_size);
124 return result.size() + 1 < resolved_path_size;
125 }
126 }
127 }
128 }
129 return false;
Todd Fialae77fce02016-09-04 00:18:56 +0000130}
131
132// TODO check if we have a general purpose fork and exec. We may be
133// able to get rid of this entirely.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000134static Error ForkChildForPTraceDebugging(const char *path, char const *argv[],
135 char const *envp[], ::pid_t *pid,
136 int *pty_fd) {
137 Error error;
138 if (!path || !argv || !envp || !pid || !pty_fd) {
139 error.SetErrorString("invalid arguments");
Todd Fialae77fce02016-09-04 00:18:56 +0000140 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000141 }
142
143 // Use a fork that ties the child process's stdin/out/err to a pseudo
144 // terminal so we can read it in our MachProcess::STDIOThread
145 // as unbuffered io.
146 lldb_utility::PseudoTerminal pty;
147 char fork_error[256];
148 memset(fork_error, 0, sizeof(fork_error));
149 *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error)));
150 if (*pid < 0) {
151 //--------------------------------------------------------------
152 // Error during fork.
153 //--------------------------------------------------------------
154 *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
155 error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__,
156 fork_error);
157 return error;
158 } else if (pid == 0) {
159 //--------------------------------------------------------------
160 // Child process
161 //--------------------------------------------------------------
162
163 // Debug this process.
164 ::ptrace(PT_TRACE_ME, 0, 0, 0);
165
166 // Get BSD signals as mach exceptions.
167 ::ptrace(PT_SIGEXC, 0, 0, 0);
168
169 // If our parent is setgid, lets make sure we don't inherit those
170 // extra powers due to nepotism.
171 if (::setgid(getgid()) == 0) {
172 // Let the child have its own process group. We need to execute
173 // this call in both the child and parent to avoid a race
174 // condition between the two processes.
175
176 // Set the child process group to match its pid.
177 ::setpgid(0, 0);
178
179 // Sleep a bit to before the exec call.
180 ::sleep(1);
181
182 // Turn this process into the given executable.
183 ::execv(path, (char *const *)argv);
184 }
185 // Exit with error code. Child process should have taken
186 // over in above exec call and if the exec fails it will
187 // exit the child process below.
188 ::exit(127);
189 } else {
190 //--------------------------------------------------------------
191 // Parent process
192 //--------------------------------------------------------------
193 // Let the child have its own process group. We need to execute
194 // this call in both the child and parent to avoid a race condition
195 // between the two processes.
196
197 // Set the child process group to match its pid
198 ::setpgid(*pid, *pid);
199 if (pty_fd) {
200 // Release our master pty file descriptor so the pty class doesn't
201 // close it and so we can continue to use it in our STDIO thread
202 *pty_fd = pty.ReleaseMasterFileDescriptor();
203 }
204 }
205 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000206}
207
208static Error
209CreatePosixSpawnFileAction(const FileAction &action,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210 posix_spawn_file_actions_t *file_actions) {
211 Error error;
Todd Fialae77fce02016-09-04 00:18:56 +0000212
Kate Stoneb9c1b512016-09-06 20:57:50 +0000213 // Log it.
214 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
215 if (log) {
216 StreamString stream;
217 stream.PutCString("converting file action for posix_spawn(): ");
218 action.Dump(stream);
219 stream.Flush();
220 log->PutCString(stream.GetString().c_str());
221 }
Todd Fialae77fce02016-09-04 00:18:56 +0000222
Kate Stoneb9c1b512016-09-06 20:57:50 +0000223 // Validate args.
224 if (!file_actions) {
225 error.SetErrorString("mandatory file_actions arg is null");
Todd Fialae77fce02016-09-04 00:18:56 +0000226 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000227 }
228
229 // Build the posix file action.
230 switch (action.GetAction()) {
231 case FileAction::eFileActionOpen: {
232 const int error_code = ::posix_spawn_file_actions_addopen(
233 file_actions, action.GetFD(), action.GetPath(),
234 action.GetActionArgument(), 0);
235 if (error_code != 0) {
236 error.SetError(error_code, eErrorTypePOSIX);
237 return error;
238 }
239 break;
240 }
241
242 case FileAction::eFileActionClose: {
243 const int error_code =
244 ::posix_spawn_file_actions_addclose(file_actions, action.GetFD());
245 if (error_code != 0) {
246 error.SetError(error_code, eErrorTypePOSIX);
247 return error;
248 }
249 break;
250 }
251
252 case FileAction::eFileActionDuplicate: {
253 const int error_code = ::posix_spawn_file_actions_adddup2(
254 file_actions, action.GetFD(), action.GetActionArgument());
255 if (error_code != 0) {
256 error.SetError(error_code, eErrorTypePOSIX);
257 return error;
258 }
259 break;
260 }
261
262 case FileAction::eFileActionNone:
263 default:
264 if (log)
265 log->Printf("%s(): unsupported file action %u", __FUNCTION__,
266 action.GetAction());
267 break;
268 }
269
270 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000271}
272
Kate Stoneb9c1b512016-09-06 20:57:50 +0000273static Error PosixSpawnChildForPTraceDebugging(const char *path,
274 ProcessLaunchInfo &launch_info,
275 ::pid_t *pid,
276 cpu_type_t *actual_cpu_type) {
277 Error error;
278 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000279
Kate Stoneb9c1b512016-09-06 20:57:50 +0000280 if (!pid) {
281 error.SetErrorStringWithFormat("%s(): pid arg cannot be null",
282 __FUNCTION__);
283 return error;
284 }
Todd Fialae77fce02016-09-04 00:18:56 +0000285
Kate Stoneb9c1b512016-09-06 20:57:50 +0000286 posix_spawnattr_t attr;
287 short flags;
288 if (log) {
289 StreamString stream;
290 stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path);
291 launch_info.Dump(stream, nullptr);
292 stream.Flush();
293 log->PutCString(stream.GetString().c_str());
294 }
295
296 int error_code;
297 if ((error_code = ::posix_spawnattr_init(&attr)) != 0) {
Todd Fialae77fce02016-09-04 00:18:56 +0000298 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000299 log->Printf("::posix_spawnattr_init(&attr) failed");
300 error.SetError(error_code, eErrorTypePOSIX);
301 return error;
302 }
Todd Fialae77fce02016-09-04 00:18:56 +0000303
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 // Ensure we clean up the spawnattr structure however we exit this
305 // function.
306 std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up(
307 &attr, ::posix_spawnattr_destroy);
Todd Fialae77fce02016-09-04 00:18:56 +0000308
Kate Stoneb9c1b512016-09-06 20:57:50 +0000309 flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
310 POSIX_SPAWN_SETSIGMASK;
311 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
312 flags |= _POSIX_SPAWN_DISABLE_ASLR;
Todd Fialae77fce02016-09-04 00:18:56 +0000313
Kate Stoneb9c1b512016-09-06 20:57:50 +0000314 sigset_t no_signals;
315 sigset_t all_signals;
316 sigemptyset(&no_signals);
317 sigfillset(&all_signals);
318 ::posix_spawnattr_setsigmask(&attr, &no_signals);
319 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
Todd Fialae77fce02016-09-04 00:18:56 +0000320
Kate Stoneb9c1b512016-09-06 20:57:50 +0000321 if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
322 if (log)
323 log->Printf("::posix_spawnattr_setflags(&attr, "
324 "POSIX_SPAWN_START_SUSPENDED%s) failed: %s",
325 flags & _POSIX_SPAWN_DISABLE_ASLR
326 ? " | _POSIX_SPAWN_DISABLE_ASLR"
327 : "",
328 strerror(error_code));
329 error.SetError(error_code, eErrorTypePOSIX);
330 return error;
331 }
Todd Fialae77fce02016-09-04 00:18:56 +0000332
333#if !defined(__arm__)
334
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 // We don't need to do this for ARM, and we really shouldn't now that we
336 // have multiple CPU subtypes and no posix_spawnattr call that allows us
337 // to set which CPU subtype to launch...
338 cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType();
339 if (desired_cpu_type != LLDB_INVALID_CPUTYPE) {
340 size_t ocount = 0;
341 error_code =
342 ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
343 if (error_code != 0) {
344 if (log)
345 log->Printf("::posix_spawnattr_setbinpref_np(&attr, 1, "
346 "cpu_type = 0x%8.8x, count => %llu): %s",
347 desired_cpu_type, (uint64_t)ocount, strerror(error_code));
348 error.SetError(error_code, eErrorTypePOSIX);
349 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000350 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000351 if (ocount != 1) {
352 error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np "
353 "did not set the expected number "
354 "of cpu_type entries: expected 1 "
355 "but was %zu",
356 ocount);
357 return error;
358 }
359 }
Todd Fialae77fce02016-09-04 00:18:56 +0000360#endif
361
Kate Stoneb9c1b512016-09-06 20:57:50 +0000362 posix_spawn_file_actions_t file_actions;
363 if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
364 if (log)
365 log->Printf("::posix_spawn_file_actions_init(&file_actions) "
366 "failed: %s",
367 strerror(error_code));
368 error.SetError(error_code, eErrorTypePOSIX);
Todd Fialae77fce02016-09-04 00:18:56 +0000369 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000370 }
371
372 // Ensure we clean up file actions however we exit this. When the
373 // file_actions_up below goes out of scope, we'll get our file action
374 // cleanup.
375 std::unique_ptr<posix_spawn_file_actions_t,
376 int (*)(posix_spawn_file_actions_t *)>
377 file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy);
378
379 // We assume the caller has setup the file actions appropriately. We
380 // are not in the business of figuring out what we really need here.
381 // lldb-server will have already called FinalizeFileActions() as well
382 // to button these up properly.
383 const size_t num_actions = launch_info.GetNumFileActions();
384 for (size_t action_index = 0; action_index < num_actions; ++action_index) {
385 const FileAction *const action =
386 launch_info.GetFileActionAtIndex(action_index);
387 if (!action)
388 continue;
389
390 error = CreatePosixSpawnFileAction(*action, &file_actions);
391 if (!error.Success()) {
392 if (log)
393 log->Printf("%s(): error converting FileAction to posix_spawn "
394 "file action: %s",
395 __FUNCTION__, error.AsCString());
396 return error;
397 }
398 }
399
400 // TODO: Verify if we can set the working directory back immediately
401 // after the posix_spawnp call without creating a race condition???
402 const char *const working_directory =
403 launch_info.GetWorkingDirectory().GetCString();
404 if (working_directory && working_directory[0])
405 ::chdir(working_directory);
406
407 auto argv = launch_info.GetArguments().GetArgumentVector();
408 auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
409 error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
410 (char *const *)argv, (char *const *)envp);
411 if (error_code != 0) {
412 if (log)
413 log->Printf("::posix_spawnp(pid => %p, path = '%s', file_actions "
414 "= %p, attr = %p, argv = %p, envp = %p) failed: %s",
415 pid, path, &file_actions, &attr, argv, envp,
416 strerror(error_code));
417 error.SetError(error_code, eErrorTypePOSIX);
418 return error;
419 }
420
421 // Validate we got a pid.
422 if (pid == LLDB_INVALID_PROCESS_ID) {
423 error.SetErrorString("posix_spawn() did not indicate a failure but it "
424 "failed to return a pid, aborting.");
425 return error;
426 }
427
428 if (actual_cpu_type) {
429 *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
430 if (log)
431 log->Printf("%s(): cpu type for launched process pid=%i: "
432 "cpu_type=0x%8.8x",
433 __FUNCTION__, *pid, *actual_cpu_type);
434 }
435
436 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000437}
438
Kate Stoneb9c1b512016-09-06 20:57:50 +0000439Error LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
440 LaunchFlavor *launch_flavor) {
441 Error error;
442 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000443
Kate Stoneb9c1b512016-09-06 20:57:50 +0000444 if (!launch_flavor) {
445 error.SetErrorString("mandatory launch_flavor field was null");
446 return error;
447 }
Todd Fialae77fce02016-09-04 00:18:56 +0000448
Kate Stoneb9c1b512016-09-06 20:57:50 +0000449 if (log) {
450 StreamString stream;
451 stream.Printf("NativeProcessDarwin::%s(): launching with the "
452 "following launch info:",
453 __FUNCTION__);
454 launch_info.Dump(stream, nullptr);
455 stream.Flush();
456 log->PutCString(stream.GetString().c_str());
457 }
Todd Fialae77fce02016-09-04 00:18:56 +0000458
Kate Stoneb9c1b512016-09-06 20:57:50 +0000459 // Retrieve the binary name given to us.
460 char given_path[PATH_MAX];
461 given_path[0] = '\0';
462 launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path));
Todd Fialae77fce02016-09-04 00:18:56 +0000463
Kate Stoneb9c1b512016-09-06 20:57:50 +0000464 // Determine the manner in which we'll launch.
465 *launch_flavor = g_launch_flavor;
466 if (*launch_flavor == LaunchFlavor::Default) {
467 // Our default launch method is posix spawn
468 *launch_flavor = LaunchFlavor::PosixSpawn;
Todd Fialae77fce02016-09-04 00:18:56 +0000469#if defined WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000470 // Check if we have an app bundle, if so launch using BackBoard Services.
471 if (strstr(given_path, ".app")) {
472 *launch_flavor = eLaunchFlavorFBS;
473 }
Todd Fialae77fce02016-09-04 00:18:56 +0000474#elif defined WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000475 // Check if we have an app bundle, if so launch using BackBoard Services.
476 if (strstr(given_path, ".app")) {
477 *launch_flavor = eLaunchFlavorBKS;
478 }
Todd Fialae77fce02016-09-04 00:18:56 +0000479#elif defined WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000480 // Check if we have an app bundle, if so launch using SpringBoard.
481 if (strstr(given_path, ".app")) {
482 *launch_flavor = eLaunchFlavorSpringBoard;
483 }
Todd Fialae77fce02016-09-04 00:18:56 +0000484#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000485 }
Todd Fialae77fce02016-09-04 00:18:56 +0000486
Kate Stoneb9c1b512016-09-06 20:57:50 +0000487 // Attempt to resolve the binary name to an absolute path.
488 char resolved_path[PATH_MAX];
489 resolved_path[0] = '\0';
Todd Fialae77fce02016-09-04 00:18:56 +0000490
Kate Stoneb9c1b512016-09-06 20:57:50 +0000491 if (log)
492 log->Printf("%s(): attempting to resolve given binary path: \"%s\"",
493 __FUNCTION__, given_path);
494
495 // If we fail to resolve the path to our executable, then just use what we
496 // were given and hope for the best
497 if (!ResolveExecutablePath(given_path, resolved_path,
498 sizeof(resolved_path))) {
Todd Fialae77fce02016-09-04 00:18:56 +0000499 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000500 log->Printf("%s(): failed to resolve binary path, using "
501 "what was given verbatim and hoping for the best",
502 __FUNCTION__);
503 ::strncpy(resolved_path, given_path, sizeof(resolved_path));
504 } else {
505 if (log)
506 log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__,
507 resolved_path);
508 }
Todd Fialae77fce02016-09-04 00:18:56 +0000509
Kate Stoneb9c1b512016-09-06 20:57:50 +0000510 char launch_err_str[PATH_MAX];
511 launch_err_str[0] = '\0';
512
513 // TODO figure out how to handle QSetProcessEvent
514 // const char *process_event = ctx.GetProcessEvent();
515
516 // Ensure the binary is there.
517 struct stat path_stat;
518 if (::stat(resolved_path, &path_stat) == -1) {
519 error.SetErrorToErrno();
520 return error;
521 }
522
523 // Fork a child process for debugging
524 // state_callback(eStateLaunching);
525
526 const auto argv = launch_info.GetArguments().GetConstArgumentVector();
527 const auto envp =
528 launch_info.GetEnvironmentEntries().GetConstArgumentVector();
529
530 switch (*launch_flavor) {
531 case LaunchFlavor::ForkExec: {
532 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
533 error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid,
534 pty_master_fd);
535 if (error.Success()) {
536 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
537 } else {
538 // Reset any variables that might have been set during a failed
539 // launch attempt.
540 if (pty_master_fd)
541 *pty_master_fd = -1;
542
543 // We're done.
544 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000545 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000546 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000547
548#ifdef WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000549 case LaunchFlavor::FBS: {
550 const char *app_ext = strstr(path, ".app");
551 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
552 std::string app_bundle_path(path, app_ext + strlen(".app"));
553 m_flags |= eMachProcessFlagsUsingFBS;
554 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
555 no_stdio, disable_aslr, event_data,
556 launch_err) != 0)
557 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
558 // non-zero m_pid.
559 else
560 break; // We tried a FBS launch, but didn't succeed lets get out
561 }
562 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000563#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000564
Todd Fialae77fce02016-09-04 00:18:56 +0000565#ifdef WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000566 case LaunchFlavor::BKS: {
567 const char *app_ext = strstr(path, ".app");
568 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
569 std::string app_bundle_path(path, app_ext + strlen(".app"));
570 m_flags |= eMachProcessFlagsUsingBKS;
571 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
572 no_stdio, disable_aslr, event_data,
573 launch_err) != 0)
574 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
575 // non-zero m_pid.
576 else
577 break; // We tried a BKS launch, but didn't succeed lets get out
578 }
579 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000580#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000581
Todd Fialae77fce02016-09-04 00:18:56 +0000582#ifdef WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000583 case LaunchFlavor::SpringBoard: {
584 // .../whatever.app/whatever ?
585 // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in
586 // "com.apple.whatever" here
587 const char *app_ext = strstr(path, ".app/");
588 if (app_ext == NULL) {
589 // .../whatever.app ?
590 int len = strlen(path);
591 if (len > 5) {
592 if (strcmp(path + len - 4, ".app") == 0) {
593 app_ext = path + len - 4;
Todd Fialae77fce02016-09-04 00:18:56 +0000594 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000595 }
596 }
597 if (app_ext) {
598 std::string app_bundle_path(path, app_ext + strlen(".app"));
599 if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
600 disable_aslr, launch_err) != 0)
601 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
602 // non-zero m_pid.
603 else
604 break; // We tried a springboard launch, but didn't succeed lets get out
605 }
606 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000607#endif
Todd Fialae77fce02016-09-04 00:18:56 +0000608
Kate Stoneb9c1b512016-09-06 20:57:50 +0000609 case LaunchFlavor::PosixSpawn: {
610 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
Todd Fialae77fce02016-09-04 00:18:56 +0000611
Kate Stoneb9c1b512016-09-06 20:57:50 +0000612 // Retrieve paths for stdin/stdout/stderr.
613 cpu_type_t actual_cpu_type = 0;
614 error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid,
615 &actual_cpu_type);
616 if (error.Success()) {
617 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
618 if (pty_master_fd)
619 *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
620 } else {
621 // Reset any variables that might have been set during a failed
622 // launch attempt.
623 if (pty_master_fd)
624 *pty_master_fd = -1;
625
626 // We're done.
627 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000628 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000629 break;
630 }
Todd Fialae77fce02016-09-04 00:18:56 +0000631
Kate Stoneb9c1b512016-09-06 20:57:50 +0000632 default:
633 // Invalid launch flavor.
634 error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown "
635 "launch flavor %d",
636 __FUNCTION__, (int)*launch_flavor);
Todd Fialae77fce02016-09-04 00:18:56 +0000637 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000638 }
639
640 if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
641 // If we don't have a valid process ID and no one has set the error,
642 // then return a generic error.
643 if (error.Success())
644 error.SetErrorStringWithFormat("%s(): failed to launch, no reason "
645 "specified",
646 __FUNCTION__);
647 }
648
649 // We're done with the launch side of the operation.
650 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000651}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000652}
653} // namespaces