blob: 95659725ce2ec73e64b02fb799ae4b97b9ad6c19 [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
Zachary Turner24ae6292017-02-16 19:38:21 +000033#include "lldb/Host/PseudoTerminal.h"
Todd Fialae77fce02016-09-04 00:18:56 +000034#include "lldb/Target/ProcessLaunchInfo.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000035#include "lldb/Utility/Log.h"
Zachary Turner97206d52017-05-12 04:51:55 +000036#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000037#include "lldb/Utility/StreamString.h"
Pavel Labath10c41f32017-06-06 14:06:17 +000038#include "llvm/Support/Errno.h"
Todd Fialae77fce02016-09-04 00:18:56 +000039
40#include "CFBundle.h"
41#include "CFString.h"
42
43using namespace lldb;
44using namespace lldb_private;
45using namespace lldb_private::process_darwin;
46using namespace lldb_private::darwin_process_launcher;
47
Kate Stoneb9c1b512016-09-06 20:57:50 +000048namespace {
49static LaunchFlavor g_launch_flavor = LaunchFlavor::Default;
Todd Fialae77fce02016-09-04 00:18:56 +000050}
51
Kate Stoneb9c1b512016-09-06 20:57:50 +000052namespace lldb_private {
53namespace darwin_process_launcher {
Todd Fialae77fce02016-09-04 00:18:56 +000054
Kate Stoneb9c1b512016-09-06 20:57:50 +000055static uint32_t GetCPUTypeForLocalProcess(::pid_t pid) {
56 int mib[CTL_MAXNAME] = {
57 0,
58 };
59 size_t len = CTL_MAXNAME;
60 if (::sysctlnametomib("sysctl.proc_cputype", mib, &len))
61 return 0;
Todd Fialae77fce02016-09-04 00:18:56 +000062
Kate Stoneb9c1b512016-09-06 20:57:50 +000063 mib[len] = pid;
64 len++;
Todd Fialae77fce02016-09-04 00:18:56 +000065
Kate Stoneb9c1b512016-09-06 20:57:50 +000066 cpu_type_t cpu;
67 size_t cpu_len = sizeof(cpu);
68 if (::sysctl(mib, static_cast<u_int>(len), &cpu, &cpu_len, 0, 0))
69 cpu = 0;
70 return cpu;
Todd Fialae77fce02016-09-04 00:18:56 +000071}
72
Kate Stoneb9c1b512016-09-06 20:57:50 +000073static bool ResolveExecutablePath(const char *path, char *resolved_path,
74 size_t resolved_path_size) {
75 if (path == NULL || path[0] == '\0')
Todd Fialae77fce02016-09-04 00:18:56 +000076 return false;
Kate Stoneb9c1b512016-09-06 20:57:50 +000077
78 char max_path[PATH_MAX];
79 std::string result;
80 CFString::GlobPath(path, result);
81
82 if (result.empty())
83 result = path;
84
85 struct stat path_stat;
86 if (::stat(path, &path_stat) == 0) {
87 if ((path_stat.st_mode & S_IFMT) == S_IFDIR) {
88 CFBundle bundle(path);
89 CFReleaser<CFURLRef> url(bundle.CopyExecutableURL());
90 if (url.get()) {
91 if (::CFURLGetFileSystemRepresentation(
92 url.get(), true, (UInt8 *)resolved_path, resolved_path_size))
93 return true;
94 }
95 }
96 }
97
98 if (realpath(path, max_path)) {
99 // Found the path relatively...
100 ::strncpy(resolved_path, max_path, resolved_path_size);
101 return strlen(resolved_path) + 1 < resolved_path_size;
102 } else {
103 // Not a relative path, check the PATH environment variable if the
104 const char *PATH = getenv("PATH");
105 if (PATH) {
106 const char *curr_path_start = PATH;
107 const char *curr_path_end;
108 while (curr_path_start && *curr_path_start) {
109 curr_path_end = strchr(curr_path_start, ':');
110 if (curr_path_end == NULL) {
111 result.assign(curr_path_start);
112 curr_path_start = NULL;
113 } else if (curr_path_end > curr_path_start) {
114 size_t len = curr_path_end - curr_path_start;
115 result.assign(curr_path_start, len);
116 curr_path_start += len + 1;
117 } else
118 break;
119
120 result += '/';
121 result += path;
122 struct stat s;
123 if (stat(result.c_str(), &s) == 0) {
124 ::strncpy(resolved_path, result.c_str(), resolved_path_size);
125 return result.size() + 1 < resolved_path_size;
126 }
127 }
128 }
129 }
130 return false;
Todd Fialae77fce02016-09-04 00:18:56 +0000131}
132
133// TODO check if we have a general purpose fork and exec. We may be
134// able to get rid of this entirely.
Zachary Turner97206d52017-05-12 04:51:55 +0000135static Status ForkChildForPTraceDebugging(const char *path, char const *argv[],
136 char const *envp[], ::pid_t *pid,
137 int *pty_fd) {
138 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000139 if (!path || !argv || !envp || !pid || !pty_fd) {
140 error.SetErrorString("invalid arguments");
Todd Fialae77fce02016-09-04 00:18:56 +0000141 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000142 }
143
144 // Use a fork that ties the child process's stdin/out/err to a pseudo
Adrian Prantl05097242018-04-30 16:49:04 +0000145 // terminal so we can read it in our MachProcess::STDIOThread as unbuffered
146 // io.
Pavel Labath07d6f882017-12-11 10:09:14 +0000147 PseudoTerminal pty;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000148 char fork_error[256];
149 memset(fork_error, 0, sizeof(fork_error));
150 *pid = static_cast<::pid_t>(pty.Fork(fork_error, sizeof(fork_error)));
151 if (*pid < 0) {
152 //--------------------------------------------------------------
Zachary Turner97206d52017-05-12 04:51:55 +0000153 // Status during fork.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000154 //--------------------------------------------------------------
155 *pid = static_cast<::pid_t>(LLDB_INVALID_PROCESS_ID);
156 error.SetErrorStringWithFormat("%s(): fork failed: %s", __FUNCTION__,
157 fork_error);
158 return error;
159 } else if (pid == 0) {
160 //--------------------------------------------------------------
161 // Child process
162 //--------------------------------------------------------------
163
164 // Debug this process.
165 ::ptrace(PT_TRACE_ME, 0, 0, 0);
166
167 // Get BSD signals as mach exceptions.
168 ::ptrace(PT_SIGEXC, 0, 0, 0);
169
Adrian Prantl05097242018-04-30 16:49:04 +0000170 // If our parent is setgid, lets make sure we don't inherit those extra
171 // powers due to nepotism.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000172 if (::setgid(getgid()) == 0) {
Adrian Prantl05097242018-04-30 16:49:04 +0000173 // Let the child have its own process group. We need to execute this call
174 // in both the child and parent to avoid a race condition between the two
175 // processes.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000176
177 // Set the child process group to match its pid.
178 ::setpgid(0, 0);
179
180 // Sleep a bit to before the exec call.
181 ::sleep(1);
182
183 // Turn this process into the given executable.
184 ::execv(path, (char *const *)argv);
185 }
Adrian Prantl05097242018-04-30 16:49:04 +0000186 // Exit with error code. Child process should have taken over in above exec
187 // call and if the exec fails it will exit the child process below.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000188 ::exit(127);
189 } else {
190 //--------------------------------------------------------------
191 // Parent process
192 //--------------------------------------------------------------
Adrian Prantl05097242018-04-30 16:49:04 +0000193 // Let the child have its own process group. We need to execute this call
194 // in both the child and parent to avoid a race condition between the two
195 // processes.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000196
197 // Set the child process group to match its pid
198 ::setpgid(*pid, *pid);
199 if (pty_fd) {
Adrian Prantl05097242018-04-30 16:49:04 +0000200 // Release our master pty file descriptor so the pty class doesn't close
201 // it and so we can continue to use it in our STDIO thread
Kate Stoneb9c1b512016-09-06 20:57:50 +0000202 *pty_fd = pty.ReleaseMasterFileDescriptor();
203 }
204 }
205 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000206}
207
Zachary Turner97206d52017-05-12 04:51:55 +0000208static Status
Todd Fialae77fce02016-09-04 00:18:56 +0000209CreatePosixSpawnFileAction(const FileAction &action,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000210 posix_spawn_file_actions_t *file_actions) {
Zachary Turner97206d52017-05-12 04:51:55 +0000211 Status 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
Zachary Turner97206d52017-05-12 04:51:55 +0000273static Status PosixSpawnChildForPTraceDebugging(const char *path,
274 ProcessLaunchInfo &launch_info,
275 ::pid_t *pid,
276 cpu_type_t *actual_cpu_type) {
277 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000278 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
Adrian Prantl05097242018-04-30 16:49:04 +0000304 // Ensure we clean up the spawnattr structure however we exit this function.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000305 std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up(
306 &attr, ::posix_spawnattr_destroy);
Todd Fialae77fce02016-09-04 00:18:56 +0000307
Kate Stoneb9c1b512016-09-06 20:57:50 +0000308 flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
309 POSIX_SPAWN_SETSIGMASK;
310 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
311 flags |= _POSIX_SPAWN_DISABLE_ASLR;
Todd Fialae77fce02016-09-04 00:18:56 +0000312
Kate Stoneb9c1b512016-09-06 20:57:50 +0000313 sigset_t no_signals;
314 sigset_t all_signals;
315 sigemptyset(&no_signals);
316 sigfillset(&all_signals);
317 ::posix_spawnattr_setsigmask(&attr, &no_signals);
318 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
Todd Fialae77fce02016-09-04 00:18:56 +0000319
Kate Stoneb9c1b512016-09-06 20:57:50 +0000320 if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000321 LLDB_LOG(log,
322 "::posix_spawnattr_setflags(&attr, "
323 "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}",
324 flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR"
325 : "",
326 llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000327 error.SetError(error_code, eErrorTypePOSIX);
328 return error;
329 }
Todd Fialae77fce02016-09-04 00:18:56 +0000330
331#if !defined(__arm__)
332
Adrian Prantl05097242018-04-30 16:49:04 +0000333 // We don't need to do this for ARM, and we really shouldn't now that we have
334 // multiple CPU subtypes and no posix_spawnattr call that allows us to set
335 // which CPU subtype to launch...
Kate Stoneb9c1b512016-09-06 20:57:50 +0000336 cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType();
337 if (desired_cpu_type != LLDB_INVALID_CPUTYPE) {
338 size_t ocount = 0;
339 error_code =
340 ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
341 if (error_code != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000342 LLDB_LOG(log,
343 "::posix_spawnattr_setbinpref_np(&attr, 1, "
344 "cpu_type = {0:x8}, count => {1}): {2}",
345 desired_cpu_type, ocount, llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000346 error.SetError(error_code, eErrorTypePOSIX);
347 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000348 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000349 if (ocount != 1) {
350 error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np "
351 "did not set the expected number "
352 "of cpu_type entries: expected 1 "
353 "but was %zu",
354 ocount);
355 return error;
356 }
357 }
Todd Fialae77fce02016-09-04 00:18:56 +0000358#endif
359
Kate Stoneb9c1b512016-09-06 20:57:50 +0000360 posix_spawn_file_actions_t file_actions;
361 if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000362 LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}",
363 llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000364 error.SetError(error_code, eErrorTypePOSIX);
Todd Fialae77fce02016-09-04 00:18:56 +0000365 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000366 }
367
368 // Ensure we clean up file actions however we exit this. When the
369 // file_actions_up below goes out of scope, we'll get our file action
370 // cleanup.
371 std::unique_ptr<posix_spawn_file_actions_t,
372 int (*)(posix_spawn_file_actions_t *)>
373 file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy);
374
Adrian Prantl05097242018-04-30 16:49:04 +0000375 // We assume the caller has setup the file actions appropriately. We are not
376 // in the business of figuring out what we really need here. lldb-server will
377 // have already called FinalizeFileActions() as well to button these up
378 // properly.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000379 const size_t num_actions = launch_info.GetNumFileActions();
380 for (size_t action_index = 0; action_index < num_actions; ++action_index) {
381 const FileAction *const action =
382 launch_info.GetFileActionAtIndex(action_index);
383 if (!action)
384 continue;
385
386 error = CreatePosixSpawnFileAction(*action, &file_actions);
387 if (!error.Success()) {
388 if (log)
389 log->Printf("%s(): error converting FileAction to posix_spawn "
390 "file action: %s",
391 __FUNCTION__, error.AsCString());
392 return error;
393 }
394 }
395
396 // TODO: Verify if we can set the working directory back immediately
397 // after the posix_spawnp call without creating a race condition???
398 const char *const working_directory =
399 launch_info.GetWorkingDirectory().GetCString();
400 if (working_directory && working_directory[0])
401 ::chdir(working_directory);
402
403 auto argv = launch_info.GetArguments().GetArgumentVector();
404 auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
405 error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
406 (char *const *)argv, (char *const *)envp);
407 if (error_code != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000408 LLDB_LOG(log,
409 "::posix_spawnp(pid => {0}, path = '{1}', file_actions "
410 "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}",
411 pid, path, &file_actions, &attr, argv, envp,
412 llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000413 error.SetError(error_code, eErrorTypePOSIX);
414 return error;
415 }
416
417 // Validate we got a pid.
418 if (pid == LLDB_INVALID_PROCESS_ID) {
419 error.SetErrorString("posix_spawn() did not indicate a failure but it "
420 "failed to return a pid, aborting.");
421 return error;
422 }
423
424 if (actual_cpu_type) {
425 *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
426 if (log)
427 log->Printf("%s(): cpu type for launched process pid=%i: "
428 "cpu_type=0x%8.8x",
429 __FUNCTION__, *pid, *actual_cpu_type);
430 }
431
432 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000433}
434
Zachary Turner97206d52017-05-12 04:51:55 +0000435Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
436 LaunchFlavor *launch_flavor) {
437 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000438 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000439
Kate Stoneb9c1b512016-09-06 20:57:50 +0000440 if (!launch_flavor) {
441 error.SetErrorString("mandatory launch_flavor field was null");
442 return error;
443 }
Todd Fialae77fce02016-09-04 00:18:56 +0000444
Kate Stoneb9c1b512016-09-06 20:57:50 +0000445 if (log) {
446 StreamString stream;
447 stream.Printf("NativeProcessDarwin::%s(): launching with the "
448 "following launch info:",
449 __FUNCTION__);
450 launch_info.Dump(stream, nullptr);
451 stream.Flush();
452 log->PutCString(stream.GetString().c_str());
453 }
Todd Fialae77fce02016-09-04 00:18:56 +0000454
Kate Stoneb9c1b512016-09-06 20:57:50 +0000455 // Retrieve the binary name given to us.
456 char given_path[PATH_MAX];
457 given_path[0] = '\0';
458 launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path));
Todd Fialae77fce02016-09-04 00:18:56 +0000459
Kate Stoneb9c1b512016-09-06 20:57:50 +0000460 // Determine the manner in which we'll launch.
461 *launch_flavor = g_launch_flavor;
462 if (*launch_flavor == LaunchFlavor::Default) {
463 // Our default launch method is posix spawn
464 *launch_flavor = LaunchFlavor::PosixSpawn;
Todd Fialae77fce02016-09-04 00:18:56 +0000465#if defined WITH_FBS
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 = eLaunchFlavorFBS;
469 }
Todd Fialae77fce02016-09-04 00:18:56 +0000470#elif defined WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000471 // Check if we have an app bundle, if so launch using BackBoard Services.
472 if (strstr(given_path, ".app")) {
473 *launch_flavor = eLaunchFlavorBKS;
474 }
Todd Fialae77fce02016-09-04 00:18:56 +0000475#elif defined WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000476 // Check if we have an app bundle, if so launch using SpringBoard.
477 if (strstr(given_path, ".app")) {
478 *launch_flavor = eLaunchFlavorSpringBoard;
479 }
Todd Fialae77fce02016-09-04 00:18:56 +0000480#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000481 }
Todd Fialae77fce02016-09-04 00:18:56 +0000482
Kate Stoneb9c1b512016-09-06 20:57:50 +0000483 // Attempt to resolve the binary name to an absolute path.
484 char resolved_path[PATH_MAX];
485 resolved_path[0] = '\0';
Todd Fialae77fce02016-09-04 00:18:56 +0000486
Kate Stoneb9c1b512016-09-06 20:57:50 +0000487 if (log)
488 log->Printf("%s(): attempting to resolve given binary path: \"%s\"",
489 __FUNCTION__, given_path);
490
491 // If we fail to resolve the path to our executable, then just use what we
492 // were given and hope for the best
493 if (!ResolveExecutablePath(given_path, resolved_path,
494 sizeof(resolved_path))) {
Todd Fialae77fce02016-09-04 00:18:56 +0000495 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000496 log->Printf("%s(): failed to resolve binary path, using "
497 "what was given verbatim and hoping for the best",
498 __FUNCTION__);
499 ::strncpy(resolved_path, given_path, sizeof(resolved_path));
500 } else {
501 if (log)
502 log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__,
503 resolved_path);
504 }
Todd Fialae77fce02016-09-04 00:18:56 +0000505
Kate Stoneb9c1b512016-09-06 20:57:50 +0000506 char launch_err_str[PATH_MAX];
507 launch_err_str[0] = '\0';
508
509 // TODO figure out how to handle QSetProcessEvent
510 // const char *process_event = ctx.GetProcessEvent();
511
512 // Ensure the binary is there.
513 struct stat path_stat;
514 if (::stat(resolved_path, &path_stat) == -1) {
515 error.SetErrorToErrno();
516 return error;
517 }
518
519 // Fork a child process for debugging
520 // state_callback(eStateLaunching);
521
522 const auto argv = launch_info.GetArguments().GetConstArgumentVector();
523 const auto envp =
524 launch_info.GetEnvironmentEntries().GetConstArgumentVector();
525
526 switch (*launch_flavor) {
527 case LaunchFlavor::ForkExec: {
528 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
529 error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid,
530 pty_master_fd);
531 if (error.Success()) {
532 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
533 } else {
Adrian Prantl05097242018-04-30 16:49:04 +0000534 // Reset any variables that might have been set during a failed launch
535 // attempt.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000536 if (pty_master_fd)
537 *pty_master_fd = -1;
538
539 // We're done.
540 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000541 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000542 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000543
544#ifdef WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000545 case LaunchFlavor::FBS: {
546 const char *app_ext = strstr(path, ".app");
547 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
548 std::string app_bundle_path(path, app_ext + strlen(".app"));
549 m_flags |= eMachProcessFlagsUsingFBS;
550 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
551 no_stdio, disable_aslr, event_data,
552 launch_err) != 0)
553 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
554 // non-zero m_pid.
555 else
556 break; // We tried a FBS launch, but didn't succeed lets get out
557 }
558 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000559#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000560
Todd Fialae77fce02016-09-04 00:18:56 +0000561#ifdef WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000562 case LaunchFlavor::BKS: {
563 const char *app_ext = strstr(path, ".app");
564 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
565 std::string app_bundle_path(path, app_ext + strlen(".app"));
566 m_flags |= eMachProcessFlagsUsingBKS;
567 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
568 no_stdio, disable_aslr, event_data,
569 launch_err) != 0)
570 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
571 // non-zero m_pid.
572 else
573 break; // We tried a BKS launch, but didn't succeed lets get out
574 }
575 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000576#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000577
Todd Fialae77fce02016-09-04 00:18:56 +0000578#ifdef WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000579 case LaunchFlavor::SpringBoard: {
580 // .../whatever.app/whatever ?
581 // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in
582 // "com.apple.whatever" here
583 const char *app_ext = strstr(path, ".app/");
584 if (app_ext == NULL) {
585 // .../whatever.app ?
586 int len = strlen(path);
587 if (len > 5) {
588 if (strcmp(path + len - 4, ".app") == 0) {
589 app_ext = path + len - 4;
Todd Fialae77fce02016-09-04 00:18:56 +0000590 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000591 }
592 }
593 if (app_ext) {
594 std::string app_bundle_path(path, app_ext + strlen(".app"));
595 if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
596 disable_aslr, launch_err) != 0)
597 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
598 // non-zero m_pid.
599 else
600 break; // We tried a springboard launch, but didn't succeed lets get out
601 }
602 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000603#endif
Todd Fialae77fce02016-09-04 00:18:56 +0000604
Kate Stoneb9c1b512016-09-06 20:57:50 +0000605 case LaunchFlavor::PosixSpawn: {
606 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
Todd Fialae77fce02016-09-04 00:18:56 +0000607
Kate Stoneb9c1b512016-09-06 20:57:50 +0000608 // Retrieve paths for stdin/stdout/stderr.
609 cpu_type_t actual_cpu_type = 0;
610 error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid,
611 &actual_cpu_type);
612 if (error.Success()) {
613 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
614 if (pty_master_fd)
615 *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
616 } else {
Adrian Prantl05097242018-04-30 16:49:04 +0000617 // Reset any variables that might have been set during a failed launch
618 // attempt.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000619 if (pty_master_fd)
620 *pty_master_fd = -1;
621
622 // We're done.
623 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000624 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000625 break;
626 }
Todd Fialae77fce02016-09-04 00:18:56 +0000627
Kate Stoneb9c1b512016-09-06 20:57:50 +0000628 default:
629 // Invalid launch flavor.
630 error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown "
631 "launch flavor %d",
632 __FUNCTION__, (int)*launch_flavor);
Todd Fialae77fce02016-09-04 00:18:56 +0000633 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000634 }
635
636 if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
Adrian Prantl05097242018-04-30 16:49:04 +0000637 // If we don't have a valid process ID and no one has set the error, then
638 // return a generic error.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000639 if (error.Success())
640 error.SetErrorStringWithFormat("%s(): failed to launch, no reason "
641 "specified",
642 __FUNCTION__);
643 }
644
645 // We're done with the launch side of the operation.
646 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000647}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000648}
649} // namespaces