//===----------------------------------------------------------------------===//
#include "MessageObjects.h"
+#include "lldb/Interpreter/Args.h"
#include "lldb/Utility/StructuredData.h"
#include "llvm/ADT/StringExtras.h"
#include "gtest/gtest.h"
using namespace lldb_private;
+using namespace lldb;
using namespace llvm;
using namespace llvm::support;
namespace llgs_tests {
-Expected<ProcessInfo> ProcessInfo::Create(StringRef response) {
+Expected<ProcessInfo> ProcessInfo::create(StringRef response) {
ProcessInfo process_info;
auto elements_or_error = SplitUniquePairList("ProcessInfo", response);
if (!elements_or_error)
return m_thread_infos;
}
+Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) {
+ auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response);
+ if (!ElementsOr)
+ return ElementsOr.takeError();
+ auto &Elements = *ElementsOr;
+
+ RegisterInfo Info = {
+ nullptr, // Name
+ nullptr, // Alt name
+ 0, // byte size
+ 0, // offset
+ eEncodingUint, // encoding
+ eFormatHex, // format
+ {
+ LLDB_INVALID_REGNUM, // eh_frame reg num
+ LLDB_INVALID_REGNUM, // DWARF reg num
+ LLDB_INVALID_REGNUM, // generic reg num
+ LLDB_INVALID_REGNUM, // process plugin reg num
+ LLDB_INVALID_REGNUM // native register number
+ },
+ NULL,
+ NULL,
+ NULL, // Dwarf expression opcode bytes pointer
+ 0 // Dwarf expression opcode bytes length
+ };
+ Info.name = ConstString(Elements["name"]).GetCString();
+ if (!Info.name)
+ return make_parsing_error("qRegisterInfo: name");
+
+ Info.alt_name = ConstString(Elements["alt-name"]).GetCString();
+
+ if (!to_integer(Elements["bitsize"], Info.byte_size, 10))
+ return make_parsing_error("qRegisterInfo: bit-size");
+ Info.byte_size /= CHAR_BIT;
+
+ if (!to_integer(Elements["offset"], Info.byte_offset, 10))
+ return make_parsing_error("qRegisterInfo: offset");
+
+ Info.encoding = Args::StringToEncoding(Elements["encoding"]);
+ if (Info.encoding == eEncodingInvalid)
+ return make_parsing_error("qRegisterInfo: encoding");
+
+ Info.format = StringSwitch<Format>(Elements["format"])
+ .Case("binary", eFormatBinary)
+ .Case("decimal", eFormatDecimal)
+ .Case("hex", eFormatHex)
+ .Case("float", eFormatFloat)
+ .Case("vector-sint8", eFormatVectorOfSInt8)
+ .Case("vector-uint8", eFormatVectorOfUInt8)
+ .Case("vector-sint16", eFormatVectorOfSInt16)
+ .Case("vector-uint16", eFormatVectorOfUInt16)
+ .Case("vector-sint32", eFormatVectorOfSInt32)
+ .Case("vector-uint32", eFormatVectorOfUInt32)
+ .Case("vector-float32", eFormatVectorOfFloat32)
+ .Case("vector-uint64", eFormatVectorOfUInt64)
+ .Case("vector-uint128", eFormatVectorOfUInt128)
+ .Default(eFormatInvalid);
+ if (Info.format == eFormatInvalid)
+ return make_parsing_error("qRegisterInfo: format");
+
+ Info.kinds[eRegisterKindGeneric] =
+ Args::StringToGenericRegister(Elements["generic"]);
+
+ return std::move(Info);
+}
+
//====== StopReply =============================================================
Expected<std::unique_ptr<StopReply>>
StopReply::create(StringRef Response, llvm::support::endianness Endian) {
typedef llvm::DenseMap<uint64_t, uint64_t> U64Map;
typedef llvm::DenseMap<unsigned int, std::string> RegisterMap;
-class ProcessInfo {
+template <typename T> struct Parser { using result_type = T; };
+
+class ProcessInfo : public Parser<ProcessInfo> {
public:
- static llvm::Expected<ProcessInfo> Create(llvm::StringRef response);
+ static llvm::Expected<ProcessInfo> create(llvm::StringRef response);
lldb::pid_t GetPid() const;
llvm::support::endianness GetEndian() const;
ThreadInfoMap m_thread_infos;
};
+struct RegisterInfoParser : public Parser<lldb_private::RegisterInfo> {
+ static llvm::Expected<lldb_private::RegisterInfo>
+ create(llvm::StringRef Response);
+};
+
class StopReply {
public:
StopReply() = default;
using namespace lldb;
using namespace lldb_private;
using namespace llvm;
-
-namespace llgs_tests {
+using namespace llgs_tests;
TestClient::TestClient(std::unique_ptr<Connection> Conn) {
SetConnection(Conn.release());
auto Client = std::unique_ptr<TestClient>(new TestClient(std::move(Conn)));
if (!InferiorArgs.empty()) {
- if (Error E = Client->QueryProcessInfo())
+ if (Error E = Client->queryProcess())
return std::move(E);
}
return E;
if (Error E = SendMessage("qLaunchSuccess"))
return E;
- if (Error E = QueryProcessInfo())
+ if (Error E = queryProcess())
return E;
return Error::success();
}
return Continue(formatv("vCont;c:{0:x-}", thread_id).str());
}
-const ProcessInfo &TestClient::GetProcessInfo() { return *m_process_info; }
+const llgs_tests::ProcessInfo &TestClient::GetProcessInfo() {
+ return *m_process_info;
+}
Optional<JThreadsInfo> TestClient::GetJThreadsInfo() {
std::string response;
}
unsigned int TestClient::GetPcRegisterId() {
- if (m_pc_register != UINT_MAX)
- return m_pc_register;
-
- for (unsigned int register_id = 0;; register_id++) {
- std::string message = formatv("qRegisterInfo{0:x-}", register_id).str();
- std::string response;
- if (SendMessage(message, response)) {
- GTEST_LOG_(ERROR) << "Unable to query register ID for PC register.";
- return UINT_MAX;
- }
+ assert(m_pc_register != LLDB_INVALID_REGNUM);
+ return m_pc_register;
+}
- auto elements_or_error = SplitUniquePairList("GetPcRegisterId", response);
- if (auto split_error = elements_or_error.takeError()) {
- GTEST_LOG_(ERROR) << "GetPcRegisterId: Error splitting response: "
- << response;
- return UINT_MAX;
- }
+Error TestClient::qProcessInfo() {
+ m_process_info = None;
+ auto InfoOr = SendMessage<ProcessInfo>("qProcessInfo");
+ if (!InfoOr)
+ return InfoOr.takeError();
+ m_process_info = std::move(*InfoOr);
+ return Error::success();
+}
- auto elements = *elements_or_error;
- if (elements["alt-name"] == "pc" || elements["generic"] == "pc") {
- m_pc_register = register_id;
+Error TestClient::qRegisterInfos() {
+ for (unsigned int Reg = 0;; ++Reg) {
+ std::string Message = formatv("qRegisterInfo{0:x-}", Reg).str();
+ Expected<RegisterInfo> InfoOr = SendMessage<RegisterInfoParser>(Message);
+ if (!InfoOr) {
+ consumeError(InfoOr.takeError());
break;
}
+ m_register_infos.emplace_back(std::move(*InfoOr));
+ if (m_register_infos[Reg].kinds[eRegisterKindGeneric] ==
+ LLDB_REGNUM_GENERIC_PC)
+ m_pc_register = Reg;
}
-
- return m_pc_register;
+ if (m_pc_register == LLDB_INVALID_REGNUM)
+ return make_parsing_error("qRegisterInfo: generic");
+ return Error::success();
}
-llvm::Error TestClient::QueryProcessInfo() {
- std::string response;
- if (Error E = SendMessage("qProcessInfo", response))
+Error TestClient::queryProcess() {
+ if (Error E = qProcessInfo())
+ return E;
+ if (Error E = qRegisterInfos())
return E;
- auto create_or_error = ProcessInfo::Create(response);
- if (!create_or_error)
- return create_or_error.takeError();
- m_process_info = *create_or_error;
return Error::success();
}
}
return Error::success();
}
-
-} // namespace llgs_tests
std::string &response_string);
llvm::Error SendMessage(llvm::StringRef message, std::string &response_string,
PacketResult expected_result);
+
+ template <typename P>
+ llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message);
unsigned int GetPcRegisterId();
private:
TestClient(std::unique_ptr<lldb_private::Connection> Conn);
- llvm::Error QueryProcessInfo();
+ llvm::Error qProcessInfo();
+ llvm::Error qRegisterInfos();
+ llvm::Error queryProcess();
llvm::Error Continue(llvm::StringRef message);
std::string FormatFailedResult(
const std::string &message,
llvm::Optional<ProcessInfo> m_process_info;
std::unique_ptr<StopReply> m_stop_reply;
- unsigned int m_pc_register = UINT_MAX;
+ std::vector<lldb_private::RegisterInfo> m_register_infos;
+ unsigned int m_pc_register = LLDB_INVALID_REGNUM;
};
+template <typename P>
+llvm::Expected<typename P::result_type>
+TestClient::SendMessage(llvm::StringRef Message) {
+ std::string ResponseText;
+ if (llvm::Error E = SendMessage(Message, ResponseText))
+ return std::move(E);
+ return P::create(ResponseText);
+}
+
} // namespace llgs_tests
#endif // LLDB_SERVER_TESTS_TESTCLIENT_H
<< "Thread ID: " << tid << " not in JThreadsInfo.";
auto pc_value = thread_infos[tid].ReadRegisterAsUint64(pc_reg);
ASSERT_THAT_EXPECTED(pc_value, Succeeded());
- ASSERT_EQ(stop_reply_pcs[tid], *pc_value)
+ ASSERT_EQ(stop_reply_pc.second, *pc_value)
<< "Mismatched PC for thread: " << tid;
}
}