diff options
Diffstat (limited to 'lldb/source/Utility')
-rw-r--r-- | lldb/source/Utility/ARM_DWARF_Registers.h | 190 | ||||
-rw-r--r-- | lldb/source/Utility/ARM_GCC_Registers.h | 35 | ||||
-rw-r--r-- | lldb/source/Utility/PseudoTerminal.cpp | 336 | ||||
-rw-r--r-- | lldb/source/Utility/PseudoTerminal.h | 267 | ||||
-rw-r--r-- | lldb/source/Utility/StringExtractor.cpp | 360 | ||||
-rw-r--r-- | lldb/source/Utility/StringExtractor.h | 126 | ||||
-rw-r--r-- | lldb/source/Utility/StringExtractorGDBRemote.cpp | 89 | ||||
-rw-r--r-- | lldb/source/Utility/StringExtractorGDBRemote.h | 73 |
8 files changed, 1476 insertions, 0 deletions
diff --git a/lldb/source/Utility/ARM_DWARF_Registers.h b/lldb/source/Utility/ARM_DWARF_Registers.h new file mode 100644 index 00000000000..40b973be6da --- /dev/null +++ b/lldb/source/Utility/ARM_DWARF_Registers.h @@ -0,0 +1,190 @@ +//===-- ARM_DWARF_Registers.h -----------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_ARM_DWARF_Registers_h_ +#define utility_ARM_DWARF_Registers_h_ + +enum +{ + dwarf_r0 = 0, + dwarf_r1, + dwarf_r2, + dwarf_r3, + dwarf_r4, + dwarf_r5, + dwarf_r6, + dwarf_r7, + dwarf_r8, + dwarf_r9, + dwarf_r10, + dwarf_r11, + dwarf_r12, + dwarf_sp, + dwarf_lr, + dwarf_pc, + dwarf_cpsr, + + dwarf_s0 = 64, + dwarf_s1, + dwarf_s2, + dwarf_s3, + dwarf_s4, + dwarf_s5, + dwarf_s6, + dwarf_s7, + dwarf_s8, + dwarf_s9, + dwarf_s10, + dwarf_s11, + dwarf_s12, + dwarf_s13, + dwarf_s14, + dwarf_s15, + dwarf_s16, + dwarf_s17, + dwarf_s18, + dwarf_s19, + dwarf_s20, + dwarf_s21, + dwarf_s22, + dwarf_s23, + dwarf_s24, + dwarf_s25, + dwarf_s26, + dwarf_s27, + dwarf_s28, + dwarf_s29, + dwarf_s30, + dwarf_s31, + + // FPA Registers 0-7 + dwarf_f0 = 96, + dwarf_f1, + dwarf_f2, + dwarf_f3, + dwarf_f4, + dwarf_f5, + dwarf_f6, + dwarf_f7, + + // Intel wireless MMX general purpose registers 0–7 + dwarf_wCGR0 = 104, + dwarf_wCGR1, + dwarf_wCGR2, + dwarf_wCGR3, + dwarf_wCGR4, + dwarf_wCGR5, + dwarf_wCGR6, + dwarf_wCGR7, + + // XScale accumulator register 0–7 (they do overlap with wCGR0 - wCGR7) + dwarf_ACC0 = 104, + dwarf_ACC1, + dwarf_ACC2, + dwarf_ACC3, + dwarf_ACC4, + dwarf_ACC5, + dwarf_ACC6, + dwarf_ACC7, + + // Intel wireless MMX data registers 0–15 + dwarf_wR0 = 112, + dwarf_wR1, + dwarf_wR2, + dwarf_wR3, + dwarf_wR4, + dwarf_wR5, + dwarf_wR6, + dwarf_wR7, + dwarf_wR8, + dwarf_wR9, + dwarf_wR10, + dwarf_wR11, + dwarf_wR12, + dwarf_wR13, + dwarf_wR14, + dwarf_wR15, + + dwarf_spsr = 128, + dwarf_spsr_fiq, + dwarf_spsr_irq, + dwarf_spsr_abt, + dwarf_spsr_und, + dwarf_spsr_svc, + + dwarf_r8_usr = 144, + dwarf_r9_usr, + dwarf_r10_usr, + dwarf_r11_usr, + dwarf_r12_usr, + dwarf_r13_usr, + dwarf_r14_usr, + dwarf_r8_fiq, + dwarf_r9_fiq, + dwarf_r10_fiq, + dwarf_r11_fiq, + dwarf_r12_fiq, + dwarf_r13_fiq, + dwarf_r14_fiq, + dwarf_r13_irq, + dwarf_r14_irq, + dwarf_r13_abt, + dwarf_r14_abt, + dwarf_r13_und, + dwarf_r14_und, + dwarf_r13_svc, + dwarf_r14_svc, + + // Intel wireless MMX control register in co-processor 0–7 + dwarf_wC0 = 192, + dwarf_wC1, + dwarf_wC2, + dwarf_wC3, + dwarf_wC4, + dwarf_wC5, + dwarf_wC6, + dwarf_wC7, + + // VFP-v3/Neon + dwarf_d0 = 256, + dwarf_d1, + dwarf_d2, + dwarf_d3, + dwarf_d4, + dwarf_d5, + dwarf_d6, + dwarf_d7, + dwarf_d8, + dwarf_d9, + dwarf_d10, + dwarf_d11, + dwarf_d12, + dwarf_d13, + dwarf_d14, + dwarf_d15, + dwarf_d16, + dwarf_d17, + dwarf_d18, + dwarf_d19, + dwarf_d20, + dwarf_d21, + dwarf_d22, + dwarf_d23, + dwarf_d24, + dwarf_d25, + dwarf_d26, + dwarf_d27, + dwarf_d28, + dwarf_d29, + dwarf_d30, + dwarf_d31 +}; + +#endif utility_ARM_DWARF_Registers_h_ + diff --git a/lldb/source/Utility/ARM_GCC_Registers.h b/lldb/source/Utility/ARM_GCC_Registers.h new file mode 100644 index 00000000000..fe1327b5e14 --- /dev/null +++ b/lldb/source/Utility/ARM_GCC_Registers.h @@ -0,0 +1,35 @@ +//===-- ARM_GCC_Registers.h -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_ARM_GCC_Registers_h_ +#define utility_ARM_GCC_Registers_h_ + +enum +{ + gcc_r0 = 0, + gcc_r1, + gcc_r2, + gcc_r3, + gcc_r4, + gcc_r5, + gcc_r6, + gcc_r7, + gcc_r8, + gcc_r9, + gcc_r10, + gcc_r11, + gcc_r12, + gcc_sp, + gcc_lr, + gcc_pc, + gcc_cpsr +}; + +#endif utility_ARM_GCC_Registers_h_ + diff --git a/lldb/source/Utility/PseudoTerminal.cpp b/lldb/source/Utility/PseudoTerminal.cpp new file mode 100644 index 00000000000..9bbecae6e6d --- /dev/null +++ b/lldb/source/Utility/PseudoTerminal.cpp @@ -0,0 +1,336 @@ +//===-- 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 "PseudoTerminal.h" + +#include <errno.h> +#include <stdlib.h> +#include <string.h> +#include <sys/ioctl.h> + +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 ownwership 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: +// Zero when successful, non-zero indicating an error occurred. +//---------------------------------------------------------------------- +bool +PseudoTerminal::OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len) +{ + if (error_str) + error_str[0] = '\0'; + + // 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; +} + +//---------------------------------------------------------------------- +// 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: +// Zero when successful, non-zero 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 == NULL) + 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 NULL; + } + const char *slave_name = ::ptsname (m_master_fd); + + if (error_str && slave_name == NULL) + ::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 (OpenFirstAvailableMaster (O_RDWR, 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 + // We are done with the master in the child process so lets close it + 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! + } + } + 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/PseudoTerminal.h b/lldb/source/Utility/PseudoTerminal.h new file mode 100644 index 00000000000..5d680745a32 --- /dev/null +++ b/lldb/source/Utility/PseudoTerminal.h @@ -0,0 +1,267 @@ +//===-- PseudoTerminal.h ----------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef liblldb_PseudoTerminal_h_ +#define liblldb_PseudoTerminal_h_ +#if defined(__cplusplus) + + +#include <fcntl.h> +#include <termios.h> +#include <string> + +#include "lldb/lldb-defines.h" + +namespace lldb_utility { + +//---------------------------------------------------------------------- +/// @class PseudoTerminal PseudoTerminal.h "lldb/Core/PseudoTerminal.h" +/// @brief A pseudo terminal helper class. +/// +/// The pseudo terminal class abtracts the use of pseudo terminals on +/// the host system. +//---------------------------------------------------------------------- +class PseudoTerminal +{ +public: + enum + { + invalid_fd = -1, ///< Invalid file descriptor value + }; + + //------------------------------------------------------------------ + /// Default constructor + /// + /// Constructs this object with invalid master and slave file + /// descriptors. + //------------------------------------------------------------------ + PseudoTerminal (); + + //------------------------------------------------------------------ + /// Destructor + /// + /// The destructor will close the master and slave file descriptors + /// if they are valid and ownwership has not been released using + /// one of: + /// @li PseudoTerminal::ReleaseMasterFileDescriptor() + /// @li PseudoTerminal::ReleaseSaveFileDescriptor() + //------------------------------------------------------------------ + ~PseudoTerminal (); + + //------------------------------------------------------------------ + /// Close the master file descriptor if it is valid. + //------------------------------------------------------------------ + void + CloseMasterFileDescriptor (); + + //------------------------------------------------------------------ + /// Close the slave file descriptor if it is valid. + //------------------------------------------------------------------ + void + CloseSlaveFileDescriptor (); + + //------------------------------------------------------------------ + /// Fork a child process that uses pseudo terminals for its stdio. + /// + /// In the parent process, a call to this function results in a pid + /// being returned. If the pid is valid, the master file descriptor + /// can be used for 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. The file handles can be released + /// using either: + /// @li PseudoTerminal::ReleaseMasterFileDescriptor() + /// @li PseudoTerminal::ReleaseSaveFileDescriptor() + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// @li \b Parent process: a child process ID that is greater + /// than zero, or -1 if the fork fails. + /// @li \b Child process: zero. + //------------------------------------------------------------------ + pid_t + Fork (char *error_str, size_t error_len); + + //------------------------------------------------------------------ + /// The master file descriptor accessor. + /// + /// This object retains ownership of the master file descriptor when + /// this accessor is used. Users can call the member function + /// PseudoTerminal::ReleaseMasterFileDescriptor() if this + /// object should release ownership of the slave file descriptor. + /// + /// @return + /// The master file descriptor, or PseudoTerminal::invalid_fd + /// if the master file descriptor is not currently valid. + /// + /// @see PseudoTerminal::ReleaseMasterFileDescriptor() + //------------------------------------------------------------------ + int + GetMasterFileDescriptor () const; + + //------------------------------------------------------------------ + /// The slave file descriptor accessor. + /// + /// This object retains ownership of the slave file descriptor when + /// this accessor is used. Users can call the member function + /// PseudoTerminal::ReleaseSlaveFileDescriptor() if this + /// object should release ownership of the slave file descriptor. + /// + /// @return + /// The slave file descriptor, or PseudoTerminal::invalid_fd + /// if the slave file descriptor is not currently valid. + /// + /// @see PseudoTerminal::ReleaseSlaveFileDescriptor() + //------------------------------------------------------------------ + int + GetSlaveFileDescriptor () const; + + //------------------------------------------------------------------ + /// Get the name of the slave pseudo terminal. + /// + /// A master pseudo terminal should already be valid prior to + /// calling this function. + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// The name of the slave pseudo terminal as a NULL terminated + /// C. This string that comes from static memory, so a copy of + /// the string should be made as subsequent calls can change + /// this value. NULL is returned if this object doesn't have + /// a valid master pseudo terminal opened or if the call to + /// \c ptsname() fails. + /// + /// @see PseudoTerminal::OpenFirstAvailableMaster() + //------------------------------------------------------------------ + const char* + GetSlaveName (char *error_str, size_t error_len) const; + + //------------------------------------------------------------------ + /// Open the first available pseudo terminal. + /// + /// Opens the first available pseudo terminal with \a oflag as the + /// permissions. The opened master file descriptor is stored in this + /// object and can be accessed by calling the + /// PseudoTerminal::GetMasterFileDescriptor() accessor. Clients + /// can call the PseudoTerminal::ReleaseMasterFileDescriptor() + /// accessor function if they wish to use the master file descriptor + /// beyond the lifespan of this object. + /// + /// If this object still has a valid master file descriptor when its + /// destructor is called, it will close it. + /// + /// @param[in] oflag + /// Flags to use when calling \c posix_openpt(\a oflag). + /// A value of "O_RDWR|O_NOCTTY" is suggested. + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// @li \b true when the a master files descriptor is + /// successfully opened. + /// @li \b false if anything goes wrong. + /// + /// @see PseudoTerminal::GetMasterFileDescriptor() + /// @see PseudoTerminal::ReleaseMasterFileDescriptor() + //------------------------------------------------------------------ + bool + OpenFirstAvailableMaster (int oflag, char *error_str, size_t error_len); + + //------------------------------------------------------------------ + /// Open the slave for the current master pseudo terminal. + /// + /// A master pseudo terminal should already be valid prior to + /// calling this function. The opened slave file descriptor is + /// stored in this object and can be accessed by calling the + /// PseudoTerminal::GetSlaveFileDescriptor() accessor. Clients + /// can call the PseudoTerminal::ReleaseSlaveFileDescriptor() + /// accessor function if they wish to use the slave file descriptor + /// beyond the lifespan of this object. + /// + /// If this object still has a valid slave file descriptor when its + /// destructor is called, it will close it. + /// + /// @param[in] oflag + /// Flags to use when calling \c open(\a oflag). + /// + /// @param[out] error + /// An pointer to an error that can describe any errors that + /// occur. This can be NULL if no error status is desired. + /// + /// @return + /// @li \b true when the a master files descriptor is + /// successfully opened. + /// @li \b false if anything goes wrong. + /// + /// @see PseudoTerminal::OpenFirstAvailableMaster() + /// @see PseudoTerminal::GetSlaveFileDescriptor() + /// @see PseudoTerminal::ReleaseSlaveFileDescriptor() + //------------------------------------------------------------------ + bool + OpenSlave (int oflag, char *error_str, size_t error_len); + + //------------------------------------------------------------------ + /// Release the master file descriptor. + /// + /// Releases 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. + /// + /// @return + /// The master file descriptor, or PseudoTerminal::invalid_fd + /// if the mast file descriptor is not currently valid. + //------------------------------------------------------------------ + int + ReleaseMasterFileDescriptor (); + + //------------------------------------------------------------------ + /// Release the slave file descriptor. + /// + /// 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. + /// + /// @return + /// The slave file descriptor, or PseudoTerminal::invalid_fd + /// if the slave file descriptor is not currently valid. + //------------------------------------------------------------------ + int + ReleaseSlaveFileDescriptor (); + +protected: + //------------------------------------------------------------------ + // Member variables + //------------------------------------------------------------------ + int m_master_fd; ///< The file descriptor for the master. + int m_slave_fd; ///< The file descriptor for the slave. + +private: + DISALLOW_COPY_AND_ASSIGN (PseudoTerminal); + +}; + +} // namespace lldb + +#endif // #if defined(__cplusplus) +#endif // #ifndef liblldb_PseudoTerminal_h_ diff --git a/lldb/source/Utility/StringExtractor.cpp b/lldb/source/Utility/StringExtractor.cpp new file mode 100644 index 00000000000..d2f69f95b7c --- /dev/null +++ b/lldb/source/Utility/StringExtractor.cpp @@ -0,0 +1,360 @@ +//===-- StringExtractor.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "StringExtractor.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + +static inline int +xdigit_to_sint (char ch) +{ + ch = tolower(ch); + if (ch >= 'a' && ch <= 'f') + return 10 + ch - 'a'; + return ch - '0'; +} + +static inline unsigned int +xdigit_to_uint (uint8_t ch) +{ + ch = tolower(ch); + if (ch >= 'a' && ch <= 'f') + return 10u + ch - 'a'; + return ch - '0'; +} + +//---------------------------------------------------------------------- +// StringExtractor constructor +//---------------------------------------------------------------------- +StringExtractor::StringExtractor() : + m_packet(), + m_index (0) +{ +} + + +StringExtractor::StringExtractor(const char *packet_cstr) : + m_packet(), + m_index (0) +{ + if (packet_cstr) + m_packet.assign (packet_cstr); +} + + +//---------------------------------------------------------------------- +// StringExtractor copy constructor +//---------------------------------------------------------------------- +StringExtractor::StringExtractor(const StringExtractor& rhs) : + m_packet (rhs.m_packet), + m_index (rhs.m_index) +{ + +} + +//---------------------------------------------------------------------- +// StringExtractor assignment operator +//---------------------------------------------------------------------- +const StringExtractor& +StringExtractor::operator=(const StringExtractor& rhs) +{ + if (this != &rhs) + { + m_packet = rhs.m_packet; + m_index = rhs.m_index; + + } + return *this; +} + +//---------------------------------------------------------------------- +// Destructor +//---------------------------------------------------------------------- +StringExtractor::~StringExtractor() +{ +} + + +char +StringExtractor::GetChar (char fail_value) +{ + if (m_index < m_packet.size()) + { + char ch = m_packet[m_index]; + ++m_index; + return ch; + } + m_index = UINT32_MAX; + return fail_value; +} + +uint32_t +StringExtractor::GetNumHexASCIICharsAtFilePos (uint32_t max) const +{ + uint32_t idx = m_index; + const size_t size = m_packet.size(); + while (idx < size && idx - m_index < max && isxdigit(m_packet[idx])) + ++idx; + return idx - m_index; +} +//---------------------------------------------------------------------- +// Extract a signed character from two hex ASCII chars in the packet +// string +//---------------------------------------------------------------------- +int8_t +StringExtractor::GetHexS8 (int8_t fail_value) +{ + if (GetNumHexASCIICharsAtFilePos(2)) + { + char hi_nibble_char = m_packet[m_index]; + char lo_nibble_char = m_packet[m_index+1]; + + if (isxdigit(hi_nibble_char) && isxdigit(lo_nibble_char)) + { + char hi_nibble = xdigit_to_sint (hi_nibble_char); + char lo_nibble = xdigit_to_sint (lo_nibble_char); + m_index += 2; + return (hi_nibble << 4) + lo_nibble; + } + } + m_index = UINT32_MAX; + return fail_value; +} + +//---------------------------------------------------------------------- +// Extract an unsigned character from two hex ASCII chars in the packet +// string +//---------------------------------------------------------------------- +uint8_t +StringExtractor::GetHexU8 (uint8_t fail_value) +{ + if (GetNumHexASCIICharsAtFilePos(2)) + { + uint8_t hi_nibble_char = m_packet[m_index]; + uint8_t lo_nibble_char = m_packet[m_index+1]; + + if (isxdigit(hi_nibble_char) && isxdigit(lo_nibble_char)) + { + uint8_t hi_nibble = xdigit_to_sint (hi_nibble_char); + uint8_t lo_nibble = xdigit_to_sint (lo_nibble_char); + m_index += 2; + return (hi_nibble << 4) + lo_nibble; + } + } + m_index = UINT32_MAX; + return fail_value; +} + +uint32_t +StringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value) +{ + uint32_t result = 0; + uint32_t nibble_count = 0; + + if (little_endian) + { + uint32_t shift_amount = 0; + while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index])) + { + // Make sure we don't exceed the size of a uint32_t... + if (nibble_count >= (sizeof(uint32_t) * 2)) + { + m_index = UINT32_MAX; + return fail_value; + } + + uint8_t nibble_lo; + uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]); + ++m_index; + if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index])) + { + nibble_lo = xdigit_to_sint (m_packet[m_index]); + ++m_index; + result |= ((uint32_t)nibble_hi << (shift_amount + 4)); + result |= ((uint32_t)nibble_lo << shift_amount); + nibble_count += 2; + shift_amount += 8; + } + else + { + result |= ((uint32_t)nibble_hi << shift_amount); + nibble_count += 1; + shift_amount += 4; + } + + } + } + else + { + while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index])) + { + // Make sure we don't exceed the size of a uint32_t... + if (nibble_count >= (sizeof(uint32_t) * 2)) + { + m_index = UINT32_MAX; + return fail_value; + } + + uint8_t nibble = xdigit_to_sint (m_packet[m_index]); + // Big Endian + result <<= 4; + result |= nibble; + + ++m_index; + ++nibble_count; + } + } + return result; +} + +uint64_t +StringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value) +{ + uint64_t result = 0; + uint32_t nibble_count = 0; + + if (little_endian) + { + uint32_t shift_amount = 0; + while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index])) + { + // Make sure we don't exceed the size of a uint64_t... + if (nibble_count >= (sizeof(uint64_t) * 2)) + { + m_index = UINT32_MAX; + return fail_value; + } + + uint8_t nibble_lo; + uint8_t nibble_hi = xdigit_to_sint (m_packet[m_index]); + ++m_index; + if (m_index < m_packet.size() && ::isxdigit (m_packet[m_index])) + { + nibble_lo = xdigit_to_sint (m_packet[m_index]); + ++m_index; + result |= ((uint64_t)nibble_hi << (shift_amount + 4)); + result |= ((uint64_t)nibble_lo << shift_amount); + nibble_count += 2; + shift_amount += 8; + } + else + { + result |= ((uint64_t)nibble_hi << shift_amount); + nibble_count += 1; + shift_amount += 4; + } + + } + } + else + { + while (m_index < m_packet.size() && ::isxdigit (m_packet[m_index])) + { + // Make sure we don't exceed the size of a uint64_t... + if (nibble_count >= (sizeof(uint64_t) * 2)) + { + m_index = UINT32_MAX; + return fail_value; + } + + uint8_t nibble = xdigit_to_sint (m_packet[m_index]); + // Big Endian + result <<= 4; + result |= nibble; + + ++m_index; + ++nibble_count; + } + } + return result; +} + +size_t +StringExtractor::GetHexBytes (void *dst_void, size_t dst_len, uint8_t fail_fill_value) +{ + uint8_t *dst = (uint8_t*)dst_void; + size_t bytes_extracted = 0; + while (bytes_extracted < dst_len && GetBytesLeft ()) + { + dst[bytes_extracted] = GetHexU8 (fail_fill_value); + if (IsGood()) + ++bytes_extracted; + else + break; + } + + for (size_t i = bytes_extracted; i < dst_len; ++i) + dst[i] = fail_fill_value; + + return bytes_extracted; +} + + +// Consume ASCII hex nibble character pairs until we have decoded byte_size +// bytes of data. + +uint64_t +StringExtractor::GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value) +{ + if (byte_size <= 8 && GetBytesLeft() >= byte_size * 2) + { + uint64_t result = 0; + uint32_t i; + if (little_endian) + { + // Little Endian + uint32_t shift_amount; + for (i = 0, shift_amount = 0; + i < byte_size && m_index != UINT32_MAX; + ++i, shift_amount += 8) + { + result |= ((uint64_t)GetHexU8() << shift_amount); + } + } + else + { + // Big Endian + for (i = 0; i < byte_size && m_index != UINT32_MAX; ++i) + { + result <<= 8; + result |= GetHexU8(); + } + } + } + m_index = UINT32_MAX; + return fail_value; +} + +bool +StringExtractor::GetNameColonValue (std::string &name, std::string &value) +{ + // Read something in the form of NNNN:VVVV; where NNNN is any character + // that is not a colon, followed by a ':' character, then a value (one or + // more ';' chars), followed by a ';' + if (m_index < m_packet.size()) + { + const size_t colon_idx = m_packet.find (':', m_index); + if (colon_idx != std::string::npos) + { + const size_t semicolon_idx = m_packet.find (';', colon_idx); + if (semicolon_idx != std::string::npos) + { + name.assign (m_packet, m_index, colon_idx - m_index); + value.assign (m_packet, colon_idx + 1, semicolon_idx - (colon_idx + 1)); + m_index = semicolon_idx + 1; + return true; + } + } + } + m_index = UINT32_MAX; + return false; +} diff --git a/lldb/source/Utility/StringExtractor.h b/lldb/source/Utility/StringExtractor.h new file mode 100644 index 00000000000..e2312f71ad7 --- /dev/null +++ b/lldb/source/Utility/StringExtractor.h @@ -0,0 +1,126 @@ +//===-- StringExtractor.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_StringExtractor_h_ +#define utility_StringExtractor_h_ + +// C Includes +// C++ Includes +#include <string> + +// Other libraries and framework includes +// Project includes + +class StringExtractor +{ +public: + + enum { + BigEndian = 0, + LittleEndian = 1 + }; + //------------------------------------------------------------------ + // Constructors and Destructors + //------------------------------------------------------------------ + StringExtractor(); + StringExtractor(const char *packet_cstr); + StringExtractor(const StringExtractor& rhs); + virtual ~StringExtractor(); + + //------------------------------------------------------------------ + // Operators + //------------------------------------------------------------------ + const StringExtractor& + operator=(const StringExtractor& rhs); + + // Returns true if the file position is still valid for the data + // contained in this string extractor object. + bool + IsGood() const + { + return m_index != UINT32_MAX; + } + + uint32_t + GetFilePos () const + { + return m_index; + } + + void + SetFilePos (uint32_t idx) + { + m_index = idx; + } + + void + Clear () + { + m_packet.clear(); + m_index = 0; + } + + std::string & + GetStringRef () + { + return m_packet; + } + + bool + Empty() + { + return m_packet.empty(); + } + + uint32_t + GetBytesLeft () + { + if (m_index < m_packet.size()) + return m_packet.size() - m_index; + return 0; + } + char + GetChar (char fail_value = '\0'); + + int8_t + GetHexS8 (int8_t fail_value = 0); + + uint8_t + GetHexU8 (uint8_t fail_value = 0); + + bool + GetNameColonValue (std::string &name, std::string &value); + + uint32_t + GetHexMaxU32 (bool little_endian, uint32_t fail_value); + + uint64_t + GetHexMaxU64 (bool little_endian, uint64_t fail_value); + + size_t + GetHexBytes (void *dst, size_t dst_len, uint8_t fail_fill_value); + + uint64_t + GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value); + +protected: + //------------------------------------------------------------------ + // For StringExtractor only + //------------------------------------------------------------------ + std::string m_packet; // The string in which to extract data. + uint32_t m_index; // When extracting data from a packet, this index + // will march along as things get extracted. If set + // to UINT32_MAX the end of the packet data was + // reached when decoding information + + uint32_t + GetNumHexASCIICharsAtFilePos (uint32_t max = UINT32_MAX) const; +}; + +#endif // utility_StringExtractor_h_ diff --git a/lldb/source/Utility/StringExtractorGDBRemote.cpp b/lldb/source/Utility/StringExtractorGDBRemote.cpp new file mode 100644 index 00000000000..f7dcc4181f3 --- /dev/null +++ b/lldb/source/Utility/StringExtractorGDBRemote.cpp @@ -0,0 +1,89 @@ +//===-- StringExtractorGDBRemote.cpp ----------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "StringExtractorGDBRemote.h" + +// C Includes +// C++ Includes +// Other libraries and framework includes +// Project includes + + + +StringExtractorGDBRemote::Type +StringExtractorGDBRemote::GetType () const +{ + if (m_packet.empty()) + return eUnsupported; + + switch (m_packet[0]) + { + case 'E': + if (m_packet.size() == 3 && + isxdigit(m_packet[1]) && + isxdigit(m_packet[2])) + return eError; + break; + + case 'O': + if (m_packet.size() == 2 && m_packet[1] == 'K') + return eOK; + break; + + case '+': + if (m_packet.size() == 1) + return eAck; + break; + + case '-': + if (m_packet.size() == 1) + return eNack; + break; + } + return eResponse; +} + +bool +StringExtractorGDBRemote::IsOKPacket() const +{ + return GetType () == eOK; +} + + +bool +StringExtractorGDBRemote::IsUnsupportedPacket() const +{ + return GetType () == eUnsupported; +} + +bool +StringExtractorGDBRemote::IsNormalPacket() const +{ + return GetType () == eResponse; +} + +bool +StringExtractorGDBRemote::IsErrorPacket() const +{ + return GetType () == eError && + m_packet.size() == 3 && + isxdigit(m_packet[1]) && + isxdigit(m_packet[2]); +} + +uint8_t +StringExtractorGDBRemote::GetError () +{ + if (GetType() == eError) + { + SetFilePos(1); + return GetHexU8(255); + } + return 0; +} diff --git a/lldb/source/Utility/StringExtractorGDBRemote.h b/lldb/source/Utility/StringExtractorGDBRemote.h new file mode 100644 index 00000000000..813ddad2e27 --- /dev/null +++ b/lldb/source/Utility/StringExtractorGDBRemote.h @@ -0,0 +1,73 @@ +//===-- StringExtractorGDBRemote.h ------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef utility_StringExtractorGDBRemote_h_ +#define utility_StringExtractorGDBRemote_h_ + +// C Includes +// C++ Includes +#include <string> +// Other libraries and framework includes +// Project includes +#include "StringExtractor.h" + +class StringExtractorGDBRemote : public StringExtractor +{ +public: + + StringExtractorGDBRemote() : + StringExtractor () + { + } + + StringExtractorGDBRemote(const char *cstr) : + StringExtractor (cstr) + { + } + StringExtractorGDBRemote(const StringExtractorGDBRemote& rhs) : + StringExtractor (rhs) + { + } + + virtual ~StringExtractorGDBRemote() + { + } + + enum Type + { + eUnsupported = 0, + eAck, + eNack, + eError, + eOK, + eResponse + }; + + StringExtractorGDBRemote::Type + GetType () const; + + bool + IsOKPacket() const; + + bool + IsUnsupportedPacket() const; + + bool + IsNormalPacket () const; + + bool + IsErrorPacket() const; + + // Returns zero if the packet isn't a EXX packet where XX are two hex + // digits. Otherwise the error encoded in XX is returned. + uint8_t + GetError(); +}; + +#endif // utility_StringExtractorGDBRemote_h_ |