Vendor import of lldb release_60 branch r325932:
https://llvm.org/svn/llvm-project/lldb/branches/release_60@325932
This commit is contained in:
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
@ -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 ®isters, 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();
|
||||
}
|
||||
|
@ -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 ®isters, 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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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)));
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user