Modified: lldb/trunk/source/Host/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/CMakeLists.txt?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Host/CMakeLists.txt (original) +++ lldb/trunk/source/Host/CMakeLists.txt Thu Feb 16 13:38:21 2017 @@ -27,6 +27,7 @@ add_host_subdirectory(common common/OptionParser.cpp common/PipeBase.cpp common/ProcessRunLock.cpp + common/PseudoTerminal.cpp common/Socket.cpp common/SocketAddress.cpp common/SoftwareBreakpoint.cpp
Added: lldb/trunk/source/Host/common/PseudoTerminal.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Host/common/PseudoTerminal.cpp?rev=295368&view=auto ============================================================================== --- lldb/trunk/source/Host/common/PseudoTerminal.cpp (added) +++ lldb/trunk/source/Host/common/PseudoTerminal.cpp Thu Feb 16 13:38:21 2017 @@ -0,0 +1,310 @@ +//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Host/PseudoTerminal.h" +#include "lldb/Host/Config.h" + +#include <errno.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#if defined(TIOCSCTTY) +#include <sys/ioctl.h> +#endif + +#include "lldb/Host/PosixApi.h" + +#if defined(__ANDROID__) +int posix_openpt(int flags); +#endif + +using namespace lldb_utility; + +//---------------------------------------------------------------------- +// PseudoTerminal constructor +//---------------------------------------------------------------------- +PseudoTerminal::PseudoTerminal() + : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} + +//---------------------------------------------------------------------- +// Destructor +// +// The destructor will close the master and slave file descriptors +// if they are valid and ownership has not been released using the +// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() +// member functions. +//---------------------------------------------------------------------- +PseudoTerminal::~PseudoTerminal() { + CloseMasterFileDescriptor(); + CloseSlaveFileDescriptor(); +} + +//---------------------------------------------------------------------- +// Close the master file descriptor if it is valid. +//---------------------------------------------------------------------- +void PseudoTerminal::CloseMasterFileDescriptor() { + if (m_master_fd >= 0) { + ::close(m_master_fd); + m_master_fd = invalid_fd; + } +} + +//---------------------------------------------------------------------- +// Close the slave file descriptor if it is valid. +//---------------------------------------------------------------------- +void PseudoTerminal::CloseSlaveFileDescriptor() { + if (m_slave_fd >= 0) { + ::close(m_slave_fd); + m_slave_fd = invalid_fd; + } +} + +//---------------------------------------------------------------------- +// Open the first available pseudo terminal with OFLAG as the +// permissions. The file descriptor is stored in this object and can +// be accessed with the MasterFileDescriptor() accessor. The +// ownership of the master file descriptor can be released using +// the ReleaseMasterFileDescriptor() accessor. If this object has +// a valid master files descriptor when its destructor is called, it +// will close the master file descriptor, therefore clients must +// call ReleaseMasterFileDescriptor() if they wish to use the master +// file descriptor after this object is out of scope or destroyed. +// +// RETURNS: +// True when successful, false indicating an error occurred. +//---------------------------------------------------------------------- +bool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str, + size_t error_len) { + if (error_str) + error_str[0] = '\0'; + +#if !defined(LLDB_DISABLE_POSIX) + // Open the master side of a pseudo terminal + m_master_fd = ::posix_openpt(oflag); + if (m_master_fd < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + return false; + } + + // Grant access to the slave pseudo terminal + if (::grantpt(m_master_fd) < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + CloseMasterFileDescriptor(); + return false; + } + + // Clear the lock flag on the slave pseudo terminal + if (::unlockpt(m_master_fd) < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + CloseMasterFileDescriptor(); + return false; + } + + return true; +#else + if (error_str) + ::snprintf(error_str, error_len, "%s", "pseudo terminal not supported"); + return false; +#endif +} + +//---------------------------------------------------------------------- +// Open the slave pseudo terminal for the current master pseudo +// terminal. A master pseudo terminal should already be valid prior to +// calling this function (see OpenFirstAvailableMaster()). +// The file descriptor is stored this object's member variables and can +// be accessed via the GetSlaveFileDescriptor(), or released using the +// ReleaseSlaveFileDescriptor() member function. +// +// RETURNS: +// True when successful, false indicating an error occurred. +//---------------------------------------------------------------------- +bool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) { + if (error_str) + error_str[0] = '\0'; + + CloseSlaveFileDescriptor(); + + // Open the master side of a pseudo terminal + const char *slave_name = GetSlaveName(error_str, error_len); + + if (slave_name == nullptr) + return false; + + m_slave_fd = ::open(slave_name, oflag); + + if (m_slave_fd < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + return false; + } + + return true; +} + +//---------------------------------------------------------------------- +// Get the name of the slave pseudo terminal. A master pseudo terminal +// should already be valid prior to calling this function (see +// OpenFirstAvailableMaster()). +// +// RETURNS: +// NULL if no valid master pseudo terminal or if ptsname() fails. +// The name of the slave pseudo terminal as a NULL terminated C string +// that comes from static memory, so a copy of the string should be +// made as subsequent calls can change this value. +//---------------------------------------------------------------------- +const char *PseudoTerminal::GetSlaveName(char *error_str, + size_t error_len) const { + if (error_str) + error_str[0] = '\0'; + + if (m_master_fd < 0) { + if (error_str) + ::snprintf(error_str, error_len, "%s", + "master file descriptor is invalid"); + return nullptr; + } + const char *slave_name = ::ptsname(m_master_fd); + + if (error_str && slave_name == nullptr) + ::strerror_r(errno, error_str, error_len); + + return slave_name; +} + +//---------------------------------------------------------------------- +// Fork a child process and have its stdio routed to a pseudo terminal. +// +// In the parent process when a valid pid is returned, the master file +// descriptor can be used as a read/write access to stdio of the +// child process. +// +// In the child process the stdin/stdout/stderr will already be routed +// to the slave pseudo terminal and the master file descriptor will be +// closed as it is no longer needed by the child process. +// +// This class will close the file descriptors for the master/slave +// when the destructor is called, so be sure to call +// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any +// file descriptors are going to be used past the lifespan of this +// object. +// +// RETURNS: +// in the parent process: the pid of the child, or -1 if fork fails +// in the child process: zero +//---------------------------------------------------------------------- +lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { + if (error_str) + error_str[0] = '\0'; + pid_t pid = LLDB_INVALID_PROCESS_ID; +#if !defined(LLDB_DISABLE_POSIX) + int flags = O_RDWR; + flags |= O_CLOEXEC; + if (OpenFirstAvailableMaster(flags, error_str, error_len)) { + // Successfully opened our master pseudo terminal + + pid = ::fork(); + if (pid < 0) { + // Fork failed + if (error_str) + ::strerror_r(errno, error_str, error_len); + } else if (pid == 0) { + // Child Process + ::setsid(); + + if (OpenSlave(O_RDWR, error_str, error_len)) { + // Successfully opened slave + + // Master FD should have O_CLOEXEC set, but let's close it just in + // case... + CloseMasterFileDescriptor(); + +#if defined(TIOCSCTTY) + // Acquire the controlling terminal + if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) { + if (error_str) + ::strerror_r(errno, error_str, error_len); + } +#endif + // Duplicate all stdio file descriptors to the slave pseudo terminal + if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) { + if (error_str && !error_str[0]) + ::strerror_r(errno, error_str, error_len); + } + + if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) { + if (error_str && !error_str[0]) + ::strerror_r(errno, error_str, error_len); + } + + if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) { + if (error_str && !error_str[0]) + ::strerror_r(errno, error_str, error_len); + } + } + } else { + // Parent Process + // Do nothing and let the pid get returned! + } + } +#endif + return pid; +} + +//---------------------------------------------------------------------- +// The master file descriptor accessor. This object retains ownership +// of the master file descriptor when this accessor is used. Use +// ReleaseMasterFileDescriptor() if you wish this object to release +// ownership of the master file descriptor. +// +// Returns the master file descriptor, or -1 if the master file +// descriptor is not currently valid. +//---------------------------------------------------------------------- +int PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; } + +//---------------------------------------------------------------------- +// The slave file descriptor accessor. +// +// Returns the slave file descriptor, or -1 if the slave file +// descriptor is not currently valid. +//---------------------------------------------------------------------- +int PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; } + +//---------------------------------------------------------------------- +// Release ownership of the master pseudo terminal file descriptor +// without closing it. The destructor for this class will close the +// master file descriptor if the ownership isn't released using this +// call and the master file descriptor has been opened. +//---------------------------------------------------------------------- +int PseudoTerminal::ReleaseMasterFileDescriptor() { + // Release ownership of the master pseudo terminal file + // descriptor without closing it. (the destructor for this + // class will close it otherwise!) + int fd = m_master_fd; + m_master_fd = invalid_fd; + return fd; +} + +//---------------------------------------------------------------------- +// Release ownership of the slave pseudo terminal file descriptor +// without closing it. The destructor for this class will close the +// slave file descriptor if the ownership isn't released using this +// call and the slave file descriptor has been opened. +//---------------------------------------------------------------------- +int PseudoTerminal::ReleaseSlaveFileDescriptor() { + // Release ownership of the slave pseudo terminal file + // descriptor without closing it (the destructor for this + // class will close it otherwise!) + int fd = m_slave_fd; + m_slave_fd = invalid_fd; + return fd; +} Modified: lldb/trunk/source/Interpreter/ScriptInterpreter.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Interpreter/ScriptInterpreter.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Interpreter/ScriptInterpreter.cpp (original) +++ lldb/trunk/source/Interpreter/ScriptInterpreter.cpp Thu Feb 16 13:38:21 2017 @@ -14,9 +14,9 @@ #include <string> #include "lldb/Core/StringList.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Interpreter/CommandReturnObject.h" #include "lldb/Utility/Error.h" -#include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/Stream.h" using namespace lldb; Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp (original) +++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformAppleSimulator.cpp Thu Feb 16 13:38:21 2017 @@ -19,10 +19,10 @@ #include <thread> // Other libraries and framework includes // Project includes +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Target/Process.h" #include "lldb/Utility/Error.h" #include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/StreamString.h" #include "llvm/Support/Threading.h" Modified: lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm (original) +++ lldb/trunk/source/Plugins/Platform/MacOSX/PlatformiOSSimulatorCoreSimulatorSupport.mm Thu Feb 16 13:38:21 2017 @@ -16,8 +16,8 @@ #include <CoreFoundation/CoreFoundation.h> #include <Foundation/Foundation.h> // Project includes +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Target/FileAction.h" -#include "lldb/Utility/PseudoTerminal.h" #include "llvm/ADT/StringRef.h" Modified: lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp (original) +++ lldb/trunk/source/Plugins/Process/Darwin/DarwinProcessLauncher.cpp Thu Feb 16 13:38:21 2017 @@ -31,9 +31,9 @@ #include "lldb/lldb-enumerations.h" #include "lldb/Core/Log.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Target/ProcessLaunchInfo.h" #include "lldb/Utility/Error.h" -#include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/StreamString.h" #include "CFBundle.h" Modified: lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp (original) +++ lldb/trunk/source/Plugins/Process/Darwin/NativeProcessDarwin.cpp Thu Feb 16 13:38:21 2017 @@ -21,8 +21,8 @@ // LLDB includes #include "lldb/Core/Log.h" #include "lldb/Core/State.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Target/ProcessLaunchInfo.h" -#include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/StreamString.h" #include "CFBundle.h" Modified: lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp (original) +++ lldb/trunk/source/Plugins/Process/FreeBSD/ProcessMonitor.cpp Thu Feb 16 13:38:21 2017 @@ -24,12 +24,12 @@ #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" #include "lldb/Host/Host.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Thread.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Error.h" -#include "lldb/Utility/PseudoTerminal.h" #include "FreeBSDThread.h" #include "Plugins/Process/POSIX/CrashReason.h" Modified: lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp (original) +++ lldb/trunk/source/Plugins/Process/Linux/NativeProcessLinux.cpp Thu Feb 16 13:38:21 2017 @@ -29,6 +29,7 @@ #include "lldb/Core/State.h" #include "lldb/Host/Host.h" #include "lldb/Host/HostProcess.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/ThreadLauncher.h" #include "lldb/Host/common/NativeBreakpoint.h" #include "lldb/Host/common/NativeRegisterContext.h" @@ -41,7 +42,6 @@ #include "lldb/Target/Target.h" #include "lldb/Utility/Error.h" #include "lldb/Utility/LLDBAssert.h" -#include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/StringExtractor.h" #include "NativeThreadLinux.h" Modified: lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp (original) +++ lldb/trunk/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp Thu Feb 16 13:38:21 2017 @@ -42,6 +42,7 @@ #include "lldb/Host/FileSpec.h" #include "lldb/Host/FileSystem.h" #include "lldb/Host/HostThread.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Host/StringConvert.h" #include "lldb/Host/Symbols.h" #include "lldb/Host/ThreadLauncher.h" @@ -64,7 +65,6 @@ #include "lldb/Target/TargetList.h" #include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Utility/CleanUp.h" -#include "lldb/Utility/PseudoTerminal.h" #include "lldb/Utility/StreamString.h" // Project includes Modified: lldb/trunk/source/Utility/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/CMakeLists.txt?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Utility/CMakeLists.txt (original) +++ lldb/trunk/source/Utility/CMakeLists.txt Thu Feb 16 13:38:21 2017 @@ -4,7 +4,6 @@ add_lldb_library(lldbUtility JSON.cpp LLDBAssert.cpp NameMatches.cpp - PseudoTerminal.cpp Range.cpp RegularExpression.cpp SelectHelper.cpp @@ -16,9 +15,10 @@ add_lldb_library(lldbUtility StringLexer.cpp TaskPool.cpp UriParser.cpp + VASprintf.cpp LINK_LIBS - lldbHost + # lldbUtility cannot have any dependencies LINK_COMPONENTS Support Modified: lldb/trunk/source/Utility/Error.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/Error.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Utility/Error.cpp (original) +++ lldb/trunk/source/Utility/Error.cpp Thu Feb 16 13:38:21 2017 @@ -20,8 +20,8 @@ #include "llvm/ADT/SmallVector.h" // Project includes -#include "lldb/Host/PosixApi.h" #include "lldb/Utility/Error.h" +#include "lldb/Utility/VASPrintf.h" using namespace lldb; using namespace lldb_private; @@ -233,25 +233,9 @@ int Error::SetErrorStringWithVarArg(cons if (Success()) SetErrorToGenericError(); - // Try and fit our error into a 1024 byte buffer first... - llvm::SmallVector<char, 1024> buf; - buf.resize(1024); - // Copy in case our first call to vsnprintf doesn't fit into our - // allocated buffer above - va_list copy_args; - va_copy(copy_args, args); - unsigned length = ::vsnprintf(buf.data(), buf.size(), format, args); - if (length >= buf.size()) { - // The error formatted string didn't fit into our buffer, resize it - // to the exact needed size, and retry - buf.resize(length + 1); - length = ::vsnprintf(buf.data(), buf.size(), format, copy_args); - va_end(copy_args); - assert(length < buf.size()); - } - m_string.assign(buf.data(), length); - va_end(args); - return length; + llvm::SmallString<1024> buf; + VASprintf(buf, format, args); + return buf.size(); } else { m_string.clear(); } Removed: lldb/trunk/source/Utility/PseudoTerminal.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/PseudoTerminal.cpp?rev=295367&view=auto ============================================================================== --- lldb/trunk/source/Utility/PseudoTerminal.cpp (original) +++ lldb/trunk/source/Utility/PseudoTerminal.cpp (removed) @@ -1,311 +0,0 @@ -//===-- PseudoTerminal.cpp --------------------------------------*- C++ -*-===// -// -// The LLVM Compiler Infrastructure -// -// This file is distributed under the University of Illinois Open Source -// License. See LICENSE.TXT for details. -// -//===----------------------------------------------------------------------===// - -#include "lldb/Utility/PseudoTerminal.h" -#include "lldb/Host/Config.h" - -#include <errno.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#if defined(TIOCSCTTY) -#include <sys/ioctl.h> -#endif - -#include "lldb/Host/PosixApi.h" - -#if defined(__ANDROID__) -int posix_openpt(int flags); -#endif - -using namespace lldb_utility; - -//---------------------------------------------------------------------- -// PseudoTerminal constructor -//---------------------------------------------------------------------- -PseudoTerminal::PseudoTerminal() - : m_master_fd(invalid_fd), m_slave_fd(invalid_fd) {} - -//---------------------------------------------------------------------- -// Destructor -// -// The destructor will close the master and slave file descriptors -// if they are valid and ownership has not been released using the -// ReleaseMasterFileDescriptor() or the ReleaseSaveFileDescriptor() -// member functions. -//---------------------------------------------------------------------- -PseudoTerminal::~PseudoTerminal() { - CloseMasterFileDescriptor(); - CloseSlaveFileDescriptor(); -} - -//---------------------------------------------------------------------- -// Close the master file descriptor if it is valid. -//---------------------------------------------------------------------- -void PseudoTerminal::CloseMasterFileDescriptor() { - if (m_master_fd >= 0) { - ::close(m_master_fd); - m_master_fd = invalid_fd; - } -} - -//---------------------------------------------------------------------- -// Close the slave file descriptor if it is valid. -//---------------------------------------------------------------------- -void PseudoTerminal::CloseSlaveFileDescriptor() { - if (m_slave_fd >= 0) { - ::close(m_slave_fd); - m_slave_fd = invalid_fd; - } -} - -//---------------------------------------------------------------------- -// Open the first available pseudo terminal with OFLAG as the -// permissions. The file descriptor is stored in this object and can -// be accessed with the MasterFileDescriptor() accessor. The -// ownership of the master file descriptor can be released using -// the ReleaseMasterFileDescriptor() accessor. If this object has -// a valid master files descriptor when its destructor is called, it -// will close the master file descriptor, therefore clients must -// call ReleaseMasterFileDescriptor() if they wish to use the master -// file descriptor after this object is out of scope or destroyed. -// -// RETURNS: -// True when successful, false indicating an error occurred. -//---------------------------------------------------------------------- -bool PseudoTerminal::OpenFirstAvailableMaster(int oflag, char *error_str, - size_t error_len) { - if (error_str) - error_str[0] = '\0'; - -#if !defined(LLDB_DISABLE_POSIX) - // Open the master side of a pseudo terminal - m_master_fd = ::posix_openpt(oflag); - if (m_master_fd < 0) { - if (error_str) - ::strerror_r(errno, error_str, error_len); - return false; - } - - // Grant access to the slave pseudo terminal - if (::grantpt(m_master_fd) < 0) { - if (error_str) - ::strerror_r(errno, error_str, error_len); - CloseMasterFileDescriptor(); - return false; - } - - // Clear the lock flag on the slave pseudo terminal - if (::unlockpt(m_master_fd) < 0) { - if (error_str) - ::strerror_r(errno, error_str, error_len); - CloseMasterFileDescriptor(); - return false; - } - - return true; -#else - if (error_str) - ::snprintf(error_str, error_len, "%s", - "pseudo terminal not supported"); - return false; -#endif -} - -//---------------------------------------------------------------------- -// Open the slave pseudo terminal for the current master pseudo -// terminal. A master pseudo terminal should already be valid prior to -// calling this function (see OpenFirstAvailableMaster()). -// The file descriptor is stored this object's member variables and can -// be accessed via the GetSlaveFileDescriptor(), or released using the -// ReleaseSlaveFileDescriptor() member function. -// -// RETURNS: -// True when successful, false indicating an error occurred. -//---------------------------------------------------------------------- -bool PseudoTerminal::OpenSlave(int oflag, char *error_str, size_t error_len) { - if (error_str) - error_str[0] = '\0'; - - CloseSlaveFileDescriptor(); - - // Open the master side of a pseudo terminal - const char *slave_name = GetSlaveName(error_str, error_len); - - if (slave_name == nullptr) - return false; - - m_slave_fd = ::open(slave_name, oflag); - - if (m_slave_fd < 0) { - if (error_str) - ::strerror_r(errno, error_str, error_len); - return false; - } - - return true; -} - -//---------------------------------------------------------------------- -// Get the name of the slave pseudo terminal. A master pseudo terminal -// should already be valid prior to calling this function (see -// OpenFirstAvailableMaster()). -// -// RETURNS: -// NULL if no valid master pseudo terminal or if ptsname() fails. -// The name of the slave pseudo terminal as a NULL terminated C string -// that comes from static memory, so a copy of the string should be -// made as subsequent calls can change this value. -//---------------------------------------------------------------------- -const char *PseudoTerminal::GetSlaveName(char *error_str, - size_t error_len) const { - if (error_str) - error_str[0] = '\0'; - - if (m_master_fd < 0) { - if (error_str) - ::snprintf(error_str, error_len, "%s", - "master file descriptor is invalid"); - return nullptr; - } - const char *slave_name = ::ptsname(m_master_fd); - - if (error_str && slave_name == nullptr) - ::strerror_r(errno, error_str, error_len); - - return slave_name; -} - -//---------------------------------------------------------------------- -// Fork a child process and have its stdio routed to a pseudo terminal. -// -// In the parent process when a valid pid is returned, the master file -// descriptor can be used as a read/write access to stdio of the -// child process. -// -// In the child process the stdin/stdout/stderr will already be routed -// to the slave pseudo terminal and the master file descriptor will be -// closed as it is no longer needed by the child process. -// -// This class will close the file descriptors for the master/slave -// when the destructor is called, so be sure to call -// ReleaseMasterFileDescriptor() or ReleaseSlaveFileDescriptor() if any -// file descriptors are going to be used past the lifespan of this -// object. -// -// RETURNS: -// in the parent process: the pid of the child, or -1 if fork fails -// in the child process: zero -//---------------------------------------------------------------------- -lldb::pid_t PseudoTerminal::Fork(char *error_str, size_t error_len) { - if (error_str) - error_str[0] = '\0'; - pid_t pid = LLDB_INVALID_PROCESS_ID; -#if !defined(LLDB_DISABLE_POSIX) - int flags = O_RDWR; - flags |= O_CLOEXEC; - if (OpenFirstAvailableMaster(flags, error_str, error_len)) { - // Successfully opened our master pseudo terminal - - pid = ::fork(); - if (pid < 0) { - // Fork failed - if (error_str) - ::strerror_r(errno, error_str, error_len); - } else if (pid == 0) { - // Child Process - ::setsid(); - - if (OpenSlave(O_RDWR, error_str, error_len)) { - // Successfully opened slave - - // Master FD should have O_CLOEXEC set, but let's close it just in - // case... - CloseMasterFileDescriptor(); - -#if defined(TIOCSCTTY) - // Acquire the controlling terminal - if (::ioctl(m_slave_fd, TIOCSCTTY, (char *)0) < 0) { - if (error_str) - ::strerror_r(errno, error_str, error_len); - } -#endif - // Duplicate all stdio file descriptors to the slave pseudo terminal - if (::dup2(m_slave_fd, STDIN_FILENO) != STDIN_FILENO) { - if (error_str && !error_str[0]) - ::strerror_r(errno, error_str, error_len); - } - - if (::dup2(m_slave_fd, STDOUT_FILENO) != STDOUT_FILENO) { - if (error_str && !error_str[0]) - ::strerror_r(errno, error_str, error_len); - } - - if (::dup2(m_slave_fd, STDERR_FILENO) != STDERR_FILENO) { - if (error_str && !error_str[0]) - ::strerror_r(errno, error_str, error_len); - } - } - } else { - // Parent Process - // Do nothing and let the pid get returned! - } - } -#endif - return pid; -} - -//---------------------------------------------------------------------- -// The master file descriptor accessor. This object retains ownership -// of the master file descriptor when this accessor is used. Use -// ReleaseMasterFileDescriptor() if you wish this object to release -// ownership of the master file descriptor. -// -// Returns the master file descriptor, or -1 if the master file -// descriptor is not currently valid. -//---------------------------------------------------------------------- -int PseudoTerminal::GetMasterFileDescriptor() const { return m_master_fd; } - -//---------------------------------------------------------------------- -// The slave file descriptor accessor. -// -// Returns the slave file descriptor, or -1 if the slave file -// descriptor is not currently valid. -//---------------------------------------------------------------------- -int PseudoTerminal::GetSlaveFileDescriptor() const { return m_slave_fd; } - -//---------------------------------------------------------------------- -// Release ownership of the master pseudo terminal file descriptor -// without closing it. The destructor for this class will close the -// master file descriptor if the ownership isn't released using this -// call and the master file descriptor has been opened. -//---------------------------------------------------------------------- -int PseudoTerminal::ReleaseMasterFileDescriptor() { - // Release ownership of the master pseudo terminal file - // descriptor without closing it. (the destructor for this - // class will close it otherwise!) - int fd = m_master_fd; - m_master_fd = invalid_fd; - return fd; -} - -//---------------------------------------------------------------------- -// Release ownership of the slave pseudo terminal file descriptor -// without closing it. The destructor for this class will close the -// slave file descriptor if the ownership isn't released using this -// call and the slave file descriptor has been opened. -//---------------------------------------------------------------------- -int PseudoTerminal::ReleaseSlaveFileDescriptor() { - // Release ownership of the slave pseudo terminal file - // descriptor without closing it (the destructor for this - // class will close it otherwise!) - int fd = m_slave_fd; - m_slave_fd = invalid_fd; - return fd; -} Modified: lldb/trunk/source/Utility/Stream.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/Stream.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/source/Utility/Stream.cpp (original) +++ lldb/trunk/source/Utility/Stream.cpp Thu Feb 16 13:38:21 2017 @@ -8,8 +8,9 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/Stream.h" -#include "lldb/Host/PosixApi.h" + #include "lldb/Utility/Endian.h" +#include "lldb/Utility/VASPrintf.h" #include <stddef.h> #include <stdio.h> #include <stdlib.h> @@ -162,36 +163,14 @@ size_t Stream::Printf(const char *format // Print some formatted output to the stream. //------------------------------------------------------------------ size_t Stream::PrintfVarArg(const char *format, va_list args) { - char str[1024]; - va_list args_copy; - - va_copy(args_copy, args); + llvm::SmallString<1024> buf; + VASprintf(buf, format, args); - size_t bytes_written = 0; - // Try and format our string into a fixed buffer first and see if it fits - size_t length = ::vsnprintf(str, sizeof(str), format, args); - if (length < sizeof(str)) { - // Include the NULL termination byte for binary output - if (m_flags.Test(eBinary)) - length += 1; - // The formatted string fit into our stack based buffer, so we can just - // append that to our packet - bytes_written = Write(str, length); - } else { - // Our stack buffer wasn't big enough to contain the entire formatted - // string, so lets let vasprintf create the string for us! - char *str_ptr = NULL; - length = ::vasprintf(&str_ptr, format, args_copy); - if (str_ptr) { - // Include the NULL termination byte for binary output - if (m_flags.Test(eBinary)) - length += 1; - bytes_written = Write(str_ptr, length); - ::free(str_ptr); - } - } - va_end(args_copy); - return bytes_written; + // Include the NULL termination byte for binary output + size_t length = buf.size(); + if (m_flags.Test(eBinary)) + ++length; + return Write(buf.c_str(), length); } //------------------------------------------------------------------ @@ -358,34 +337,18 @@ lldb::ByteOrder Stream::GetByteOrder() c size_t Stream::PrintfAsRawHex8(const char *format, ...) { va_list args; - va_list args_copy; va_start(args, format); - va_copy(args_copy, args); // Copy this so we - char str[1024]; - size_t bytes_written = 0; - // Try and format our string into a fixed buffer first and see if it fits - size_t length = ::vsnprintf(str, sizeof(str), format, args); - if (length < sizeof(str)) { - // The formatted string fit into our stack based buffer, so we can just - // append that to our packet - for (size_t i = 0; i < length; ++i) - bytes_written += _PutHex8(str[i], false); - } else { - // Our stack buffer wasn't big enough to contain the entire formatted - // string, so lets let vasprintf create the string for us! - char *str_ptr = NULL; - length = ::vasprintf(&str_ptr, format, args_copy); - if (str_ptr) { - for (size_t i = 0; i < length; ++i) - bytes_written += _PutHex8(str_ptr[i], false); - ::free(str_ptr); - } - } + llvm::SmallString<1024> buf; + VASprintf(buf, format, args); + + size_t length = 0; + for (char C : buf) + length += _PutHex8(C, false); + va_end(args); - va_end(args_copy); - return bytes_written; + return length; } size_t Stream::PutNHex8(size_t n, uint8_t uvalue) { Added: lldb/trunk/source/Utility/VASprintf.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Utility/VASprintf.cpp?rev=295368&view=auto ============================================================================== --- lldb/trunk/source/Utility/VASprintf.cpp (added) +++ lldb/trunk/source/Utility/VASprintf.cpp Thu Feb 16 13:38:21 2017 @@ -0,0 +1,52 @@ +//===-- VASPrintf.cpp -------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/VASprintf.h" + +#include "llvm/ADT/SmallString.h" + +using namespace lldb_private; + +bool lldb_private::VASprintf(llvm::SmallVectorImpl<char> &buf, const char *fmt, + va_list args) { + llvm::SmallString<16> error("<Encoding error>"); + bool result = true; + + // Copy in case our first call to vsnprintf doesn't fit into our buffer + va_list copy_args; + va_copy(copy_args, args); + + buf.resize(buf.capacity()); + // Write up to `capacity` bytes, ignoring the current size. + int length = ::vsnprintf(buf.data(), buf.size(), fmt, args); + if (length < 0) { + buf = error; + result = false; + goto finish; + } + + if (length >= buf.size()) { + // The error formatted string didn't fit into our buffer, resize it + // to the exact needed size, and retry + buf.resize(length + 1); + length = ::vsnprintf(buf.data(), buf.size(), fmt, copy_args); + if (length < 0) { + buf = error; + result = false; + goto finish; + } + assert(length < buf.size()); + } + buf.resize(length); + +finish: + va_end(args); + va_end(copy_args); + return result; +} Modified: lldb/trunk/tools/driver/Driver.h URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/tools/driver/Driver.h?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/tools/driver/Driver.h (original) +++ lldb/trunk/tools/driver/Driver.h Thu Feb 16 13:38:21 2017 @@ -11,7 +11,7 @@ #define lldb_Driver_h_ #include "Platform.h" -#include "lldb/Utility/PseudoTerminal.h" +#include "lldb/Host/PseudoTerminal.h" #include <bitset> #include <set> Modified: lldb/trunk/unittests/Editline/EditlineTest.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Editline/EditlineTest.cpp?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/unittests/Editline/EditlineTest.cpp (original) +++ lldb/trunk/unittests/Editline/EditlineTest.cpp Thu Feb 16 13:38:21 2017 @@ -22,8 +22,8 @@ #include "lldb/Core/StringList.h" #include "lldb/Host/Editline.h" #include "lldb/Host/Pipe.h" +#include "lldb/Host/PseudoTerminal.h" #include "lldb/Utility/Error.h" -#include "lldb/Utility/PseudoTerminal.h" namespace { const size_t TIMEOUT_MILLIS = 5000; Modified: lldb/trunk/unittests/Utility/CMakeLists.txt URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Utility/CMakeLists.txt?rev=295368&r1=295367&r2=295368&view=diff ============================================================================== --- lldb/trunk/unittests/Utility/CMakeLists.txt (original) +++ lldb/trunk/unittests/Utility/CMakeLists.txt Thu Feb 16 13:38:21 2017 @@ -4,9 +4,9 @@ add_lldb_unittest(UtilityTests TaskPoolTest.cpp TimeoutTest.cpp UriParserTest.cpp + VASprintfTest.cpp LINK_LIBS - lldbHost lldbUtility LINK_COMPONENTS Support Added: lldb/trunk/unittests/Utility/VASprintfTest.cpp URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/unittests/Utility/VASprintfTest.cpp?rev=295368&view=auto ============================================================================== --- lldb/trunk/unittests/Utility/VASprintfTest.cpp (added) +++ lldb/trunk/unittests/Utility/VASprintfTest.cpp Thu Feb 16 13:38:21 2017 @@ -0,0 +1,59 @@ +//===-- VASprintfTest.cpp ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Utility/VASprintf.h" +#include "llvm/ADT/SmallString.h" + +#include "gtest/gtest.h" + +#include <locale.h> + +using namespace lldb_private; +using namespace llvm; + +static bool Sprintf(llvm::SmallVectorImpl<char> &Buffer, const char *Fmt, ...) { + va_list args; + va_start(args, Fmt); + bool Result = VASprintf(Buffer, Fmt, args); + va_end(args); + return Result; +} + +TEST(VASprintfTest, NoBufferResize) { + std::string TestStr("small"); + + llvm::SmallString<32> BigBuffer; + ASSERT_TRUE(Sprintf(BigBuffer, "%s", TestStr.c_str())); + EXPECT_STREQ(TestStr.c_str(), BigBuffer.c_str()); + EXPECT_EQ(TestStr.size(), BigBuffer.size()); +} + +TEST(VASprintfTest, BufferResize) { + std::string TestStr("bigger"); + llvm::SmallString<4> SmallBuffer; + ASSERT_TRUE(Sprintf(SmallBuffer, "%s", TestStr.c_str())); + EXPECT_STREQ(TestStr.c_str(), SmallBuffer.c_str()); + EXPECT_EQ(TestStr.size(), SmallBuffer.size()); +} + +TEST(VASprintfTest, EncodingError) { + // Save the current locale first. + std::string Current(::setlocale(LC_ALL, nullptr)); + + setlocale(LC_ALL, ".932"); + + wchar_t Invalid[2]; + Invalid[0] = 129; + Invalid[1] = 0; + llvm::SmallString<32> Buffer; + EXPECT_FALSE(Sprintf(Buffer, "%ls", Invalid)); + EXPECT_EQ("<Encoding error>", Buffer); + + setlocale(LC_CTYPE, Current.c_str()); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits