Vendor import of lldb release_60 branch r325932:

https://llvm.org/svn/llvm-project/lldb/branches/release_60@325932
This commit is contained in:
Dimitry Andric 2018-02-24 21:28:02 +00:00
parent 4a80bcabc1
commit adc606d1b7
Notes: svn2git 2020-12-20 02:59:44 +00:00
svn path=/vendor/lldb/dist-release_60/; revision=329939
svn path=/vendor/lldb/lldb-release_600-r326565/; revision=330383; tag=vendor/lldb/lldb-release_600-r326565
5 changed files with 295 additions and 143 deletions

View File

@ -8,16 +8,17 @@
//===----------------------------------------------------------------------===//
#include "MessageObjects.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/Interpreter/Args.h"
#include "lldb/Utility/StringExtractor.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)
@ -53,36 +54,50 @@ Expected<ProcessInfo> ProcessInfo::Create(StringRef response) {
lldb::pid_t ProcessInfo::GetPid() const { return m_pid; }
endianness ProcessInfo::GetEndian() const { return m_endian; }
support::endianness ProcessInfo::GetEndian() const { return m_endian; }
//====== ThreadInfo ============================================================
ThreadInfo::ThreadInfo(StringRef name, StringRef reason,
const RegisterMap &registers, unsigned int signal)
: m_name(name.str()), m_reason(reason.str()), m_registers(registers),
m_signal(signal) {}
ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers,
unsigned int signal)
: m_name(name.str()), m_reason(reason.str()),
m_registers(std::move(registers)), m_signal(signal) {}
StringRef ThreadInfo::ReadRegister(unsigned int register_id) const {
return m_registers.lookup(register_id);
}
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))
return make_parsing_error("ThreadInfo value for register {0}: {1}",
register_id, value_str);
sys::swapByteOrder(value);
return value;
const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const {
auto Iter = m_registers.find(Id);
return Iter == m_registers.end() ? nullptr : &Iter->getSecond();
}
//====== JThreadsInfo ==========================================================
Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response,
endianness endian) {
Expected<RegisterMap>
JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict,
ArrayRef<RegisterInfo> RegInfos) {
RegisterMap Result;
auto KeysObj = Dict.GetKeys();
auto Keys = KeysObj->GetAsArray();
for (size_t i = 0; i < Keys->GetSize(); i++) {
StringRef KeyStr, ValueStr;
Keys->GetItemAtIndexAsString(i, KeyStr);
Dict.GetValueForKeyAsString(KeyStr, ValueStr);
unsigned int Register;
if (!llvm::to_integer(KeyStr, Register, 10))
return make_parsing_error("JThreadsInfo: register key[{0}]", i);
auto RegValOr =
parseRegisterValue(RegInfos[Register], ValueStr, support::big);
if (!RegValOr)
return RegValOr.takeError();
Result[Register] = std::move(*RegValOr);
}
return std::move(Result);
}
Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response,
ArrayRef<RegisterInfo> RegInfos) {
JThreadsInfo jthreads_info;
StructuredData::ObjectSP json = StructuredData::ParseJSON(response);
StructuredData::ObjectSP json = StructuredData::ParseJSON(Response);
StructuredData::Array *array = json->GetAsArray();
if (!array)
return make_parsing_error("JThreadsInfo: JSON array");
@ -106,23 +121,11 @@ Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response,
if (!register_dict)
return make_parsing_error("JThreadsInfo: registers JSON obj");
RegisterMap registers;
auto keys_obj = register_dict->GetKeys();
auto keys = keys_obj->GetAsArray();
for (size_t i = 0; i < keys->GetSize(); i++) {
StringRef key_str, value_str;
keys->GetItemAtIndexAsString(i, key_str);
register_dict->GetValueForKeyAsString(key_str, value_str);
unsigned int register_id;
if (key_str.getAsInteger(10, register_id))
return make_parsing_error("JThreadsInfo: register key[{0}]", i);
registers[register_id] = value_str.str();
}
auto RegsOr = parseRegisters(*register_dict, RegInfos);
if (!RegsOr)
return RegsOr.takeError();
jthreads_info.m_thread_infos[tid] =
ThreadInfo(name, reason, registers, signal);
ThreadInfo(name, reason, std::move(*RegsOr), signal);
}
return jthreads_info;
@ -132,20 +135,130 @@ const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const {
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);
}
Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info,
StringRef HexValue,
llvm::support::endianness Endian) {
SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2);
StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc');
RegisterValue Value;
Status ST;
Value.SetFromMemoryData(
&Info, Bytes.data(), Bytes.size(),
Endian == support::little ? eByteOrderLittle : eByteOrderBig, ST);
if (ST.Fail())
return ST.ToError();
return Value;
}
//====== StopReply =============================================================
Expected<std::unique_ptr<StopReply>>
StopReply::create(StringRef Response, llvm::support::endianness Endian) {
StopReply::create(StringRef Response, llvm::support::endianness Endian,
ArrayRef<RegisterInfo> RegInfos) {
if (Response.size() < 3)
return make_parsing_error("StopReply: Invalid packet");
if (Response.consume_front("T"))
return StopReplyStop::create(Response, Endian);
return StopReplyStop::create(Response, Endian, RegInfos);
if (Response.consume_front("W"))
return StopReplyExit::create(Response);
return make_parsing_error("StopReply: Invalid packet");
}
Expected<RegisterMap> StopReplyStop::parseRegisters(
const StringMap<SmallVector<StringRef, 2>> &Elements,
support::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) {
RegisterMap Result;
for (const auto &E : Elements) {
StringRef Key = E.getKey();
const auto &Val = E.getValue();
if (Key.size() != 2)
continue;
unsigned int Reg;
if (!to_integer(Key, Reg, 16))
continue;
if (Val.size() != 1)
return make_parsing_error(
"StopReplyStop: multiple entries for register field [{0:x}]", Reg);
auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian);
if (!RegValOr)
return RegValOr.takeError();
Result[Reg] = std::move(*RegValOr);
}
return std::move(Result);
}
Expected<std::unique_ptr<StopReplyStop>>
StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) {
StopReplyStop::create(StringRef Response, support::endianness Endian,
ArrayRef<RegisterInfo> RegInfos) {
unsigned int Signal;
StringRef SignalStr = Response.take_front(2);
Response = Response.drop_front(2);
@ -176,40 +289,31 @@ StopReplyStop::create(StringRef Response, llvm::support::endianness Endian) {
if (Threads.size() != Pcs.size())
return make_parsing_error("StopReply: thread/PC count mismatch");
U64Map ThreadPcs;
RegisterMap ThreadPcs;
const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) {
return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC;
});
assert(PcInfo);
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 PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian);
if (!PcOr)
return PcOr.takeError();
ThreadPcs[Id] = std::move(*PcOr);
}
RegisterMap Registers;
for (const auto &E : Elements) {
StringRef Key = E.getKey();
const auto &Val = E.getValue();
if (Key.size() != 2)
continue;
auto RegistersOr = parseRegisters(Elements, Endian, RegInfos);
if (!RegistersOr)
return RegistersOr.takeError();
unsigned int Reg;
if (!to_integer(Key, Reg, 16))
continue;
if (Val.size() != 1)
return make_parsing_error(
"StopReply: multiple entries for register field [{0:x}]", Reg);
Registers[Reg] = Val[0].str();
}
return llvm::make_unique<StopReplyStop>(Signal, Thread, Name, ThreadPcs,
Registers, Reason);
return llvm::make_unique<StopReplyStop>(Signal, Thread, Name,
std::move(ThreadPcs),
std::move(*RegistersOr), Reason);
}
Expected<std::unique_ptr<StopReplyExit>>
@ -251,3 +355,12 @@ StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
return pairs;
}
} // namespace llgs_tests
std::ostream &lldb_private::operator<<(std::ostream &OS,
const RegisterValue &RegVal) {
ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()),
RegVal.GetByteSize());
return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(),
make_range(Bytes.begin(), Bytes.end()))
.str();
}

View File

@ -10,7 +10,9 @@
#ifndef LLDB_SERVER_TESTS_MESSAGEOBJECTS_H
#define LLDB_SERVER_TESTS_MESSAGEOBJECTS_H
#include "lldb/Core/RegisterValue.h"
#include "lldb/Host/Host.h"
#include "lldb/Utility/StructuredData.h"
#include "lldb/lldb-types.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/SmallString.h"
@ -22,12 +24,13 @@
namespace llgs_tests {
class ThreadInfo;
typedef llvm::DenseMap<uint64_t, ThreadInfo> ThreadInfoMap;
typedef llvm::DenseMap<uint64_t, uint64_t> U64Map;
typedef llvm::DenseMap<unsigned int, std::string> RegisterMap;
typedef llvm::DenseMap<unsigned int, lldb_private::RegisterValue> 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;
@ -49,10 +52,9 @@ class ThreadInfo {
public:
ThreadInfo() = default;
ThreadInfo(llvm::StringRef name, llvm::StringRef reason,
const RegisterMap &registers, unsigned int signal);
RegisterMap registers, unsigned int signal);
llvm::StringRef ReadRegister(unsigned int register_id) const;
llvm::Expected<uint64_t> ReadRegisterAsUint64(unsigned int register_id) const;
const lldb_private::RegisterValue *ReadRegister(unsigned int Id) const;
private:
std::string m_name;
@ -61,25 +63,40 @@ class ThreadInfo {
unsigned int m_signal;
};
class JThreadsInfo {
class JThreadsInfo : public Parser<JThreadsInfo> {
public:
static llvm::Expected<JThreadsInfo> Create(llvm::StringRef response,
llvm::support::endianness endian);
static llvm::Expected<JThreadsInfo>
create(llvm::StringRef Response,
llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
const ThreadInfoMap &GetThreadInfos() const;
private:
static llvm::Expected<RegisterMap>
parseRegisters(const lldb_private::StructuredData::Dictionary &Dict,
llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
JThreadsInfo() = default;
ThreadInfoMap m_thread_infos;
};
struct RegisterInfoParser : public Parser<lldb_private::RegisterInfo> {
static llvm::Expected<lldb_private::RegisterInfo>
create(llvm::StringRef Response);
};
llvm::Expected<lldb_private::RegisterValue>
parseRegisterValue(const lldb_private::RegisterInfo &Info,
llvm::StringRef HexValue, llvm::support::endianness Endian);
class StopReply {
public:
StopReply() = default;
virtual ~StopReply() = default;
static llvm::Expected<std::unique_ptr<StopReply>>
create(llvm::StringRef response, llvm::support::endianness endian);
create(llvm::StringRef Response, llvm::support::endianness Endian,
llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
// for llvm::cast<>
virtual lldb_private::WaitStatus getKind() const = 0;
@ -91,15 +108,17 @@ class StopReply {
class StopReplyStop : public StopReply {
public:
StopReplyStop(uint8_t Signal, lldb::tid_t ThreadId, llvm::StringRef Name,
U64Map ThreadPcs, RegisterMap Registers, llvm::StringRef Reason)
RegisterMap ThreadPcs, RegisterMap Registers,
llvm::StringRef Reason)
: Signal(Signal), ThreadId(ThreadId), Name(Name),
ThreadPcs(std::move(ThreadPcs)), Registers(std::move(Registers)),
Reason(Reason) {}
static llvm::Expected<std::unique_ptr<StopReplyStop>>
create(llvm::StringRef response, llvm::support::endianness endian);
create(llvm::StringRef Response, llvm::support::endianness Endian,
llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
const U64Map &getThreadPcs() const { return ThreadPcs; }
const RegisterMap &getThreadPcs() const { return ThreadPcs; }
lldb::tid_t getThreadId() const { return ThreadId; }
// for llvm::cast<>
@ -111,10 +130,15 @@ class StopReplyStop : public StopReply {
}
private:
static llvm::Expected<RegisterMap> parseRegisters(
const llvm::StringMap<llvm::SmallVector<llvm::StringRef, 2>> &Elements,
llvm::support::endianness Endian,
llvm::ArrayRef<lldb_private::RegisterInfo> RegInfos);
uint8_t Signal;
lldb::tid_t ThreadId;
std::string Name;
U64Map ThreadPcs;
RegisterMap ThreadPcs;
RegisterMap Registers;
std::string Reason;
};
@ -156,4 +180,8 @@ llvm::Error make_parsing_error(llvm::StringRef format, Args &&... args) {
} // namespace llgs_tests
namespace lldb_private {
std::ostream &operator<<(std::ostream &OS, const RegisterValue &RegVal);
}
#endif // LLDB_SERVER_TESTS_MESSAGEOBJECTS_H

View File

@ -25,8 +25,7 @@
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());
@ -106,7 +105,7 @@ Expected<std::unique_ptr<TestClient>> TestClient::launchCustom(StringRef Log, Ar
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);
}
@ -136,7 +135,7 @@ Error TestClient::SetInferior(llvm::ArrayRef<std::string> inferior_args) {
return E;
if (Error E = SendMessage("qLaunchSuccess"))
return E;
if (Error E = QueryProcessInfo())
if (Error E = queryProcess())
return E;
return Error::success();
}
@ -155,19 +154,12 @@ Error TestClient::ContinueThread(unsigned long thread_id) {
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;
if (SendMessage("jThreadsInfo", response))
return llvm::None;
auto creation = JThreadsInfo::Create(response, m_process_info->GetEndian());
if (auto create_error = creation.takeError()) {
GTEST_LOG_(ERROR) << toString(std::move(create_error));
return llvm::None;
}
return std::move(*creation);
Expected<JThreadsInfo> TestClient::GetJThreadsInfo() {
return SendMessage<JThreadsInfo>("jThreadsInfo", m_register_infos);
}
const StopReply &TestClient::GetLatestStopReply() {
@ -209,42 +201,42 @@ Error TestClient::SendMessage(StringRef message, std::string &response_string,
}
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;
}
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;
}
auto elements = *elements_or_error;
if (elements["alt-name"] == "pc" || elements["generic"] == "pc") {
m_pc_register = register_id;
break;
}
}
assert(m_pc_register != LLDB_INVALID_REGNUM);
return m_pc_register;
}
llvm::Error TestClient::QueryProcessInfo() {
std::string response;
if (Error E = SendMessage("qProcessInfo", response))
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();
}
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;
}
if (m_pc_register == LLDB_INVALID_REGNUM)
return make_parsing_error("qRegisterInfo: generic");
return Error::success();
}
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();
}
@ -254,7 +246,8 @@ Error TestClient::Continue(StringRef message) {
std::string response;
if (Error E = SendMessage(message, response))
return E;
auto creation = StopReply::create(response, m_process_info->GetEndian());
auto creation = StopReply::create(response, m_process_info->GetEndian(),
m_register_infos);
if (Error E = creation.takeError())
return E;
@ -273,5 +266,3 @@ Error TestClient::Continue(StringRef message) {
}
return Error::success();
}
} // namespace llgs_tests

View File

@ -59,7 +59,7 @@ class TestClient
llvm::Error ContinueAll();
llvm::Error ContinueThread(unsigned long thread_id);
const ProcessInfo &GetProcessInfo();
llvm::Optional<JThreadsInfo> GetJThreadsInfo();
llvm::Expected<JThreadsInfo> GetJThreadsInfo();
const StopReply &GetLatestStopReply();
template <typename T> llvm::Expected<const T &> GetLatestStopReplyAs() {
assert(m_stop_reply);
@ -74,12 +74,18 @@ class TestClient
std::string &response_string);
llvm::Error SendMessage(llvm::StringRef message, std::string &response_string,
PacketResult expected_result);
template <typename P, typename... CreateArgs>
llvm::Expected<typename P::result_type> SendMessage(llvm::StringRef Message,
CreateArgs &&... Args);
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,
@ -88,9 +94,19 @@ class TestClient
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, typename... CreateArgs>
llvm::Expected<typename P::result_type>
TestClient::SendMessage(llvm::StringRef Message, CreateArgs &&... Args) {
std::string ResponseText;
if (llvm::Error E = SendMessage(Message, ResponseText))
return std::move(E);
return P::create(ResponseText, std::forward<CreateArgs>(Args)...);
}
} // namespace llgs_tests
#endif // LLDB_SERVER_TESTS_TESTCLIENT_H

View File

@ -9,13 +9,19 @@
#include "TestBase.h"
#include "TestClient.h"
#include "lldb/Utility/DataExtractor.h"
#include "llvm/Support/FormatVariadic.h"
#include "llvm/Support/Path.h"
#include "llvm/Testing/Support/Error.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include <string>
using namespace llgs_tests;
using namespace lldb_private;
using namespace llvm;
using namespace lldb;
using namespace testing;
TEST_F(StandardStartupTest, TestStopReplyContainsThreadPcs) {
// This inferior spawns 4 threads, then forces a break.
@ -29,7 +35,7 @@ TEST_F(StandardStartupTest, TestStopReplyContainsThreadPcs) {
ASSERT_NE(pc_reg, UINT_MAX);
auto jthreads_info = Client->GetJThreadsInfo();
ASSERT_TRUE(jthreads_info);
ASSERT_THAT_EXPECTED(jthreads_info, Succeeded());
auto stop_reply = Client->GetLatestStopReplyAs<StopReplyStop>();
ASSERT_THAT_EXPECTED(stop_reply, Succeeded());
@ -42,9 +48,7 @@ TEST_F(StandardStartupTest, TestStopReplyContainsThreadPcs) {
unsigned long tid = stop_reply_pc.first;
ASSERT_TRUE(thread_infos.find(tid) != thread_infos.end())
<< "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)
<< "Mismatched PC for thread: " << tid;
EXPECT_THAT(thread_infos[tid].ReadRegister(pc_reg),
Pointee(Eq(stop_reply_pc.second)));
}
}