diff options
Diffstat (limited to 'unittests/tools/lldb-server/tests/MessageObjects.cpp')
| -rw-r--r-- | unittests/tools/lldb-server/tests/MessageObjects.cpp | 247 |
1 files changed, 180 insertions, 67 deletions
diff --git a/unittests/tools/lldb-server/tests/MessageObjects.cpp b/unittests/tools/lldb-server/tests/MessageObjects.cpp index e5927d037f985..2ccd6f6123ca1 100644 --- a/unittests/tools/lldb-server/tests/MessageObjects.cpp +++ b/unittests/tools/lldb-server/tests/MessageObjects.cpp @@ -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); +const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const { + auto Iter = m_registers.find(Id); + return Iter == m_registers.end() ? nullptr : &Iter->getSecond(); } -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); +//====== JThreadsInfo ========================================================== + +Expected<RegisterMap> +JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict, + ArrayRef<RegisterInfo> RegInfos) { + RegisterMap Result; - sys::swapByteOrder(value); - return value; + 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); } -//====== JThreadsInfo ========================================================== -Expected<JThreadsInfo> JThreadsInfo::Create(StringRef response, - endianness endian) { +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(); +} |
