lldb_private::Status PlatformAppleSimulator::LaunchProcess( lldb_private::ProcessLaunchInfo &launch_info) { #if defined(__APPLE__) LoadCoreSimulator(); CoreSimulatorSupport::Device device(GetSimulatorDevice()); if (device.GetState() != CoreSimulatorSupport::Device::State::Booted) { Status boot_err; device.Boot(boot_err); if (boot_err.Fail()) return boot_err; } auto spawned = device.Spawn(launch_info); if (spawned) { launch_info.SetProcessID(spawned.GetPID()); return Status(); } else return spawned.GetError(); #else Status err; err.SetErrorString(UNSUPPORTED_ERROR); return err; #endif }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *hostname, uint16_t in_port, lldb_private::ProcessLaunchInfo &launch_info, uint16_t &out_port) { out_port = in_port; Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) debugserver_file_spec.SetFile (env_debugserver_path, false); else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources // directory. if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { g_debugserver_file_spec = debugserver_file_spec; } else { g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); // If a host and port is supplied then use it char host_and_port[128]; if (hostname) { snprintf (host_and_port, sizeof(host_and_port), "%s:%u", hostname, in_port); debugserver_args.AppendArgument(host_and_port); } else { host_and_port[0] = '\0'; } // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); char named_pipe_path[PATH_MAX]; named_pipe_path[0] = '\0'; bool listen = false; if (host_and_port[0]) { // Create a temporary file to get the stdout/stderr and redirect the // output of the command into this file. We will later read this file // if all goes well and fill the data into "command_output_ptr" if (in_port == 0) { // Binding to port zero, we need to figure out what port it ends up // using using a named pipe... FileSpec tmpdir_file_spec; if (Host::GetLLDBPath (ePathTypeLLDBTempSystemDir, tmpdir_file_spec)) { tmpdir_file_spec.GetFilename().SetCString("debugserver-named-pipe.XXXXXX"); strncpy(named_pipe_path, tmpdir_file_spec.GetPath().c_str(), sizeof(named_pipe_path)); } else { strncpy(named_pipe_path, "/tmp/debugserver-named-pipe.XXXXXX", sizeof(named_pipe_path)); } if (::mktemp (named_pipe_path)) { if (::mkfifo(named_pipe_path, 0600) == 0) { debugserver_args.AppendArgument("--named-pipe"); debugserver_args.AppendArgument(named_pipe_path); } } } else { listen = true; } } else { // No host and port given, so lets listen on our end and make the debugserver // connect to us.. error = StartListenThread ("localhost", 0); if (error.Fail()) return error; ConnectionFileDescriptor *connection = (ConnectionFileDescriptor *)GetConnection (); out_port = connection->GetBoundPort(3); assert (out_port != 0); char port_cstr[32]; snprintf(port_cstr, sizeof(port_cstr), "localhost:%i", out_port); // Send the host and port down that debugserver and specify an option // so that it connects back to the port we are listening to in this process debugserver_args.AppendArgument("--reverse-connect"); debugserver_args.AppendArgument(port_cstr); } const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); debugserver_args.AppendArgument(arg_cstr); } const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. launch_info.AppendCloseFileAction (STDIN_FILENO); launch_info.AppendCloseFileAction (STDOUT_FILENO); launch_info.AppendCloseFileAction (STDERR_FILENO); error = Host::LaunchProcess(launch_info); if (named_pipe_path[0]) { File name_pipe_file; error = name_pipe_file.Open(named_pipe_path, File::eOpenOptionRead); if (error.Success()) { char port_cstr[256]; port_cstr[0] = '\0'; size_t num_bytes = sizeof(port_cstr); error = name_pipe_file.Read(port_cstr, num_bytes); assert (error.Success()); assert (num_bytes > 0 && port_cstr[num_bytes-1] == '\0'); out_port = Args::StringToUInt32(port_cstr, 0); name_pipe_file.Close(); } Host::Unlink(named_pipe_path); } else if (listen) { } else { // Make sure we actually connect with the debugserver... JoinListenThread(); } } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
Error GDBRemoteCommunication::StartDebugserverProcess (const char *debugserver_url, const char *unix_socket_name, // For handshaking lldb_private::ProcessLaunchInfo &launch_info) { Error error; // If we locate debugserver, keep that located version around static FileSpec g_debugserver_file_spec; // This function will fill in the launch information for the debugserver // instance that gets launched. launch_info.Clear(); char debugserver_path[PATH_MAX]; FileSpec &debugserver_file_spec = launch_info.GetExecutableFile(); // Always check to see if we have an environment override for the path // to the debugserver to use and use it if we do. const char *env_debugserver_path = getenv("LLDB_DEBUGSERVER_PATH"); if (env_debugserver_path) debugserver_file_spec.SetFile (env_debugserver_path, false); else debugserver_file_spec = g_debugserver_file_spec; bool debugserver_exists = debugserver_file_spec.Exists(); if (!debugserver_exists) { // The debugserver binary is in the LLDB.framework/Resources // directory. if (Host::GetLLDBPath (ePathTypeSupportExecutableDir, debugserver_file_spec)) { debugserver_file_spec.GetFilename().SetCString(DEBUGSERVER_BASENAME); debugserver_exists = debugserver_file_spec.Exists(); if (debugserver_exists) { g_debugserver_file_spec = debugserver_file_spec; } else { g_debugserver_file_spec.Clear(); debugserver_file_spec.Clear(); } } } if (debugserver_exists) { debugserver_file_spec.GetPath (debugserver_path, sizeof(debugserver_path)); Args &debugserver_args = launch_info.GetArguments(); debugserver_args.Clear(); char arg_cstr[PATH_MAX]; // Start args with "debugserver /file/path -r --" debugserver_args.AppendArgument(debugserver_path); debugserver_args.AppendArgument(debugserver_url); // use native registers, not the GDB registers debugserver_args.AppendArgument("--native-regs"); // make debugserver run in its own session so signals generated by // special terminal key sequences (^C) don't affect debugserver debugserver_args.AppendArgument("--setsid"); if (unix_socket_name && unix_socket_name[0]) { debugserver_args.AppendArgument("--unix-socket"); debugserver_args.AppendArgument(unix_socket_name); } const char *env_debugserver_log_file = getenv("LLDB_DEBUGSERVER_LOG_FILE"); if (env_debugserver_log_file) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-file=%s", env_debugserver_log_file); debugserver_args.AppendArgument(arg_cstr); } const char *env_debugserver_log_flags = getenv("LLDB_DEBUGSERVER_LOG_FLAGS"); if (env_debugserver_log_flags) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--log-flags=%s", env_debugserver_log_flags); debugserver_args.AppendArgument(arg_cstr); } // debugserver_args.AppendArgument("--log-file=/tmp/debugserver.txt"); // debugserver_args.AppendArgument("--log-flags=0x802e0e"); // We currently send down all arguments, attach pids, or attach // process names in dedicated GDB server packets, so we don't need // to pass them as arguments. This is currently because of all the // things we need to setup prior to launching: the environment, // current working dir, file actions, etc. #if 0 // Now append the program arguments if (inferior_argv) { // Terminate the debugserver args so we can now append the inferior args debugserver_args.AppendArgument("--"); for (int i = 0; inferior_argv[i] != NULL; ++i) debugserver_args.AppendArgument (inferior_argv[i]); } else if (attach_pid != LLDB_INVALID_PROCESS_ID) { ::snprintf (arg_cstr, sizeof(arg_cstr), "--attach=%u", attach_pid); debugserver_args.AppendArgument (arg_cstr); } else if (attach_name && attach_name[0]) { if (wait_for_launch) debugserver_args.AppendArgument ("--waitfor"); else debugserver_args.AppendArgument ("--attach"); debugserver_args.AppendArgument (attach_name); } #endif // Close STDIN, STDOUT and STDERR. We might need to redirect them // to "/dev/null" if we run into any problems. // launch_info.AppendCloseFileAction (STDIN_FILENO); // launch_info.AppendCloseFileAction (STDOUT_FILENO); // launch_info.AppendCloseFileAction (STDERR_FILENO); error = Host::LaunchProcess(launch_info); } else { error.SetErrorStringWithFormat ("unable to locate " DEBUGSERVER_BASENAME ); } return error; }
lldb::ProcessSP PlatformRemoteGDBServer::DebugProcess (lldb_private::ProcessLaunchInfo &launch_info, lldb_private::Debugger &debugger, lldb_private::Target *target, // Can be NULL, if NULL create a new target, else use existing one lldb_private::Error &error) { lldb::ProcessSP process_sp; if (IsRemote()) { if (IsConnected()) { lldb::pid_t debugserver_pid = LLDB_INVALID_PROCESS_ID; ArchSpec remote_arch = GetRemoteSystemArchitecture(); llvm::Triple &remote_triple = remote_arch.GetTriple(); uint16_t port = 0; if (remote_triple.getVendor() == llvm::Triple::Apple && remote_triple.getOS() == llvm::Triple::IOS) { // When remote debugging to iOS, we use a USB mux that always talks // to localhost, so we will need the remote debugserver to accept connections // only from localhost, no matter what our current hostname is port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, "127.0.0.1"); } else { // All other hosts should use their actual hostname port = m_gdb_client.LaunchGDBserverAndGetPort(debugserver_pid, NULL); } if (port == 0) { error.SetErrorStringWithFormat ("unable to launch a GDB server on '%s'", GetHostname ()); } else { if (target == NULL) { TargetSP new_target_sp; error = debugger.GetTargetList().CreateTarget (debugger, NULL, NULL, false, NULL, new_target_sp); target = new_target_sp.get(); } else error.Clear(); if (target && error.Success()) { debugger.GetTargetList().SetSelectedTarget(target); // The darwin always currently uses the GDB remote debugger plug-in // so even when debugging locally we are debugging remotely! process_sp = target->CreateProcess (launch_info.GetListenerForProcess(debugger), "gdb-remote", NULL); if (process_sp) { char connect_url[256]; const char *override_hostname = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_HOSTNAME"); const char *port_offset_c_str = getenv("LLDB_PLATFORM_REMOTE_GDB_SERVER_PORT_OFFSET"); int port_offset = port_offset_c_str ? ::atoi(port_offset_c_str) : 0; const int connect_url_len = ::snprintf (connect_url, sizeof(connect_url), "connect://%s:%u", override_hostname ? override_hostname : GetHostname (), port + port_offset); assert (connect_url_len < (int)sizeof(connect_url)); error = process_sp->ConnectRemote (NULL, connect_url); // Retry the connect remote one time... if (error.Fail()) error = process_sp->ConnectRemote (NULL, connect_url); if (error.Success()) error = process_sp->Launch(launch_info); else if (debugserver_pid != LLDB_INVALID_PROCESS_ID) { printf ("error: connect remote failed (%s)\n", error.AsCString()); m_gdb_client.KillSpawnedProcess(debugserver_pid); } } } } } else { error.SetErrorString("not connected to remote gdb server"); } } return process_sp; }