diff options
Diffstat (limited to 'lldb/source/Utility')
| -rw-r--r-- | lldb/source/Utility/CMakeLists.txt | 4 | ||||
| -rw-r--r-- | lldb/source/Utility/Error.cpp | 24 | ||||
| -rw-r--r-- | lldb/source/Utility/PseudoTerminal.cpp | 311 | ||||
| -rw-r--r-- | lldb/source/Utility/Stream.cpp | 71 | ||||
| -rw-r--r-- | lldb/source/Utility/VASprintf.cpp | 52 |
5 files changed, 75 insertions, 387 deletions
diff --git a/lldb/source/Utility/CMakeLists.txt b/lldb/source/Utility/CMakeLists.txt index dc0615c2638..d0b823b0839 100644 --- a/lldb/source/Utility/CMakeLists.txt +++ b/lldb/source/Utility/CMakeLists.txt @@ -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 diff --git a/lldb/source/Utility/Error.cpp b/lldb/source/Utility/Error.cpp index 3b3d1fa32c4..0b14949e88f 100644 --- a/lldb/source/Utility/Error.cpp +++ b/lldb/source/Utility/Error.cpp @@ -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(const char *format, va_list args) { 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(); } diff --git a/lldb/source/Utility/PseudoTerminal.cpp b/lldb/source/Utility/PseudoTerminal.cpp deleted file mode 100644 index 4d99a568b65..00000000000 --- a/lldb/source/Utility/PseudoTerminal.cpp +++ /dev/null @@ -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; -} diff --git a/lldb/source/Utility/Stream.cpp b/lldb/source/Utility/Stream.cpp index d3c0b050a56..8899a43496c 100644 --- a/lldb/source/Utility/Stream.cpp +++ b/lldb/source/Utility/Stream.cpp @@ -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() const { return m_byte_order; } 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) { diff --git a/lldb/source/Utility/VASprintf.cpp b/lldb/source/Utility/VASprintf.cpp new file mode 100644 index 00000000000..cc280ec3a14 --- /dev/null +++ b/lldb/source/Utility/VASprintf.cpp @@ -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; +} |

