blob: c72def3740780a21de76363bc0449799f22d64b9 [file] [log] [blame]
Alexander Shaposhnikov696bd632016-11-26 05:23:44 +00001//===-- DarwinProcessLauncher.cpp -------------------------------*- C++ -*-===//
2//
Chandler Carruth2946cd72019-01-19 08:50:56 +00003// 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
Alexander Shaposhnikov696bd632016-11-26 05:23:44 +00006//
7//===----------------------------------------------------------------------===//
8
Todd Fialae77fce02016-09-04 00:18:56 +00009//
10// DarwinProcessLauncher.cpp
11// lldb
12//
13// Created by Todd Fiala on 8/30/16.
14//
15//
16
17#include "DarwinProcessLauncher.h"
18
19// C includes
20#include <spawn.h>
21#include <sys/ptrace.h>
22#include <sys/stat.h>
23#include <sys/sysctl.h>
24
25#ifndef _POSIX_SPAWN_DISABLE_ASLR
Kate Stoneb9c1b512016-09-06 20:57:50 +000026#define _POSIX_SPAWN_DISABLE_ASLR 0x0100
Todd Fialae77fce02016-09-04 00:18:56 +000027#endif
28
29// LLDB includes
30#include "lldb/lldb-enumerations.h"
31
Zachary Turner24ae6292017-02-16 19:38:21 +000032#include "lldb/Host/PseudoTerminal.h"
Todd Fialae77fce02016-09-04 00:18:56 +000033#include "lldb/Target/ProcessLaunchInfo.h"
Zachary Turner6f9e6902017-03-03 20:56:28 +000034#include "lldb/Utility/Log.h"
Zachary Turner97206d52017-05-12 04:51:55 +000035#include "lldb/Utility/Status.h"
Zachary Turnerbf9a7732017-02-02 21:39:50 +000036#include "lldb/Utility/StreamString.h"
Pavel Labath10c41f32017-06-06 14:06:17 +000037#include "llvm/Support/Errno.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.
Zachary Turner97206d52017-05-12 04:51:55 +0000134static Status ForkChildForPTraceDebugging(const char *path, char const *argv[],
135 char const *envp[], ::pid_t *pid,
136 int *pty_fd) {
137 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000138 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
Adrian Prantl05097242018-04-30 16:49:04 +0000144 // terminal so we can read it in our MachProcess::STDIOThread as unbuffered
145 // io.
Pavel Labath07d6f882017-12-11 10:09:14 +0000146 PseudoTerminal pty;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000147 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 //--------------------------------------------------------------
Zachary Turner97206d52017-05-12 04:51:55 +0000152 // Status during fork.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000153 //--------------------------------------------------------------
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
Adrian Prantl05097242018-04-30 16:49:04 +0000169 // If our parent is setgid, lets make sure we don't inherit those extra
170 // powers due to nepotism.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000171 if (::setgid(getgid()) == 0) {
Adrian Prantl05097242018-04-30 16:49:04 +0000172 // Let the child have its own process group. We need to execute this call
173 // in both the child and parent to avoid a race condition between the two
174 // processes.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000175
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 }
Adrian Prantl05097242018-04-30 16:49:04 +0000185 // Exit with error code. Child process should have taken over in above exec
186 // call and if the exec fails it will exit the child process below.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000187 ::exit(127);
188 } else {
189 //--------------------------------------------------------------
190 // Parent process
191 //--------------------------------------------------------------
Adrian Prantl05097242018-04-30 16:49:04 +0000192 // Let the child have its own process group. We need to execute this call
193 // in both the child and parent to avoid a race condition between the two
194 // processes.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000195
196 // Set the child process group to match its pid
197 ::setpgid(*pid, *pid);
198 if (pty_fd) {
Adrian Prantl05097242018-04-30 16:49:04 +0000199 // Release our master pty file descriptor so the pty class doesn't close
200 // it and so we can continue to use it in our STDIO thread
Kate Stoneb9c1b512016-09-06 20:57:50 +0000201 *pty_fd = pty.ReleaseMasterFileDescriptor();
202 }
203 }
204 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000205}
206
Zachary Turner97206d52017-05-12 04:51:55 +0000207static Status
Todd Fialae77fce02016-09-04 00:18:56 +0000208CreatePosixSpawnFileAction(const FileAction &action,
Kate Stoneb9c1b512016-09-06 20:57:50 +0000209 posix_spawn_file_actions_t *file_actions) {
Zachary Turner97206d52017-05-12 04:51:55 +0000210 Status error;
Todd Fialae77fce02016-09-04 00:18:56 +0000211
Kate Stoneb9c1b512016-09-06 20:57:50 +0000212 // Log it.
213 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
214 if (log) {
215 StreamString stream;
216 stream.PutCString("converting file action for posix_spawn(): ");
217 action.Dump(stream);
218 stream.Flush();
219 log->PutCString(stream.GetString().c_str());
220 }
Todd Fialae77fce02016-09-04 00:18:56 +0000221
Kate Stoneb9c1b512016-09-06 20:57:50 +0000222 // Validate args.
223 if (!file_actions) {
224 error.SetErrorString("mandatory file_actions arg is null");
Todd Fialae77fce02016-09-04 00:18:56 +0000225 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000226 }
227
228 // Build the posix file action.
229 switch (action.GetAction()) {
230 case FileAction::eFileActionOpen: {
231 const int error_code = ::posix_spawn_file_actions_addopen(
232 file_actions, action.GetFD(), action.GetPath(),
233 action.GetActionArgument(), 0);
234 if (error_code != 0) {
235 error.SetError(error_code, eErrorTypePOSIX);
236 return error;
237 }
238 break;
239 }
240
241 case FileAction::eFileActionClose: {
242 const int error_code =
243 ::posix_spawn_file_actions_addclose(file_actions, action.GetFD());
244 if (error_code != 0) {
245 error.SetError(error_code, eErrorTypePOSIX);
246 return error;
247 }
248 break;
249 }
250
251 case FileAction::eFileActionDuplicate: {
252 const int error_code = ::posix_spawn_file_actions_adddup2(
253 file_actions, action.GetFD(), action.GetActionArgument());
254 if (error_code != 0) {
255 error.SetError(error_code, eErrorTypePOSIX);
256 return error;
257 }
258 break;
259 }
260
261 case FileAction::eFileActionNone:
262 default:
263 if (log)
264 log->Printf("%s(): unsupported file action %u", __FUNCTION__,
265 action.GetAction());
266 break;
267 }
268
269 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000270}
271
Zachary Turner97206d52017-05-12 04:51:55 +0000272static Status PosixSpawnChildForPTraceDebugging(const char *path,
273 ProcessLaunchInfo &launch_info,
274 ::pid_t *pid,
275 cpu_type_t *actual_cpu_type) {
276 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000277 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000278
Kate Stoneb9c1b512016-09-06 20:57:50 +0000279 if (!pid) {
280 error.SetErrorStringWithFormat("%s(): pid arg cannot be null",
281 __FUNCTION__);
282 return error;
283 }
Todd Fialae77fce02016-09-04 00:18:56 +0000284
Kate Stoneb9c1b512016-09-06 20:57:50 +0000285 posix_spawnattr_t attr;
286 short flags;
287 if (log) {
288 StreamString stream;
289 stream.Printf("%s(path='%s',...)\n", __FUNCTION__, path);
290 launch_info.Dump(stream, nullptr);
291 stream.Flush();
292 log->PutCString(stream.GetString().c_str());
293 }
294
295 int error_code;
296 if ((error_code = ::posix_spawnattr_init(&attr)) != 0) {
Todd Fialae77fce02016-09-04 00:18:56 +0000297 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000298 log->Printf("::posix_spawnattr_init(&attr) failed");
299 error.SetError(error_code, eErrorTypePOSIX);
300 return error;
301 }
Todd Fialae77fce02016-09-04 00:18:56 +0000302
Adrian Prantl05097242018-04-30 16:49:04 +0000303 // Ensure we clean up the spawnattr structure however we exit this function.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000304 std::unique_ptr<posix_spawnattr_t, int (*)(posix_spawnattr_t *)> spawnattr_up(
305 &attr, ::posix_spawnattr_destroy);
Todd Fialae77fce02016-09-04 00:18:56 +0000306
Kate Stoneb9c1b512016-09-06 20:57:50 +0000307 flags = POSIX_SPAWN_START_SUSPENDED | POSIX_SPAWN_SETSIGDEF |
308 POSIX_SPAWN_SETSIGMASK;
309 if (launch_info.GetFlags().Test(eLaunchFlagDisableASLR))
310 flags |= _POSIX_SPAWN_DISABLE_ASLR;
Todd Fialae77fce02016-09-04 00:18:56 +0000311
Kate Stoneb9c1b512016-09-06 20:57:50 +0000312 sigset_t no_signals;
313 sigset_t all_signals;
314 sigemptyset(&no_signals);
315 sigfillset(&all_signals);
316 ::posix_spawnattr_setsigmask(&attr, &no_signals);
317 ::posix_spawnattr_setsigdefault(&attr, &all_signals);
Todd Fialae77fce02016-09-04 00:18:56 +0000318
Kate Stoneb9c1b512016-09-06 20:57:50 +0000319 if ((error_code = ::posix_spawnattr_setflags(&attr, flags)) != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000320 LLDB_LOG(log,
321 "::posix_spawnattr_setflags(&attr, "
322 "POSIX_SPAWN_START_SUSPENDED{0}) failed: {1}",
323 flags & _POSIX_SPAWN_DISABLE_ASLR ? " | _POSIX_SPAWN_DISABLE_ASLR"
324 : "",
325 llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000326 error.SetError(error_code, eErrorTypePOSIX);
327 return error;
328 }
Todd Fialae77fce02016-09-04 00:18:56 +0000329
330#if !defined(__arm__)
331
Adrian Prantl05097242018-04-30 16:49:04 +0000332 // We don't need to do this for ARM, and we really shouldn't now that we have
333 // multiple CPU subtypes and no posix_spawnattr call that allows us to set
334 // which CPU subtype to launch...
Kate Stoneb9c1b512016-09-06 20:57:50 +0000335 cpu_type_t desired_cpu_type = launch_info.GetArchitecture().GetMachOCPUType();
336 if (desired_cpu_type != LLDB_INVALID_CPUTYPE) {
337 size_t ocount = 0;
338 error_code =
339 ::posix_spawnattr_setbinpref_np(&attr, 1, &desired_cpu_type, &ocount);
340 if (error_code != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000341 LLDB_LOG(log,
342 "::posix_spawnattr_setbinpref_np(&attr, 1, "
343 "cpu_type = {0:x8}, count => {1}): {2}",
344 desired_cpu_type, ocount, llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000345 error.SetError(error_code, eErrorTypePOSIX);
346 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000347 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000348 if (ocount != 1) {
349 error.SetErrorStringWithFormat("posix_spawnattr_setbinpref_np "
350 "did not set the expected number "
351 "of cpu_type entries: expected 1 "
352 "but was %zu",
353 ocount);
354 return error;
355 }
356 }
Todd Fialae77fce02016-09-04 00:18:56 +0000357#endif
358
Kate Stoneb9c1b512016-09-06 20:57:50 +0000359 posix_spawn_file_actions_t file_actions;
360 if ((error_code = ::posix_spawn_file_actions_init(&file_actions)) != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000361 LLDB_LOG(log, "::posix_spawn_file_actions_init(&file_actions) failed: {0}",
362 llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000363 error.SetError(error_code, eErrorTypePOSIX);
Todd Fialae77fce02016-09-04 00:18:56 +0000364 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000365 }
366
367 // Ensure we clean up file actions however we exit this. When the
368 // file_actions_up below goes out of scope, we'll get our file action
369 // cleanup.
370 std::unique_ptr<posix_spawn_file_actions_t,
371 int (*)(posix_spawn_file_actions_t *)>
372 file_actions_up(&file_actions, ::posix_spawn_file_actions_destroy);
373
Adrian Prantl05097242018-04-30 16:49:04 +0000374 // We assume the caller has setup the file actions appropriately. We are not
375 // in the business of figuring out what we really need here. lldb-server will
376 // have already called FinalizeFileActions() as well to button these up
377 // properly.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000378 const size_t num_actions = launch_info.GetNumFileActions();
379 for (size_t action_index = 0; action_index < num_actions; ++action_index) {
380 const FileAction *const action =
381 launch_info.GetFileActionAtIndex(action_index);
382 if (!action)
383 continue;
384
385 error = CreatePosixSpawnFileAction(*action, &file_actions);
386 if (!error.Success()) {
387 if (log)
388 log->Printf("%s(): error converting FileAction to posix_spawn "
389 "file action: %s",
390 __FUNCTION__, error.AsCString());
391 return error;
392 }
393 }
394
395 // TODO: Verify if we can set the working directory back immediately
396 // after the posix_spawnp call without creating a race condition???
397 const char *const working_directory =
398 launch_info.GetWorkingDirectory().GetCString();
399 if (working_directory && working_directory[0])
400 ::chdir(working_directory);
401
402 auto argv = launch_info.GetArguments().GetArgumentVector();
403 auto envp = launch_info.GetEnvironmentEntries().GetArgumentVector();
404 error_code = ::posix_spawnp(pid, path, &file_actions, &attr,
405 (char *const *)argv, (char *const *)envp);
406 if (error_code != 0) {
Pavel Labath10c41f32017-06-06 14:06:17 +0000407 LLDB_LOG(log,
408 "::posix_spawnp(pid => {0}, path = '{1}', file_actions "
409 "= {2}, attr = {3}, argv = {4}, envp = {5}) failed: {6}",
410 pid, path, &file_actions, &attr, argv, envp,
411 llvm::sys::StrError(error_code));
Kate Stoneb9c1b512016-09-06 20:57:50 +0000412 error.SetError(error_code, eErrorTypePOSIX);
413 return error;
414 }
415
416 // Validate we got a pid.
417 if (pid == LLDB_INVALID_PROCESS_ID) {
418 error.SetErrorString("posix_spawn() did not indicate a failure but it "
419 "failed to return a pid, aborting.");
420 return error;
421 }
422
423 if (actual_cpu_type) {
424 *actual_cpu_type = GetCPUTypeForLocalProcess(*pid);
425 if (log)
426 log->Printf("%s(): cpu type for launched process pid=%i: "
427 "cpu_type=0x%8.8x",
428 __FUNCTION__, *pid, *actual_cpu_type);
429 }
430
431 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000432}
433
Zachary Turner97206d52017-05-12 04:51:55 +0000434Status LaunchInferior(ProcessLaunchInfo &launch_info, int *pty_master_fd,
435 LaunchFlavor *launch_flavor) {
436 Status error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000437 Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
Todd Fialae77fce02016-09-04 00:18:56 +0000438
Kate Stoneb9c1b512016-09-06 20:57:50 +0000439 if (!launch_flavor) {
440 error.SetErrorString("mandatory launch_flavor field was null");
441 return error;
442 }
Todd Fialae77fce02016-09-04 00:18:56 +0000443
Kate Stoneb9c1b512016-09-06 20:57:50 +0000444 if (log) {
445 StreamString stream;
446 stream.Printf("NativeProcessDarwin::%s(): launching with the "
447 "following launch info:",
448 __FUNCTION__);
449 launch_info.Dump(stream, nullptr);
450 stream.Flush();
451 log->PutCString(stream.GetString().c_str());
452 }
Todd Fialae77fce02016-09-04 00:18:56 +0000453
Kate Stoneb9c1b512016-09-06 20:57:50 +0000454 // Retrieve the binary name given to us.
455 char given_path[PATH_MAX];
456 given_path[0] = '\0';
457 launch_info.GetExecutableFile().GetPath(given_path, sizeof(given_path));
Todd Fialae77fce02016-09-04 00:18:56 +0000458
Kate Stoneb9c1b512016-09-06 20:57:50 +0000459 // Determine the manner in which we'll launch.
460 *launch_flavor = g_launch_flavor;
461 if (*launch_flavor == LaunchFlavor::Default) {
462 // Our default launch method is posix spawn
463 *launch_flavor = LaunchFlavor::PosixSpawn;
Todd Fialae77fce02016-09-04 00:18:56 +0000464#if defined WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000465 // Check if we have an app bundle, if so launch using BackBoard Services.
466 if (strstr(given_path, ".app")) {
467 *launch_flavor = eLaunchFlavorFBS;
468 }
Todd Fialae77fce02016-09-04 00:18:56 +0000469#elif defined WITH_BKS
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 = eLaunchFlavorBKS;
473 }
Todd Fialae77fce02016-09-04 00:18:56 +0000474#elif defined WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000475 // Check if we have an app bundle, if so launch using SpringBoard.
476 if (strstr(given_path, ".app")) {
477 *launch_flavor = eLaunchFlavorSpringBoard;
478 }
Todd Fialae77fce02016-09-04 00:18:56 +0000479#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000480 }
Todd Fialae77fce02016-09-04 00:18:56 +0000481
Kate Stoneb9c1b512016-09-06 20:57:50 +0000482 // Attempt to resolve the binary name to an absolute path.
483 char resolved_path[PATH_MAX];
484 resolved_path[0] = '\0';
Todd Fialae77fce02016-09-04 00:18:56 +0000485
Kate Stoneb9c1b512016-09-06 20:57:50 +0000486 if (log)
487 log->Printf("%s(): attempting to resolve given binary path: \"%s\"",
488 __FUNCTION__, given_path);
489
490 // If we fail to resolve the path to our executable, then just use what we
491 // were given and hope for the best
492 if (!ResolveExecutablePath(given_path, resolved_path,
493 sizeof(resolved_path))) {
Todd Fialae77fce02016-09-04 00:18:56 +0000494 if (log)
Kate Stoneb9c1b512016-09-06 20:57:50 +0000495 log->Printf("%s(): failed to resolve binary path, using "
496 "what was given verbatim and hoping for the best",
497 __FUNCTION__);
498 ::strncpy(resolved_path, given_path, sizeof(resolved_path));
499 } else {
500 if (log)
501 log->Printf("%s(): resolved given binary path to: \"%s\"", __FUNCTION__,
502 resolved_path);
503 }
Todd Fialae77fce02016-09-04 00:18:56 +0000504
Kate Stoneb9c1b512016-09-06 20:57:50 +0000505 char launch_err_str[PATH_MAX];
506 launch_err_str[0] = '\0';
507
508 // TODO figure out how to handle QSetProcessEvent
509 // const char *process_event = ctx.GetProcessEvent();
510
511 // Ensure the binary is there.
512 struct stat path_stat;
513 if (::stat(resolved_path, &path_stat) == -1) {
514 error.SetErrorToErrno();
515 return error;
516 }
517
518 // Fork a child process for debugging
519 // state_callback(eStateLaunching);
520
521 const auto argv = launch_info.GetArguments().GetConstArgumentVector();
522 const auto envp =
523 launch_info.GetEnvironmentEntries().GetConstArgumentVector();
524
525 switch (*launch_flavor) {
526 case LaunchFlavor::ForkExec: {
527 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
528 error = ForkChildForPTraceDebugging(resolved_path, argv, envp, &pid,
529 pty_master_fd);
530 if (error.Success()) {
531 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
532 } else {
Adrian Prantl05097242018-04-30 16:49:04 +0000533 // Reset any variables that might have been set during a failed launch
534 // attempt.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000535 if (pty_master_fd)
536 *pty_master_fd = -1;
537
538 // We're done.
539 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000540 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000541 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000542
543#ifdef WITH_FBS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000544 case LaunchFlavor::FBS: {
545 const char *app_ext = strstr(path, ".app");
546 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
547 std::string app_bundle_path(path, app_ext + strlen(".app"));
548 m_flags |= eMachProcessFlagsUsingFBS;
549 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
550 no_stdio, disable_aslr, event_data,
551 launch_err) != 0)
552 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
553 // non-zero m_pid.
554 else
555 break; // We tried a FBS launch, but didn't succeed lets get out
556 }
557 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000558#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000559
Todd Fialae77fce02016-09-04 00:18:56 +0000560#ifdef WITH_BKS
Kate Stoneb9c1b512016-09-06 20:57:50 +0000561 case LaunchFlavor::BKS: {
562 const char *app_ext = strstr(path, ".app");
563 if (app_ext && (app_ext[4] == '\0' || app_ext[4] == '/')) {
564 std::string app_bundle_path(path, app_ext + strlen(".app"));
565 m_flags |= eMachProcessFlagsUsingBKS;
566 if (BoardServiceLaunchForDebug(app_bundle_path.c_str(), argv, envp,
567 no_stdio, disable_aslr, event_data,
568 launch_err) != 0)
569 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
570 // non-zero m_pid.
571 else
572 break; // We tried a BKS launch, but didn't succeed lets get out
573 }
574 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000575#endif
Kate Stoneb9c1b512016-09-06 20:57:50 +0000576
Todd Fialae77fce02016-09-04 00:18:56 +0000577#ifdef WITH_SPRINGBOARD
Kate Stoneb9c1b512016-09-06 20:57:50 +0000578 case LaunchFlavor::SpringBoard: {
579 // .../whatever.app/whatever ?
580 // Or .../com.apple.whatever.app/whatever -- be careful of ".app" in
581 // "com.apple.whatever" here
582 const char *app_ext = strstr(path, ".app/");
583 if (app_ext == NULL) {
584 // .../whatever.app ?
585 int len = strlen(path);
586 if (len > 5) {
587 if (strcmp(path + len - 4, ".app") == 0) {
588 app_ext = path + len - 4;
Todd Fialae77fce02016-09-04 00:18:56 +0000589 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000590 }
591 }
592 if (app_ext) {
593 std::string app_bundle_path(path, app_ext + strlen(".app"));
594 if (SBLaunchForDebug(app_bundle_path.c_str(), argv, envp, no_stdio,
595 disable_aslr, launch_err) != 0)
596 return m_pid; // A successful SBLaunchForDebug() returns and assigns a
597 // non-zero m_pid.
598 else
599 break; // We tried a springboard launch, but didn't succeed lets get out
600 }
601 } break;
Todd Fialae77fce02016-09-04 00:18:56 +0000602#endif
Todd Fialae77fce02016-09-04 00:18:56 +0000603
Kate Stoneb9c1b512016-09-06 20:57:50 +0000604 case LaunchFlavor::PosixSpawn: {
605 ::pid_t pid = LLDB_INVALID_PROCESS_ID;
Todd Fialae77fce02016-09-04 00:18:56 +0000606
Kate Stoneb9c1b512016-09-06 20:57:50 +0000607 // Retrieve paths for stdin/stdout/stderr.
608 cpu_type_t actual_cpu_type = 0;
609 error = PosixSpawnChildForPTraceDebugging(resolved_path, launch_info, &pid,
610 &actual_cpu_type);
611 if (error.Success()) {
612 launch_info.SetProcessID(static_cast<lldb::pid_t>(pid));
613 if (pty_master_fd)
614 *pty_master_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor();
615 } else {
Adrian Prantl05097242018-04-30 16:49:04 +0000616 // Reset any variables that might have been set during a failed launch
617 // attempt.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000618 if (pty_master_fd)
619 *pty_master_fd = -1;
620
621 // We're done.
622 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000623 }
Kate Stoneb9c1b512016-09-06 20:57:50 +0000624 break;
625 }
Todd Fialae77fce02016-09-04 00:18:56 +0000626
Kate Stoneb9c1b512016-09-06 20:57:50 +0000627 default:
628 // Invalid launch flavor.
629 error.SetErrorStringWithFormat("NativeProcessDarwin::%s(): unknown "
630 "launch flavor %d",
631 __FUNCTION__, (int)*launch_flavor);
Todd Fialae77fce02016-09-04 00:18:56 +0000632 return error;
Kate Stoneb9c1b512016-09-06 20:57:50 +0000633 }
634
635 if (launch_info.GetProcessID() == LLDB_INVALID_PROCESS_ID) {
Adrian Prantl05097242018-04-30 16:49:04 +0000636 // If we don't have a valid process ID and no one has set the error, then
637 // return a generic error.
Kate Stoneb9c1b512016-09-06 20:57:50 +0000638 if (error.Success())
639 error.SetErrorStringWithFormat("%s(): failed to launch, no reason "
640 "specified",
641 __FUNCTION__);
642 }
643
644 // We're done with the launch side of the operation.
645 return error;
Todd Fialae77fce02016-09-04 00:18:56 +0000646}
Kate Stoneb9c1b512016-09-06 20:57:50 +0000647}
648} // namespaces