summaryrefslogtreecommitdiff
path: root/unittests/tools/lldb-server/tests/MessageObjects.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'unittests/tools/lldb-server/tests/MessageObjects.cpp')
-rw-r--r--unittests/tools/lldb-server/tests/MessageObjects.cpp152
1 files changed, 99 insertions, 53 deletions
diff --git a/unittests/tools/lldb-server/tests/MessageObjects.cpp b/unittests/tools/lldb-server/tests/MessageObjects.cpp
index 6ac067bce0621..e5927d037f985 100644
--- a/unittests/tools/lldb-server/tests/MessageObjects.cpp
+++ b/unittests/tools/lldb-server/tests/MessageObjects.cpp
@@ -19,7 +19,7 @@ namespace llgs_tests {
Expected<ProcessInfo> ProcessInfo::Create(StringRef response) {
ProcessInfo process_info;
- auto elements_or_error = SplitPairList("ProcessInfo", response);
+ auto elements_or_error = SplitUniquePairList("ProcessInfo", response);
if (!elements_or_error)
return elements_or_error.takeError();
@@ -65,19 +65,16 @@ StringRef ThreadInfo::ReadRegister(unsigned int register_id) const {
return m_registers.lookup(register_id);
}
-bool ThreadInfo::ReadRegisterAsUint64(unsigned int register_id,
- uint64_t &value) const {
+Expected<uint64_t>
+ThreadInfo::ReadRegisterAsUint64(unsigned int register_id) const {
+ uint64_t value;
std::string value_str(m_registers.lookup(register_id));
- if (!llvm::to_integer(value_str, value, 16)) {
- GTEST_LOG_(ERROR)
- << formatv("ThreadInfo: Unable to parse register value at {0}.",
- register_id)
- .str();
- return false;
- }
+ if (!llvm::to_integer(value_str, value, 16))
+ return make_parsing_error("ThreadInfo value for register {0}: {1}",
+ register_id, value_str);
sys::swapByteOrder(value);
- return true;
+ return value;
}
//====== JThreadsInfo ==========================================================
@@ -136,60 +133,96 @@ const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const {
}
//====== StopReply =============================================================
-const U64Map &StopReply::GetThreadPcs() const { return m_thread_pcs; }
+Expected<std::unique_ptr<StopReply>>
+StopReply::create(StringRef Response, llvm::support::endianness Endian) {
+ if (Response.size() < 3)
+ return make_parsing_error("StopReply: Invalid packet");
+ if (Response.consume_front("T"))
+ return StopReplyStop::create(Response, Endian);
+ if (Response.consume_front("W"))
+ return StopReplyExit::create(Response);
+ return make_parsing_error("StopReply: Invalid packet");
+}
-Expected<StopReply> StopReply::Create(StringRef response,
- llvm::support::endianness endian) {
- StopReply stop_reply;
+Expected<std::unique_ptr<StopReplyStop>>
+StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) {
+ unsigned int Signal;
+ StringRef SignalStr = Response.take_front(2);
+ Response = Response.drop_front(2);
+ if (!to_integer(SignalStr, Signal, 16))
+ return make_parsing_error("StopReply: stop signal");
+
+ auto Elements = SplitPairList(Response);
+ for (StringRef Field :
+ {"name", "reason", "thread", "threads", "thread-pcs"}) {
+ // This will insert an empty field if there is none. In the future, we
+ // should probably differentiate between these fields not being present and
+ // them being empty, but right now no tests depends on this.
+ if (Elements.insert({Field, {""}}).first->second.size() != 1)
+ return make_parsing_error(
+ "StopReply: got multiple responses for the {0} field", Field);
+ }
+ StringRef Name = Elements["name"][0];
+ StringRef Reason = Elements["reason"][0];
+
+ lldb::tid_t Thread;
+ if (!to_integer(Elements["thread"][0], Thread, 16))
+ return make_parsing_error("StopReply: thread");
+
+ SmallVector<StringRef, 20> Threads;
+ SmallVector<StringRef, 20> Pcs;
+ Elements["threads"][0].split(Threads, ',');
+ Elements["thread-pcs"][0].split(Pcs, ',');
+ if (Threads.size() != Pcs.size())
+ return make_parsing_error("StopReply: thread/PC count mismatch");
- auto elements_or_error = SplitPairList("StopReply", response);
- if (auto split_error = elements_or_error.takeError()) {
- return std::move(split_error);
+ U64Map ThreadPcs;
+ for (auto ThreadPc : zip(Threads, Pcs)) {
+ lldb::tid_t Id;
+ uint64_t Pc;
+ if (!to_integer(std::get<0>(ThreadPc), Id, 16))
+ return make_parsing_error("StopReply: Thread id '{0}'",
+ std::get<0>(ThreadPc));
+ if (!to_integer(std::get<1>(ThreadPc), Pc, 16))
+ return make_parsing_error("StopReply Thread Pc '{0}'",
+ std::get<1>(ThreadPc));
+
+ ThreadPcs[Id] = Pc;
}
- auto elements = *elements_or_error;
- stop_reply.m_name = elements["name"];
- stop_reply.m_reason = elements["reason"];
+ RegisterMap Registers;
+ for (const auto &E : Elements) {
+ StringRef Key = E.getKey();
+ const auto &Val = E.getValue();
+ if (Key.size() != 2)
+ continue;
- SmallVector<StringRef, 20> threads;
- SmallVector<StringRef, 20> pcs;
- elements["threads"].split(threads, ',');
- elements["thread-pcs"].split(pcs, ',');
- if (threads.size() != pcs.size())
- return make_parsing_error("StopReply: thread/PC count mismatch");
+ unsigned int Reg;
+ if (!to_integer(Key, Reg, 16))
+ continue;
- for (size_t i = 0; i < threads.size(); i++) {
- lldb::tid_t thread_id;
- uint64_t pc;
- if (threads[i].getAsInteger(16, thread_id))
- return make_parsing_error("StopReply: thread ID at [{0}].", i);
- if (pcs[i].getAsInteger(16, pc))
- return make_parsing_error("StopReply: thread PC at [{0}].", i);
+ if (Val.size() != 1)
+ return make_parsing_error(
+ "StopReply: multiple entries for register field [{0:x}]", Reg);
- stop_reply.m_thread_pcs[thread_id] = pc;
+ Registers[Reg] = Val[0].str();
}
- for (auto i = elements.begin(); i != elements.end(); i++) {
- StringRef key = i->getKey();
- StringRef val = i->getValue();
- if (key.size() >= 9 && key[0] == 'T' && key.substr(3, 6) == "thread") {
- if (val.getAsInteger(16, stop_reply.m_thread))
- return make_parsing_error("StopReply: thread id");
- if (key.substr(1, 2).getAsInteger(16, stop_reply.m_signal))
- return make_parsing_error("StopReply: stop signal");
- } else if (key.size() == 2) {
- unsigned int reg;
- if (!key.getAsInteger(16, reg)) {
- stop_reply.m_registers[reg] = val.str();
- }
- }
- }
+ return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, ThreadPcs,
+ Registers, Reason);
+}
- return stop_reply;
+Expected<std::unique_ptr<StopReplyExit>>
+StopReplyExit::create(StringRef Response) {
+ uint8_t Status;
+ if (!to_integer(Response, Status, 16))
+ return make_parsing_error("StopReply: exit status");
+ return llvm::make_unique<StopReplyExit>(Status);
}
//====== Globals ===============================================================
-Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) {
+Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,
+ StringRef str) {
SmallVector<StringRef, 20> elements;
str.split(elements, ';');
@@ -199,7 +232,20 @@ Expected<StringMap<StringRef>> SplitPairList(StringRef caller, StringRef str) {
if (pairs.count(pair.first))
return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first);
- pairs.insert(s.split(':'));
+ pairs.insert(pair);
+ }
+
+ return pairs;
+}
+
+StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
+ SmallVector<StringRef, 20> elements;
+ str.split(elements, ';');
+
+ StringMap<SmallVector<StringRef, 2>> pairs;
+ for (StringRef s : elements) {
+ std::pair<StringRef, StringRef> pair = s.split(':');
+ pairs[pair.first].push_back(pair.second);
}
return pairs;