Index: lldb/include/lldb/Utility/StringExtractor.h =================================================================== --- lldb/include/lldb/Utility/StringExtractor.h +++ lldb/include/lldb/Utility/StringExtractor.h @@ -10,8 +10,11 @@ #define LLDB_UTILITY_STRINGEXTRACTOR_H #include "llvm/ADT/ArrayRef.h" +#include "llvm/ADT/Optional.h" #include "llvm/ADT/StringRef.h" +#include "lldb/lldb-types.h" + #include #include #include @@ -95,6 +98,13 @@ size_t GetHexByteStringTerminatedBy(std::string &str, char terminator); + // Read thread-id in the | "p" ["." ] format, where + // and can be either "-1", "0" or a hex-encoded number. Note that + // the function does not check for incorrect values such as -1.. + // A pair of (llvm::None, llvm::None) is returned for malformed input. + std::pair, llvm::Optional> + GetPidTid(); + bool ConsumeFront(const llvm::StringRef &str); const char *Peek() { Index: lldb/source/Utility/StringExtractor.cpp =================================================================== --- lldb/source/Utility/StringExtractor.cpp +++ lldb/source/Utility/StringExtractor.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Utility/StringExtractor.h" +#include "lldb/lldb-defines.h" #include "llvm/ADT/StringExtras.h" #include @@ -369,3 +370,56 @@ while (m_index < n && llvm::isSpace(m_packet[m_index])) ++m_index; } + +std::pair, llvm::Optional> +StringExtractor::GetPidTid() { + llvm::Optional pid = llvm::None; + llvm::Optional tid = llvm::None; + + SkipSpaces(); + if (m_index < m_packet.size() && m_packet[m_index] == 'p') { + // process identifier + ++m_index; + SkipSpaces(); + if (m_index + 1 < m_packet.size() && m_packet[m_index] == '-' && + m_packet[m_index + 1] == '1') { + // -1 is a special case + m_index += 2; + pid = LLDB_INVALID_PROCESS_ID; + } else { + uint64_t prev_index = m_index; + pid = GetHexMaxU64(false, 0); + if (m_index == prev_index || m_index == UINT64_MAX) { + // if index was not incremented or we overflowed, it failed + pid = llvm::None; + return {pid, tid}; + } + } + + // "." must follow if we expect TID too + SkipSpaces(); + if (!(m_index < m_packet.size() && m_packet[m_index] == '.')) + return {pid, tid}; + ++m_index; + SkipSpaces(); + } + + // thread identifier + if (m_index + 1 < m_packet.size() && m_packet[m_index] == '-' && + m_packet[m_index + 1] == '1') { + // -1 is a special case + m_index += 2; + tid = LLDB_INVALID_PROCESS_ID; + } else { + uint64_t prev_index = m_index; + tid = GetHexMaxU64(false, 0); + if (m_index == prev_index || m_index == UINT64_MAX) { + // if index was not incremented or we overflowed, it failed + // (also reset pid since the value is incorrect) + pid = llvm::None; + tid = llvm::None; + } + } + + return {pid, tid}; +} Index: lldb/unittests/Utility/StringExtractorTest.cpp =================================================================== --- lldb/unittests/Utility/StringExtractorTest.cpp +++ lldb/unittests/Utility/StringExtractorTest.cpp @@ -1,7 +1,9 @@ #include "gtest/gtest.h" +#include "gmock/gmock.h" #include #include "lldb/Utility/StringExtractor.h" +#include "lldb/lldb-defines.h" namespace { class StringExtractorTest : public ::testing::Test {}; @@ -695,3 +697,193 @@ ex.Reset("123456789ABCDEF000"); EXPECT_EQ(0ull, ex.GetHexMaxU64(false, 0)); } + +TEST_F(StringExtractorTest, GetPidTid) { + StringExtractor ex(""); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + // invalid/short values + + ex.Reset("narf"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset(";1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset(".1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("pnarf"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p;1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p.1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p1234."); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p1234.;1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("-2"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p1234.-2"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p-2"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p-2.1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + // overflow + + ex.Reset("p10000000000000000"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p10000000000000000.0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("10000000000000000"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p0.10000000000000000"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + ex.Reset("p10000000000000000.10000000000000000"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, llvm::None)); + + // pure thread id + + ex.Reset("0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, 0)); + + ex.Reset("-1"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, LLDB_INVALID_THREAD_ID)); + + ex.Reset("1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, 0x1234ULL)); + + ex.Reset("123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(llvm::None, 0x123456789ABCDEF0ULL)); + + // pure process id + + ex.Reset("p0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0, llvm::None)); + + ex.Reset("p-1"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(LLDB_INVALID_PROCESS_ID, llvm::None)); + + ex.Reset("p1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x1234ULL, llvm::None)); + + ex.Reset("p123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x123456789ABCDEF0ULL, llvm::None)); + + // combined thread id + process id + + ex.Reset("p0.0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0, 0)); + + ex.Reset("p0.-1"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0, LLDB_INVALID_THREAD_ID)); + + // NB: technically, specific thread with unspecified process is invalid + // but we do not filter that in StringExtractor + + ex.Reset("p0.1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0, 0x1234ULL)); + + ex.Reset("p0.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0, 0x123456789ABCDEF0ULL)); + + ex.Reset("p-1.0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(LLDB_INVALID_PROCESS_ID, 0)); + + ex.Reset("p-1.-1"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(LLDB_INVALID_PROCESS_ID, LLDB_INVALID_THREAD_ID)); + + ex.Reset("p-1.1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(LLDB_INVALID_PROCESS_ID, 0x1234ULL)); + + ex.Reset("p-1.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(LLDB_INVALID_PROCESS_ID, 0x123456789ABCDEF0ULL)); + + ex.Reset("p1234.0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x1234ULL, 0)); + + ex.Reset("p1234.-1"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x1234ULL, LLDB_INVALID_THREAD_ID)); + + ex.Reset("p1234.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x1234ULL, 0x123456789ABCDEF0ULL)); + + ex.Reset("p123456789ABCDEF0.0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0)); + + ex.Reset("p123456789ABCDEF0.-1"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x123456789ABCDEF0ULL, LLDB_INVALID_THREAD_ID)); + + ex.Reset("p123456789ABCDEF0.1234"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0x1234ULL)); + + ex.Reset("p123456789ABCDEF0.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0x123456789ABCDEF0ULL)); + + ex.Reset("p123456789ABCDEF0.123456789ABCDEF0"); + EXPECT_THAT(ex.GetPidTid(), + ::testing::Pair(0x123456789ABCDEF0ULL, 0x123456789ABCDEF0ULL)); +}