diff options
Diffstat (limited to 'unittests/tools/lldb-server/tests/MessageObjects.cpp')
| -rw-r--r-- | unittests/tools/lldb-server/tests/MessageObjects.cpp | 249 | 
1 files changed, 181 insertions, 68 deletions
diff --git a/unittests/tools/lldb-server/tests/MessageObjects.cpp b/unittests/tools/lldb-server/tests/MessageObjects.cpp index e5927d037f98..2ccd6f6123ca 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) {} - -StringRef ThreadInfo::ReadRegister(unsigned int register_id) const { -  return m_registers.lookup(register_id); +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) {} + +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 ========================================================== -  sys::swapByteOrder(value); -  return value; +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);  } -//====== 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; - -    unsigned int Reg; -    if (!to_integer(Key, Reg, 16)) -      continue; +  auto RegistersOr = parseRegisters(Elements, Endian, RegInfos); +  if (!RegistersOr) +    return RegistersOr.takeError(); -    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(); +}  | 
