diff options
Diffstat (limited to 'lldb/source/Plugins')
4 files changed, 35 insertions, 253 deletions
diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp index b3842302c6d..ae32a777773 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.cpp @@ -29,9 +29,11 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/State.h" #include "lldb/Host/Host.h" +#include "lldb/Host/HostProcess.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/Host/common/NativeRegisterContext.h" +#include "lldb/Host/linux/ProcessLauncherLinux.h" #include "lldb/Symbol/ObjectFile.h" #include "lldb/Target/Process.h" #include "lldb/Target/ProcessLaunchInfo.h" @@ -60,8 +62,6 @@ #include "lldb/Host/linux/Uio.h" #include "lldb/Host/android/Android.h" -#define LLDB_PERSONALITY_GET_CURRENT_SETTINGS 0xffffffff - // Support hardware breakpoints in case it has not been defined #ifndef TRAP_HWBKPT #define TRAP_HWBKPT 4 @@ -130,37 +130,6 @@ ResolveProcessArchitecture(lldb::pid_t pid, ArchSpec &arch) return Error("failed to retrieve a valid architecture from the exe module"); } -// Used to notify the parent about which part of the launch sequence failed. -enum LaunchCallSpecifier -{ - ePtraceFailed, - eDupStdinFailed, - eDupStdoutFailed, - eDupStderrFailed, - eChdirFailed, - eExecFailed, - eSetGidFailed, - eSetSigMaskFailed, - eLaunchCallMax = eSetSigMaskFailed -}; - -static uint8_t LLVM_ATTRIBUTE_NORETURN -ExitChildAbnormally(LaunchCallSpecifier spec) -{ - static_assert(eLaunchCallMax < 0x8, "Have more launch calls than we are able to represent"); - // This may truncate the topmost bits of the errno because the exit code is only 8 bits wide. - // However, it should still give us a pretty good indication of what went wrong. (And the - // most common errors have small numbers anyway). - _exit(unsigned(spec) | (errno << 3)); -} - -// The second member is the errno (or its 5 lowermost bits anyway). -inline std::pair<LaunchCallSpecifier, uint8_t> -DecodeChildExitCode(int exit_code) -{ - return std::make_pair(LaunchCallSpecifier(exit_code & 0x7), exit_code >> 3); -} - void MaybeLogLaunchInfo(const ProcessLaunchInfo &info) { @@ -411,101 +380,6 @@ NativeProcessLinux::AttachToInferior (MainLoop &mainloop, lldb::pid_t pid, Error Attach(pid, error); } -void -NativeProcessLinux::ChildFunc(const ProcessLaunchInfo &info) -{ - // Start tracing this child that is about to exec. - if (ptrace(PTRACE_TRACEME, 0, nullptr, nullptr) == -1) - ExitChildAbnormally(ePtraceFailed); - - // Do not inherit setgid powers. - if (setgid(getgid()) != 0) - ExitChildAbnormally(eSetGidFailed); - - // Attempt to have our own process group. - if (setpgid(0, 0) != 0) - { - // FIXME log that this failed. This is common. - // Don't allow this to prevent an inferior exec. - } - - // Dup file descriptors if needed. - if (const FileAction *action = info.GetFileActionForFD(STDIN_FILENO)) - if (!DupDescriptor(action->GetFileSpec(), STDIN_FILENO, O_RDONLY)) - ExitChildAbnormally(eDupStdinFailed); - - if (const FileAction *action = info.GetFileActionForFD(STDOUT_FILENO)) - if (!DupDescriptor(action->GetFileSpec(), STDOUT_FILENO, O_WRONLY | O_CREAT | O_TRUNC)) - ExitChildAbnormally(eDupStdoutFailed); - - if (const FileAction *action = info.GetFileActionForFD(STDERR_FILENO)) - if (!DupDescriptor(action->GetFileSpec(), STDERR_FILENO, O_WRONLY | O_CREAT | O_TRUNC)) - ExitChildAbnormally(eDupStderrFailed); - - // Close everything besides stdin, stdout, and stderr that has no file - // action to avoid leaking - for (int fd = 3; fd < sysconf(_SC_OPEN_MAX); ++fd) - if (!info.GetFileActionForFD(fd)) - close(fd); - - // Change working directory - if (info.GetWorkingDirectory() && 0 != ::chdir(info.GetWorkingDirectory().GetCString())) - ExitChildAbnormally(eChdirFailed); - - // Disable ASLR if requested. - if (info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)) - { - const int old_personality = personality(LLDB_PERSONALITY_GET_CURRENT_SETTINGS); - if (old_personality == -1) - { - // Can't retrieve Linux personality. Cannot disable ASLR. - } - else - { - const int new_personality = personality(ADDR_NO_RANDOMIZE | old_personality); - if (new_personality == -1) - { - // Disabling ASLR failed. - } - else - { - // Disabling ASLR succeeded. - } - } - } - - // Clear the signal mask to prevent the child from being affected by - // any masking done by the parent. - sigset_t set; - if (sigemptyset(&set) != 0 || pthread_sigmask(SIG_SETMASK, &set, nullptr) != 0) - ExitChildAbnormally(eSetSigMaskFailed); - - const char **argv = info.GetArguments().GetConstArgumentVector(); - - // Propagate the environment if one is not supplied. - const char **envp = info.GetEnvironmentEntries().GetConstArgumentVector(); - if (envp == NULL || envp[0] == NULL) - envp = const_cast<const char **>(environ); - - // Execute. We should never return... - execve(argv[0], const_cast<char *const *>(argv), const_cast<char *const *>(envp)); - - if (errno == ETXTBSY) - { - // On android M and earlier we can get this error because the adb deamon can hold a write - // handle on the executable even after it has finished uploading it. This state lasts - // only a short time and happens only when there are many concurrent adb commands being - // issued, such as when running the test suite. (The file remains open when someone does - // an "adb shell" command in the fork() child before it has had a chance to exec.) Since - // this state should clear up quickly, wait a while and then give it one more go. - usleep(50000); - execve(argv[0], const_cast<char *const *>(argv), const_cast<char *const *>(envp)); - } - - // ...unless exec fails. In which case we definitely need to end the child here. - ExitChildAbnormally(eExecFailed); -} - Error NativeProcessLinux::LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch_info) { @@ -516,34 +390,11 @@ NativeProcessLinux::LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch SetState(eStateLaunching); - lldb_utility::PseudoTerminal terminal; - const size_t err_len = 1024; - char err_str[err_len]; - lldb::pid_t pid; - MaybeLogLaunchInfo(launch_info); - if ((pid = terminal.Fork(err_str, err_len)) == static_cast<lldb::pid_t> (-1)) - { - error.SetErrorToGenericError(); - error.SetErrorStringWithFormat("Process fork failed: %s", err_str); + ::pid_t pid = ProcessLauncherLinux().LaunchProcess(launch_info, error).GetProcessId(); + if (error.Fail()) return error; - } - - // Child process. - if (pid == 0) - { - // First, make sure we disable all logging. If we are logging to stdout, our logs can be - // mistaken for inferior output. - Log::DisableAllLogChannels(nullptr); - - // terminal has already dupped the tty descriptors to stdin/out/err. - // This closes original fd from which they were copied (and avoids - // leaking descriptors to the debugged process. - terminal.CloseSlaveFileDescriptor(); - - ChildFunc(launch_info); - } Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); @@ -563,53 +414,6 @@ NativeProcessLinux::LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch return error; } - else if (WIFEXITED(status)) - { - auto p = DecodeChildExitCode(WEXITSTATUS(status)); - Error child_error(p.second, eErrorTypePOSIX); - const char *failure_reason; - switch (p.first) - { - case ePtraceFailed: - failure_reason = "Child ptrace failed"; - break; - case eDupStdinFailed: - failure_reason = "Child open stdin failed"; - break; - case eDupStdoutFailed: - failure_reason = "Child open stdout failed"; - break; - case eDupStderrFailed: - failure_reason = "Child open stderr failed"; - break; - case eChdirFailed: - failure_reason = "Child failed to set working directory"; - break; - case eExecFailed: - failure_reason = "Child exec failed"; - break; - case eSetGidFailed: - failure_reason = "Child setgid failed"; - break; - case eSetSigMaskFailed: - failure_reason = "Child failed to set signal mask"; - break; - } - error.SetErrorStringWithFormat("%s: %d - %s (error code truncated)", failure_reason, child_error.GetError(), child_error.AsCString()); - - if (log) - { - log->Printf ("NativeProcessLinux::%s inferior exited with status %d before issuing a STOP", - __FUNCTION__, - WEXITSTATUS(status)); - } - - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. - SetState (StateType::eStateInvalid); - - return error; - } assert(WIFSTOPPED(status) && (wpid == static_cast< ::pid_t> (pid)) && "Could not sync with inferior process."); @@ -632,29 +436,30 @@ NativeProcessLinux::LaunchInferior(MainLoop &mainloop, ProcessLaunchInfo &launch // Release the master terminal descriptor and pass it off to the // NativeProcessLinux instance. Similarly stash the inferior pid. - m_terminal_fd = terminal.ReleaseMasterFileDescriptor(); + m_terminal_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); m_pid = pid; launch_info.SetProcessID(pid); - // Set the terminal fd to be in non blocking mode (it simplifies the - // implementation of ProcessLinux::GetSTDOUT to have a non-blocking - // descriptor to read from). - error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); - if (error.Fail()) + if (m_terminal_fd != -1) { - if (log) - log->Printf ("NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s", - __FUNCTION__, error.AsCString ()); + error = EnsureFDFlags(m_terminal_fd, O_NONBLOCK); + if (error.Fail()) + { + if (log) + log->Printf( + "NativeProcessLinux::%s inferior EnsureFDFlags failed for ensuring terminal O_NONBLOCK setting: %s", + __FUNCTION__, error.AsCString()); - // Mark the inferior as invalid. - // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. - SetState (StateType::eStateInvalid); + // Mark the inferior as invalid. + // FIXME this could really use a new state - eStateLaunchFailure. For now, using eStateInvalid. + SetState(StateType::eStateInvalid); - return error; + return error; + } } if (log) - log->Printf ("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, pid); + log->Printf("NativeProcessLinux::%s() adding pid = %" PRIu64, __FUNCTION__, uint64_t(pid)); ResolveProcessArchitecture(m_pid, m_arch); NativeThreadLinuxSP thread_sp = AddThread(pid); @@ -2516,20 +2321,6 @@ NativeProcessLinux::Detach(lldb::tid_t tid) } bool -NativeProcessLinux::DupDescriptor(const FileSpec &file_spec, int fd, int flags) -{ - int target_fd = open(file_spec.GetCString(), flags, 0666); - - if (target_fd == -1) - return false; - - if (dup2(target_fd, fd) == -1) - return false; - - return (close(target_fd) == -1) ? false : true; -} - -bool NativeProcessLinux::HasThreadNoLock (lldb::tid_t thread_id) { for (auto thread_sp : m_threads) diff --git a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h index d5be06f0cb5..7b1fcd81b4b 100644 --- a/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h +++ b/lldb/source/Plugins/Process/Linux/NativeProcessLinux.h @@ -166,15 +166,9 @@ namespace process_linux { ::pid_t Attach(lldb::pid_t pid, Error &error); - static void - ChildFunc(const ProcessLaunchInfo &launch_info) LLVM_ATTRIBUTE_NORETURN; - static Error SetDefaultPtraceOpts(const lldb::pid_t); - static bool - DupDescriptor(const FileSpec &file_spec, int fd, int flags); - static void * MonitorThread(void *baton); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp index 7f876fb393d..7095815f0f0 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerCommon.cpp @@ -884,8 +884,8 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDIN (StringExtractorGDBRemote & FileAction file_action; std::string path; packet.GetHexByteString(path); - const bool read = false; - const bool write = true; + const bool read = true; + const bool write = false; if (file_action.Open(STDIN_FILENO, FileSpec{path, false}, read, write)) { m_process_launch_info.AppendFileAction(file_action); @@ -901,8 +901,8 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDOUT (StringExtractorGDBRemote FileAction file_action; std::string path; packet.GetHexByteString(path); - const bool read = true; - const bool write = false; + const bool read = false; + const bool write = true; if (file_action.Open(STDOUT_FILENO, FileSpec{path, false}, read, write)) { m_process_launch_info.AppendFileAction(file_action); @@ -918,8 +918,8 @@ GDBRemoteCommunicationServerCommon::Handle_QSetSTDERR (StringExtractorGDBRemote FileAction file_action; std::string path; packet.GetHexByteString(path); - const bool read = true; - const bool write = false; + const bool read = false; + const bool write = true; if (file_action.Open(STDERR_FILENO, FileSpec{path, false}, read, write)) { m_process_launch_info.AppendFileAction(file_action); diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index fc6b31ec088..ede69769c79 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -203,6 +203,15 @@ GDBRemoteCommunicationServerLLGS::LaunchProcess () if (!m_process_launch_info.GetArguments ().GetArgumentCount ()) return Error ("%s: no process command line specified to launch", __FUNCTION__); + const bool should_forward_stdio = m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || + m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr; + m_process_launch_info.SetLaunchInSeparateProcessGroup(true); + m_process_launch_info.GetFlags().Set(eLaunchFlagDebug); + + const bool default_to_use_pty = true; + m_process_launch_info.FinalizeFileActions(nullptr, default_to_use_pty); + Error error; { std::lock_guard<std::recursive_mutex> guard(m_debugged_process_mutex); @@ -226,11 +235,7 @@ GDBRemoteCommunicationServerLLGS::LaunchProcess () // file actions non-null // process launch -i/e/o will also make these file actions non-null // nullptr means that the traffic is expected to flow over gdb-remote protocol - if ( - m_process_launch_info.GetFileActionForFD(STDIN_FILENO) == nullptr || - m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) == nullptr || - m_process_launch_info.GetFileActionForFD(STDERR_FILENO) == nullptr - ) + if (should_forward_stdio) { // nullptr means it's not redirected to file or pty (in case of LLGS local) // at least one of stdio will be transferred pty<->gdb-remote @@ -998,14 +1003,6 @@ GDBRemoteCommunicationServerLLGS::StartSTDIOForwarding() if (! m_stdio_communication.IsConnected()) return; - // llgs local-process debugging may specify PTY paths, which will make these - // file actions non-null - // process launch -e/o will also make these file actions non-null - // nullptr means that the traffic is expected to flow over gdb-remote protocol - if ( m_process_launch_info.GetFileActionForFD(STDOUT_FILENO) && - m_process_launch_info.GetFileActionForFD(STDERR_FILENO)) - return; - Error error; lldbassert(! m_stdio_handle_up); m_stdio_handle_up = m_mainloop.RegisterReadObject( |