diff options
Diffstat (limited to 'source/Utility')
-rw-r--r-- | source/Utility/JSON.cpp | 470 | ||||
-rw-r--r-- | source/Utility/StringExtractor.cpp | 11 | ||||
-rw-r--r-- | source/Utility/StringExtractor.h | 164 | ||||
-rw-r--r-- | source/Utility/StringExtractorGDBRemote.cpp | 8 | ||||
-rw-r--r-- | source/Utility/StringExtractorGDBRemote.h | 4 |
5 files changed, 472 insertions, 185 deletions
diff --git a/source/Utility/JSON.cpp b/source/Utility/JSON.cpp index 0ba8cf4..1e16a5a 100644 --- a/source/Utility/JSON.cpp +++ b/source/Utility/JSON.cpp @@ -9,6 +9,10 @@ #include "lldb/Utility/JSON.h" +#include <limits.h> +#include "lldb/Core/StreamString.h" +#include "lldb/Host/StringConvert.h" + using namespace lldb_private; std::string @@ -33,20 +37,20 @@ JSONString::json_string_quote_metachars (const std::string &s) } JSONString::JSONString () : -JSONValue(JSONValue::Kind::String), -m_data() + JSONValue(JSONValue::Kind::String), + m_data() { } JSONString::JSONString (const char* s) : -JSONValue(JSONValue::Kind::String), -m_data(s ? s : "") + JSONValue(JSONValue::Kind::String), + m_data(s ? s : "") { } JSONString::JSONString (const std::string& s) : -JSONValue(JSONValue::Kind::String), -m_data(s) + JSONValue(JSONValue::Kind::String), + m_data(s) { } @@ -57,25 +61,41 @@ JSONString::Write (Stream& s) } JSONNumber::JSONNumber () : -JSONValue(JSONValue::Kind::Number), -m_data(0) + JSONValue(JSONValue::Kind::Number), + m_is_integer(true), + m_data(0), + m_double(0.0) +{ +} + +JSONNumber::JSONNumber (uint64_t i) : + JSONValue(JSONValue::Kind::Number), + m_is_integer(true), + m_data(i), + m_double(0.0) { } -JSONNumber::JSONNumber (int64_t i) : -JSONValue(JSONValue::Kind::Number), -m_data(i) + +JSONNumber::JSONNumber (double d) : + JSONValue(JSONValue::Kind::Number), + m_is_integer(false), + m_data(0), + m_double(d) { } void JSONNumber::Write (Stream& s) { - s.Printf("%" PRId64, m_data); + if (m_is_integer) + s.Printf("%" PRIu64, m_data); + else + s.Printf("%g", m_double); } JSONTrue::JSONTrue () : -JSONValue(JSONValue::Kind::True) + JSONValue(JSONValue::Kind::True) { } @@ -86,7 +106,7 @@ JSONTrue::Write(Stream& s) } JSONFalse::JSONFalse () : -JSONValue(JSONValue::Kind::False) + JSONValue(JSONValue::Kind::False) { } @@ -97,7 +117,7 @@ JSONFalse::Write(Stream& s) } JSONNull::JSONNull () : -JSONValue(JSONValue::Kind::Null) + JSONValue(JSONValue::Kind::Null) { } @@ -108,7 +128,7 @@ JSONNull::Write(Stream& s) } JSONObject::JSONObject () : -JSONValue(JSONValue::Kind::Object) + JSONValue(JSONValue::Kind::Object) { } @@ -153,7 +173,7 @@ JSONObject::GetObject (const std::string& key) } JSONArray::JSONArray () : -JSONValue(JSONValue::Kind::Array) + JSONValue(JSONValue::Kind::Array) { } @@ -215,3 +235,419 @@ JSONArray::GetNumElements () { return m_elements.size(); } + + +JSONParser::JSONParser (const char *cstr) : + StringExtractor(cstr) +{ +} + +JSONParser::Token +JSONParser::GetToken (std::string &value) +{ + StreamString error; + + value.clear(); + SkipSpaces (); + const uint64_t start_index = m_index; + const char ch = GetChar(); + switch (ch) + { + case '{': return Token::ObjectStart; + case '}': return Token::ObjectEnd; + case '[': return Token::ArrayStart; + case ']': return Token::ArrayEnd; + case ',': return Token::Comma; + case ':': return Token::Colon; + case '\0': return Token::EndOfFile; + case 't': + if (GetChar() == 'r') + if (GetChar() == 'u') + if (GetChar() == 'e') + return Token::True; + break; + + case 'f': + if (GetChar() == 'a') + if (GetChar() == 'l') + if (GetChar() == 's') + if (GetChar() == 'e') + return Token::False; + break; + + case 'n': + if (GetChar() == 'u') + if (GetChar() == 'l') + if (GetChar() == 'l') + return Token::Null; + break; + + case '"': + { + while (1) + { + bool was_escaped = false; + int escaped_ch = GetEscapedChar(was_escaped); + if (escaped_ch == -1) + { + error.Printf("error: an error occurred getting a character from offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + + } + else + { + const bool is_end_quote = escaped_ch == '"'; + const bool is_null = escaped_ch == 0; + if (was_escaped || (!is_end_quote && !is_null)) + { + if (CHAR_MIN <= escaped_ch && escaped_ch <= CHAR_MAX) + { + value.append(1, (char)escaped_ch); + } + else + { + error.Printf("error: wide character support is needed for unicode character 0x%4.4x at offset %" PRIu64, escaped_ch, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + } + else if (is_end_quote) + { + return Token::String; + } + else if (is_null) + { + value = "error: missing end quote for string"; + return Token::Error; + } + } + } + } + break; + + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + { + bool done = false; + bool got_decimal_point = false; + uint64_t exp_index = 0; + bool got_int_digits = (ch >= '0') && (ch <= '9'); + bool got_frac_digits = false; + bool got_exp_digits = false; + while (!done) + { + const char next_ch = PeekChar(); + switch (next_ch) + { + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + if (exp_index != 0) + { + got_exp_digits = true; + } + else if (got_decimal_point) + { + got_frac_digits = true; + } + else + { + got_int_digits = true; + } + ++m_index; // Skip this character + break; + + case '.': + if (got_decimal_point) + { + error.Printf("error: extra decimal point found at offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + else + { + got_decimal_point = true; + ++m_index; // Skip this character + } + break; + + case 'e': + case 'E': + if (exp_index != 0) + { + error.Printf("error: extra expenent character found at offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + else + { + exp_index = m_index; + ++m_index; // Skip this character + } + break; + + case '+': + case '-': + // The '+' and '-' can only come after an exponent character... + if (exp_index == m_index - 1) + { + ++m_index; // Skip the exponent sign character + } + else + { + error.Printf("error: unexpected %c character at offset %" PRIu64, next_ch, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + + default: + done = true; + break; + } + } + + if (m_index > start_index) + { + value = m_packet.substr(start_index, m_index - start_index); + if (got_decimal_point) + { + if (exp_index != 0) + { + // We have an exponent, make sure we got exponent digits + if (got_exp_digits) + { + return Token::Float; + } + else + { + error.Printf("error: got exponent character but no exponent digits at offset in float value \"%s\"", value.c_str()); + value = std::move(error.GetString()); + return Token::Error; + } + } + else + { + // No exponent, but we need at least one decimal after the decimal point + if (got_frac_digits) + { + return Token::Float; + } + else + { + error.Printf("error: no digits after decimal point \"%s\"", value.c_str()); + value = std::move(error.GetString()); + return Token::Error; + } + } + } + else + { + // No decimal point + if (got_int_digits) + { + // We need at least some integer digits to make an integer + return Token::Integer; + } + else + { + error.Printf("error: no digits negate sign \"%s\"", value.c_str()); + value = std::move(error.GetString()); + return Token::Error; + } + } + } + else + { + error.Printf("error: invalid number found at offset %" PRIu64, start_index); + value = std::move(error.GetString()); + return Token::Error; + } + } + break; + default: + break; + } + error.Printf("error: failed to parse token at offset %" PRIu64 " (around character '%c')", start_index, ch); + value = std::move(error.GetString()); + return Token::Error; +} + +int +JSONParser::GetEscapedChar(bool &was_escaped) +{ + was_escaped = false; + const char ch = GetChar(); + if (ch == '\\') + { + was_escaped = true; + const char ch2 = GetChar(); + switch (ch2) + { + case '"': + case '\\': + case '/': + default: + break; + + case 'b': return '\b'; + case 'f': return '\f'; + case 'n': return '\n'; + case 'r': return '\r'; + case 't': return '\t'; + case 'u': + { + const int hi_byte = DecodeHexU8(); + const int lo_byte = DecodeHexU8(); + if (hi_byte >=0 && lo_byte >= 0) + return hi_byte << 8 | lo_byte; + return -1; + } + break; + } + return ch2; + } + return ch; +} + +JSONValue::SP +JSONParser::ParseJSONObject () +{ + // The "JSONParser::Token::ObjectStart" token should have already been consumed + // by the time this function is called + std::unique_ptr<JSONObject> dict_up(new JSONObject()); + + std::string value; + std::string key; + while (1) + { + JSONParser::Token token = GetToken(value); + + if (token == JSONParser::Token::String) + { + key.swap(value); + token = GetToken(value); + if (token == JSONParser::Token::Colon) + { + JSONValue::SP value_sp = ParseJSONValue(); + if (value_sp) + dict_up->SetObject(key, value_sp); + else + break; + } + } + else if (token == JSONParser::Token::ObjectEnd) + { + return JSONValue::SP(dict_up.release()); + } + else if (token == JSONParser::Token::Comma) + { + continue; + } + else + { + break; + } + } + return JSONValue::SP(); +} + +JSONValue::SP +JSONParser::ParseJSONArray () +{ + // The "JSONParser::Token::ObjectStart" token should have already been consumed + // by the time this function is called + std::unique_ptr<JSONArray> array_up(new JSONArray()); + + std::string value; + std::string key; + while (1) + { + JSONValue::SP value_sp = ParseJSONValue(); + if (value_sp) + array_up->AppendObject(value_sp); + else + break; + + JSONParser::Token token = GetToken(value); + if (token == JSONParser::Token::Comma) + { + continue; + } + else if (token == JSONParser::Token::ArrayEnd) + { + return JSONValue::SP(array_up.release()); + } + else + { + break; + } + } + return JSONValue::SP(); +} + +JSONValue::SP +JSONParser::ParseJSONValue () +{ + std::string value; + const JSONParser::Token token = GetToken(value); + switch (token) + { + case JSONParser::Token::ObjectStart: + return ParseJSONObject(); + + case JSONParser::Token::ArrayStart: + return ParseJSONArray(); + + case JSONParser::Token::Integer: + { + bool success = false; + uint64_t uval = StringConvert::ToUInt64(value.c_str(), 0, 0, &success); + if (success) + return JSONValue::SP(new JSONNumber(uval)); + } + break; + + case JSONParser::Token::Float: + { + bool success = false; + double val = StringConvert::ToDouble(value.c_str(), 0.0, &success); + if (success) + return JSONValue::SP(new JSONNumber(val)); + } + break; + + case JSONParser::Token::String: + return JSONValue::SP(new JSONString(value)); + + case JSONParser::Token::True: + return JSONValue::SP(new JSONTrue()); + + case JSONParser::Token::False: + return JSONValue::SP(new JSONFalse()); + + case JSONParser::Token::Null: + return JSONValue::SP(new JSONNull()); + + default: + break; + } + return JSONValue::SP(); + +} diff --git a/source/Utility/StringExtractor.cpp b/source/Utility/StringExtractor.cpp index e82c83d..6302c03 100644 --- a/source/Utility/StringExtractor.cpp +++ b/source/Utility/StringExtractor.cpp @@ -7,7 +7,7 @@ // //===----------------------------------------------------------------------===// -#include "Utility/StringExtractor.h" +#include "lldb/Utility/StringExtractor.h" // C Includes #include <stdlib.h> @@ -476,3 +476,12 @@ StringExtractor::GetNameColonValue (std::string &name, std::string &value) m_index = UINT64_MAX; return false; } + +void +StringExtractor::SkipSpaces () +{ + const size_t n = m_packet.size(); + while (m_index < n && isspace(m_packet[m_index])) + ++m_index; +} + diff --git a/source/Utility/StringExtractor.h b/source/Utility/StringExtractor.h deleted file mode 100644 index 49dfe99..0000000 --- a/source/Utility/StringExtractor.h +++ /dev/null @@ -1,164 +0,0 @@ -//===-- 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> -#include <stdint.h> - -// 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 != 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; - } - - 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'); - - int - DecodeHexU8(); - - uint8_t - GetHexU8 (uint8_t fail_value = 0, 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 StringExtractor 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_ diff --git a/source/Utility/StringExtractorGDBRemote.cpp b/source/Utility/StringExtractorGDBRemote.cpp index aeceaa0..17ee0b6 100644 --- a/source/Utility/StringExtractorGDBRemote.cpp +++ b/source/Utility/StringExtractorGDBRemote.cpp @@ -82,7 +82,7 @@ StringExtractorGDBRemote::GetServerPacketType () const case 'A': return eServerPacketType_A; - + case 'Q': switch (packet_cstr[1]) @@ -122,7 +122,7 @@ StringExtractorGDBRemote::GetServerPacketType () const break; } break; - + case 'q': switch (packet_cstr[1]) { @@ -219,6 +219,10 @@ StringExtractorGDBRemote::GetServerPacketType () const break; } break; + + case 'j': + if (PACKET_MATCHES("jSignalInfo")) return eServerPacketType_jSignalsInfo; + case 'v': if (PACKET_STARTS_WITH("vFile:")) { diff --git a/source/Utility/StringExtractorGDBRemote.h b/source/Utility/StringExtractorGDBRemote.h index beb07e5..475b5a8 100644 --- a/source/Utility/StringExtractorGDBRemote.h +++ b/source/Utility/StringExtractorGDBRemote.h @@ -15,7 +15,7 @@ #include <string> // Other libraries and framework includes // Project includes -#include "Utility/StringExtractor.h" +#include "lldb/Utility/StringExtractor.h" class StringExtractorGDBRemote : public StringExtractor { @@ -118,6 +118,8 @@ public: eServerPacketType_qWatchpointSupportInfoSupported, eServerPacketType_qXfer_auxv_read, + eServerPacketType_jSignalsInfo, + eServerPacketType_vAttach, eServerPacketType_vAttachWait, eServerPacketType_vAttachOrWait, |