--- /dev/null
+//===-- StdStringExtractor.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_StdStringExtractor_h_
+#define utility_StdStringExtractor_h_
+
+// C Includes
+// C++ Includes
+#include <string>
+#include <stdint.h>
+
+// Other libraries and framework includes
+// Project includes
+
+// Based on StringExtractor, with the added limitation that this file should not
+// take a dependency on LLVM, as it is used from debugserver.
+class StdStringExtractor
+{
+public:
+
+ enum {
+ BigEndian = 0,
+ LittleEndian = 1
+ };
+ //------------------------------------------------------------------
+ // Constructors and Destructors
+ //------------------------------------------------------------------
+ StdStringExtractor();
+ StdStringExtractor(const char *packet_cstr);
+ StdStringExtractor(const StdStringExtractor& rhs);
+ virtual ~StdStringExtractor();
+
+ //------------------------------------------------------------------
+ // Operators
+ //------------------------------------------------------------------
+ const StdStringExtractor&
+ operator=(const StdStringExtractor& 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 != UINT64_MAX;
+ }
+
+ uint64_t
+ GetFilePos () const
+ {
+ return m_index;
+ }
+
+ void
+ SetFilePos (uint32_t idx)
+ {
+ m_index = idx;
+ }
+
+ void
+ Clear ()
+ {
+ m_packet.clear();
+ m_index = 0;
+ }
+
+ void
+ SkipSpaces ();
+
+ std::string &
+ GetStringRef ()
+ {
+ return m_packet;
+ }
+
+ const std::string &
+ GetStringRef () const
+ {
+ return m_packet;
+ }
+
+ bool
+ Empty()
+ {
+ return m_packet.empty();
+ }
+
+ size_t
+ GetBytesLeft ()
+ {
+ if (m_index < m_packet.size())
+ return m_packet.size() - m_index;
+ return 0;
+ }
+
+ char
+ GetChar (char fail_value = '\0');
+
+ char
+ PeekChar (char fail_value = '\0')
+ {
+ const char *cstr = Peek();
+ if (cstr)
+ return cstr[0];
+ return fail_value;
+ }
+
+ int
+ DecodeHexU8();
+
+ uint8_t
+ GetHexU8 (uint8_t fail_value = 0, bool set_eof_on_fail = true);
+
+ bool
+ GetHexU8Ex (uint8_t& ch, bool set_eof_on_fail = true);
+
+ bool
+ GetNameColonValue (std::string &name, std::string &value);
+
+ int32_t
+ GetS32 (int32_t fail_value, int base = 0);
+
+ uint32_t
+ GetU32 (uint32_t fail_value, int base = 0);
+
+ int64_t
+ GetS64 (int64_t fail_value, int base = 0);
+
+ uint64_t
+ GetU64 (uint64_t fail_value, int base = 0);
+
+ 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);
+
+ size_t
+ GetHexBytesAvail (void *dst, size_t dst_len);
+
+ uint64_t
+ GetHexWithFixedSize (uint32_t byte_size, bool little_endian, uint64_t fail_value);
+
+ size_t
+ GetHexByteString (std::string &str);
+
+ size_t
+ GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length);
+
+ size_t
+ GetHexByteStringTerminatedBy (std::string &str,
+ char terminator);
+
+ const char *
+ Peek ()
+ {
+ if (m_index < m_packet.size())
+ return m_packet.c_str() + m_index;
+ return nullptr;
+ }
+
+protected:
+ //------------------------------------------------------------------
+ // For StdStringExtractor only
+ //------------------------------------------------------------------
+ std::string m_packet; // The string in which to extract data.
+ uint64_t m_index; // When extracting data from a packet, this index
+ // will march along as things get extracted. If set
+ // to UINT64_MAX the end of the packet data was
+ // reached when decoding information
+};
+
+#endif // utility_StringExtractor_h_
--- /dev/null
+//===-- StdStringExtractor.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/StdStringExtractor.h"
+
+// C Includes
+#include <stdlib.h>
+
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+
+static inline int
+xdigit_to_sint (char ch)
+{
+ if (ch >= 'a' && ch <= 'f')
+ return 10 + ch - 'a';
+ if (ch >= 'A' && ch <= 'F')
+ return 10 + ch - 'A';
+ if (ch >= '0' && ch <= '9')
+ return ch - '0';
+ return -1;
+}
+
+//----------------------------------------------------------------------
+// StdStringExtractor constructor
+//----------------------------------------------------------------------
+StdStringExtractor::StdStringExtractor() :
+ m_packet(),
+ m_index (0)
+{
+}
+
+
+StdStringExtractor::StdStringExtractor(const char *packet_cstr) :
+ m_packet(),
+ m_index (0)
+{
+ if (packet_cstr)
+ m_packet.assign (packet_cstr);
+}
+
+
+//----------------------------------------------------------------------
+// StdStringExtractor copy constructor
+//----------------------------------------------------------------------
+StdStringExtractor::StdStringExtractor(const StdStringExtractor& rhs) :
+ m_packet (rhs.m_packet),
+ m_index (rhs.m_index)
+{
+
+}
+
+//----------------------------------------------------------------------
+// StdStringExtractor assignment operator
+//----------------------------------------------------------------------
+const StdStringExtractor&
+StdStringExtractor::operator=(const StdStringExtractor& rhs)
+{
+ if (this != &rhs)
+ {
+ m_packet = rhs.m_packet;
+ m_index = rhs.m_index;
+
+ }
+ return *this;
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+StdStringExtractor::~StdStringExtractor()
+{
+}
+
+
+char
+StdStringExtractor::GetChar (char fail_value)
+{
+ if (m_index < m_packet.size())
+ {
+ char ch = m_packet[m_index];
+ ++m_index;
+ return ch;
+ }
+ m_index = UINT64_MAX;
+ return fail_value;
+}
+
+//----------------------------------------------------------------------
+// If a pair of valid hex digits exist at the head of the
+// StdStringExtractor they are decoded into an unsigned byte and returned
+// by this function
+//
+// If there is not a pair of valid hex digits at the head of the
+// StdStringExtractor, it is left unchanged and -1 is returned
+//----------------------------------------------------------------------
+int
+StdStringExtractor::DecodeHexU8()
+{
+ SkipSpaces();
+ if (GetBytesLeft() < 2)
+ {
+ return -1;
+ }
+ const int hi_nibble = xdigit_to_sint(m_packet[m_index]);
+ const int lo_nibble = xdigit_to_sint(m_packet[m_index+1]);
+ if (hi_nibble == -1 || lo_nibble == -1)
+ {
+ return -1;
+ }
+ m_index += 2;
+ return (uint8_t)((hi_nibble << 4) + lo_nibble);
+}
+
+//----------------------------------------------------------------------
+// Extract an unsigned character from two hex ASCII chars in the packet
+// string, or return fail_value on failure
+//----------------------------------------------------------------------
+uint8_t
+StdStringExtractor::GetHexU8 (uint8_t fail_value, bool set_eof_on_fail)
+{
+ // On success, fail_value will be overwritten with the next
+ // character in the stream
+ GetHexU8Ex(fail_value, set_eof_on_fail);
+ return fail_value;
+}
+
+bool
+StdStringExtractor::GetHexU8Ex (uint8_t& ch, bool set_eof_on_fail)
+{
+ int byte = DecodeHexU8();
+ if (byte == -1)
+ {
+ if (set_eof_on_fail || m_index >= m_packet.size())
+ m_index = UINT64_MAX;
+ // ch should not be changed in case of failure
+ return false;
+ }
+ ch = (uint8_t)byte;
+ return true;
+}
+
+uint32_t
+StdStringExtractor::GetU32 (uint32_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ uint32_t result = static_cast<uint32_t>(::strtoul (cstr, &end, base));
+
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+int32_t
+StdStringExtractor::GetS32 (int32_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ int32_t result = static_cast<int32_t>(::strtol (cstr, &end, base));
+
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+
+uint64_t
+StdStringExtractor::GetU64 (uint64_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ uint64_t result = ::strtoull (cstr, &end, base);
+
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+int64_t
+StdStringExtractor::GetS64 (int64_t fail_value, int base)
+{
+ if (m_index < m_packet.size())
+ {
+ char *end = nullptr;
+ const char *start = m_packet.c_str();
+ const char *cstr = start + m_index;
+ int64_t result = ::strtoll (cstr, &end, base);
+
+ if (end && end != cstr)
+ {
+ m_index = end - start;
+ return result;
+ }
+ }
+ return fail_value;
+}
+
+
+uint32_t
+StdStringExtractor::GetHexMaxU32 (bool little_endian, uint32_t fail_value)
+{
+ uint32_t result = 0;
+ uint32_t nibble_count = 0;
+
+ SkipSpaces();
+ 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 = UINT64_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 = UINT64_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
+StdStringExtractor::GetHexMaxU64 (bool little_endian, uint64_t fail_value)
+{
+ uint64_t result = 0;
+ uint32_t nibble_count = 0;
+
+ SkipSpaces();
+ 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 = UINT64_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 = UINT64_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
+StdStringExtractor::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;
+}
+
+//----------------------------------------------------------------------
+// Decodes all valid hex encoded bytes at the head of the
+// StdStringExtractor, limited by dst_len.
+//
+// Returns the number of bytes successfully decoded
+//----------------------------------------------------------------------
+size_t
+StdStringExtractor::GetHexBytesAvail (void *dst_void, size_t dst_len)
+{
+ uint8_t *dst = (uint8_t*)dst_void;
+ size_t bytes_extracted = 0;
+ while (bytes_extracted < dst_len)
+ {
+ int decode = DecodeHexU8();
+ if (decode == -1)
+ {
+ break;
+ }
+ dst[bytes_extracted++] = (uint8_t)decode;
+ }
+ return bytes_extracted;
+}
+
+// Consume ASCII hex nibble character pairs until we have decoded byte_size
+// bytes of data.
+
+uint64_t
+StdStringExtractor::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 && IsGood();
+ ++i, shift_amount += 8)
+ {
+ result |= ((uint64_t)GetHexU8() << shift_amount);
+ }
+ }
+ else
+ {
+ // Big Endian
+ for (i = 0; i < byte_size && IsGood(); ++i)
+ {
+ result <<= 8;
+ result |= GetHexU8();
+ }
+ }
+ }
+ m_index = UINT64_MAX;
+ return fail_value;
+}
+
+size_t
+StdStringExtractor::GetHexByteString (std::string &str)
+{
+ str.clear();
+ str.reserve(GetBytesLeft() / 2);
+ char ch;
+ while ((ch = GetHexU8()) != '\0')
+ str.append(1, ch);
+ return str.size();
+}
+
+size_t
+StdStringExtractor::GetHexByteStringFixedLength (std::string &str, uint32_t nibble_length)
+{
+ str.clear();
+
+ uint32_t nibble_count = 0;
+ for (const char *pch = Peek(); (nibble_count < nibble_length) && (pch != nullptr); str.append(1, GetHexU8(0, false)), pch = Peek (), nibble_count += 2)
+ {}
+
+ return str.size();
+}
+
+size_t
+StdStringExtractor::GetHexByteStringTerminatedBy (std::string &str,
+ char terminator)
+{
+ str.clear();
+ char ch;
+ while ((ch = GetHexU8(0,false)) != '\0')
+ str.append(1, ch);
+ if (Peek() && *Peek() == terminator)
+ return str.size();
+
+ str.clear();
+ return str.size();
+}
+
+bool
+StdStringExtractor::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 = UINT64_MAX;
+ return false;
+}
+
+void
+StdStringExtractor::SkipSpaces ()
+{
+ const size_t n = m_packet.size();
+ while (m_index < n && isspace(m_packet[m_index]))
+ ++m_index;
+}
+
#include "RNBServices.h"
#include "RNBSocket.h"
#include "JSON.h"
-#include "lldb/Utility/StringExtractor.h"
+#include "lldb/Utility/StdStringExtractor.h"
#include "MacOSX/Genealogy.h"
#include "JSONGenerator.h"
// QSetSTDIN
// QSetSTDOUT
// QSetSTDERR
- StringExtractor packet(p);
+ StdStringExtractor packet(p);
packet.SetFilePos (7);
char ch = packet.GetChar();
while (packet.GetChar() != ':')
// Only set the working directory if we don't already have a process
if (!m_ctx.HasValidProcessID())
{
- StringExtractor packet(p += sizeof ("QSetWorkingDir:") - 1);
+ StdStringExtractor packet(p += sizeof ("QSetWorkingDir:") - 1);
if (packet.GetHexByteString (m_ctx.GetWorkingDir()))
{
struct stat working_dir_stat;
if (g_num_reg_entries == 0)
InitializeRegisters ();
- StringExtractor packet(p);
+ StdStringExtractor packet(p);
packet.SetFilePos(1); // Skip the 'G'
nub_process_t pid = m_ctx.ProcessID();
rnb_err_t
RNBRemote::HandlePacket_AllocateMemory (const char *p)
{
- StringExtractor packet (p);
+ StdStringExtractor packet (p);
packet.SetFilePos(2); // Skip the "_M"
- nub_addr_t size = packet.GetHexMaxU64 (StringExtractor::BigEndian, 0);
+ nub_addr_t size = packet.GetHexMaxU64 (StdStringExtractor::BigEndian, 0);
if (size != 0)
{
if (packet.GetChar() == ',')
rnb_err_t
RNBRemote::HandlePacket_DeallocateMemory (const char *p)
{
- StringExtractor packet (p);
+ StdStringExtractor packet (p);
packet.SetFilePos(2); // Skip the "_m"
- nub_addr_t addr = packet.GetHexMaxU64 (StringExtractor::BigEndian, INVALID_NUB_ADDRESS);
+ nub_addr_t addr = packet.GetHexMaxU64 (StdStringExtractor::BigEndian, INVALID_NUB_ADDRESS);
if (addr != INVALID_NUB_ADDRESS)
{
return HandlePacket_ILLFORMED (__FILE__, __LINE__, p, "No thread was is set with the Hg packet");
}
- StringExtractor packet (p);
+ StdStringExtractor packet (p);
packet.SetFilePos(strlen("QRestoreRegisterState:")); // Skip the "QRestoreRegisterState:"
const uint32_t save_id = packet.GetU32(0);
nub_process_t pid = m_ctx.ProcessID();
- StringExtractor packet (p);
+ StdStringExtractor packet (p);
const char cmd_char = packet.GetChar();
// Register ID is always in big endian
if (pid == INVALID_NUB_PROCESS)
return SendPacket ("OK");
- StringExtractor packet(p += sizeof ("qGetProfileData"));
+ StdStringExtractor packet(p += sizeof ("qGetProfileData"));
DNBProfileDataScanType scan_type = eProfileAll;
std::string name;
std::string value;
if (pid == INVALID_NUB_PROCESS)
return SendPacket ("OK");
- StringExtractor packet(p += sizeof ("QSetEnableAsyncProfiling"));
+ StdStringExtractor packet(p += sizeof ("QSetEnableAsyncProfiling"));
bool enable = false;
uint64_t interval_usec = 0;
DNBProfileDataScanType scan_type = eProfileAll;