brintos

brintos / llvm-project-archived public Read only

0
0
Text · 13.8 KiB · 3283392 Raw
380 lines · cpp
1//===-- MessageObjects.cpp ------------------------------------------------===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "MessageObjects.h"10#include "lldb/Utility/Args.h"11#include "lldb/Utility/StringExtractor.h"12#include "llvm/ADT/StringExtras.h"13#include "gtest/gtest.h"14 15using namespace lldb_private;16using namespace lldb;17using namespace llvm;18namespace llgs_tests {19 20Expected<ProcessInfo> ProcessInfo::create(StringRef response) {21  ProcessInfo process_info;22  auto elements_or_error = SplitUniquePairList("ProcessInfo", response);23  if (!elements_or_error)24    return elements_or_error.takeError();25 26  auto &elements = *elements_or_error;27  if (elements["pid"].getAsInteger(16, process_info.m_pid))28    return make_parsing_error("ProcessInfo: pid");29  if (elements["parent-pid"].getAsInteger(16, process_info.m_parent_pid))30    return make_parsing_error("ProcessInfo: parent-pid");31  if (elements["real-uid"].getAsInteger(16, process_info.m_real_uid))32    return make_parsing_error("ProcessInfo: real-uid");33  if (elements["real-gid"].getAsInteger(16, process_info.m_real_gid))34    return make_parsing_error("ProcessInfo: real-uid");35  if (elements["effective-uid"].getAsInteger(16, process_info.m_effective_uid))36    return make_parsing_error("ProcessInfo: effective-uid");37  if (elements["effective-gid"].getAsInteger(16, process_info.m_effective_gid))38    return make_parsing_error("ProcessInfo: effective-gid");39  if (elements["ptrsize"].getAsInteger(10, process_info.m_ptrsize))40    return make_parsing_error("ProcessInfo: ptrsize");41 42  process_info.m_triple = fromHex(elements["triple"]);43  StringRef endian_str = elements["endian"];44  if (endian_str == "little")45    process_info.m_endian = llvm::endianness::little;46  else if (endian_str == "big")47    process_info.m_endian = llvm::endianness::big;48  else49    return make_parsing_error("ProcessInfo: endian");50 51  return process_info;52}53 54lldb::pid_t ProcessInfo::GetPid() const { return m_pid; }55 56llvm::endianness ProcessInfo::GetEndian() const { return m_endian; }57 58//====== ThreadInfo ============================================================59ThreadInfo::ThreadInfo(StringRef name, StringRef reason, RegisterMap registers,60                       unsigned int)61    : m_name(name.str()), m_reason(reason.str()),62      m_registers(std::move(registers)) {}63 64const RegisterValue *ThreadInfo::ReadRegister(unsigned int Id) const {65  auto Iter = m_registers.find(Id);66  return Iter == m_registers.end() ? nullptr : &Iter->getSecond();67}68 69//====== JThreadsInfo ==========================================================70 71Expected<RegisterMap>72JThreadsInfo::parseRegisters(const StructuredData::Dictionary &Dict,73                             ArrayRef<RegisterInfo> RegInfos) {74  RegisterMap Result;75 76  auto KeysObj = Dict.GetKeys();77  auto Keys = KeysObj->GetAsArray();78  for (size_t i = 0; i < Keys->GetSize(); i++) {79    std::optional<StringRef> MaybeKeyStr = Keys->GetItemAtIndexAsString(i);80    if (!MaybeKeyStr)81      return make_parsing_error("JThreadsInfo: Invalid Key at index {0}", i);82 83    StringRef KeyStr = *MaybeKeyStr;84    StringRef ValueStr;85    Dict.GetValueForKeyAsString(KeyStr, ValueStr);86    unsigned int Register;87    if (!llvm::to_integer(KeyStr, Register, 10))88      return make_parsing_error("JThreadsInfo: register key[{0}]", i);89 90    auto RegValOr =91        parseRegisterValue(RegInfos[Register], ValueStr, llvm::endianness::big);92    if (!RegValOr)93      return RegValOr.takeError();94    Result[Register] = std::move(*RegValOr);95  }96  return std::move(Result);97}98 99Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response,100                                            ArrayRef<RegisterInfo> RegInfos) {101  JThreadsInfo jthreads_info;102 103  StructuredData::ObjectSP json = StructuredData::ParseJSON(Response);104  StructuredData::Array *array = json->GetAsArray();105  if (!array)106    return make_parsing_error("JThreadsInfo: JSON array");107 108  for (size_t i = 0; i < array->GetSize(); i++) {109    std::optional<StructuredData::Dictionary *> maybe_thread_info =110        array->GetItemAtIndexAsDictionary(i);111    if (!maybe_thread_info)112      return make_parsing_error("JThreadsInfo: JSON obj at {0}", i);113 114    StructuredData::Dictionary *thread_info = *maybe_thread_info;115    StringRef name, reason;116    thread_info->GetValueForKeyAsString("name", name);117    thread_info->GetValueForKeyAsString("reason", reason);118    uint64_t signal;119    thread_info->GetValueForKeyAsInteger("signal", signal);120    uint64_t tid;121    thread_info->GetValueForKeyAsInteger("tid", tid);122 123    StructuredData::Dictionary *register_dict;124    thread_info->GetValueForKeyAsDictionary("registers", register_dict);125    if (!register_dict)126      return make_parsing_error("JThreadsInfo: registers JSON obj");127 128    auto RegsOr = parseRegisters(*register_dict, RegInfos);129    if (!RegsOr)130      return RegsOr.takeError();131    jthreads_info.m_thread_infos[tid] =132        ThreadInfo(name, reason, std::move(*RegsOr), signal);133  }134 135  return jthreads_info;136}137 138const ThreadInfoMap &JThreadsInfo::GetThreadInfos() const {139  return m_thread_infos;140}141 142Expected<RegisterInfo> RegisterInfoParser::create(StringRef Response) {143  auto ElementsOr = SplitUniquePairList("RegisterInfoParser", Response);144  if (!ElementsOr)145    return ElementsOr.takeError();146  auto &Elements = *ElementsOr;147 148  RegisterInfo Info = {149      nullptr,       // Name150      nullptr,       // Alt name151      0,             // byte size152      0,             // offset153      eEncodingUint, // encoding154      eFormatHex,    // format155      {156          LLDB_INVALID_REGNUM, // eh_frame reg num157          LLDB_INVALID_REGNUM, // DWARF reg num158          LLDB_INVALID_REGNUM, // generic reg num159          LLDB_INVALID_REGNUM, // process plugin reg num160          LLDB_INVALID_REGNUM  // native register number161      },162      nullptr,163      nullptr,164      nullptr,165  };166  Info.name = ConstString(Elements["name"]).GetCString();167  if (!Info.name)168    return make_parsing_error("qRegisterInfo: name");169 170  Info.alt_name = ConstString(Elements["alt-name"]).GetCString();171 172  if (!to_integer(Elements["bitsize"], Info.byte_size, 10))173    return make_parsing_error("qRegisterInfo: bit-size");174  Info.byte_size /= CHAR_BIT;175 176  if (!to_integer(Elements["offset"], Info.byte_offset, 10))177    Info.byte_offset = LLDB_INVALID_INDEX32;178 179  Info.encoding = Args::StringToEncoding(Elements["encoding"]);180  if (Info.encoding == eEncodingInvalid)181    return make_parsing_error("qRegisterInfo: encoding");182 183  Info.format = StringSwitch<Format>(Elements["format"])184                    .Case("binary", eFormatBinary)185                    .Case("decimal", eFormatDecimal)186                    .Case("hex", eFormatHex)187                    .Case("float", eFormatFloat)188                    .Case("vector-sint8", eFormatVectorOfSInt8)189                    .Case("vector-uint8", eFormatVectorOfUInt8)190                    .Case("vector-sint16", eFormatVectorOfSInt16)191                    .Case("vector-uint16", eFormatVectorOfUInt16)192                    .Case("vector-sint32", eFormatVectorOfSInt32)193                    .Case("vector-uint32", eFormatVectorOfUInt32)194                    .Case("vector-float32", eFormatVectorOfFloat32)195                    .Case("vector-uint64", eFormatVectorOfUInt64)196                    .Case("vector-uint128", eFormatVectorOfUInt128)197                    .Default(eFormatInvalid);198  if (Info.format == eFormatInvalid)199    return make_parsing_error("qRegisterInfo: format");200 201  Info.kinds[eRegisterKindGeneric] =202      Args::StringToGenericRegister(Elements["generic"]);203 204  return std::move(Info);205}206 207Expected<RegisterValue> parseRegisterValue(const RegisterInfo &Info,208                                           StringRef HexValue,209                                           llvm::endianness Endian,210                                           bool ZeroPad) {211  SmallString<128> Storage;212  if (ZeroPad && HexValue.size() < Info.byte_size * 2) {213    Storage.insert(Storage.begin(), Info.byte_size * 2 - HexValue.size(), '0');214    Storage += HexValue;215    HexValue = Storage;216  }217 218  SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2);219  StringExtractor(HexValue).GetHexBytes(Bytes, '\xcc');220  RegisterValue Value;221  Status ST;222  Value.SetFromMemoryData(Info, Bytes.data(), Bytes.size(),223                          Endian == llvm::endianness::little ? eByteOrderLittle224                                                             : eByteOrderBig,225                          ST);226  if (ST.Fail())227    return ST.ToError();228  return Value;229}230 231//====== StopReply =============================================================232Expected<std::unique_ptr<StopReply>>233StopReply::create(StringRef Response, llvm::endianness Endian,234                  ArrayRef<RegisterInfo> RegInfos) {235  if (Response.size() < 3)236    return make_parsing_error("StopReply: Invalid packet");237  if (Response.consume_front("T"))238    return StopReplyStop::create(Response, Endian, RegInfos);239  if (Response.consume_front("W"))240    return StopReplyExit::create(Response);241  return make_parsing_error("StopReply: Invalid packet");242}243 244Expected<RegisterMap> StopReplyStop::parseRegisters(245    const StringMap<SmallVector<StringRef, 2>> &Elements,246    llvm::endianness Endian, ArrayRef<lldb_private::RegisterInfo> RegInfos) {247 248  RegisterMap Result;249  for (const auto &E : Elements) {250    StringRef Key = E.getKey();251    const auto &Val = E.getValue();252    if (Key.size() != 2)253      continue;254 255    unsigned int Reg;256    if (!to_integer(Key, Reg, 16))257      continue;258 259    if (Val.size() != 1)260      return make_parsing_error(261          "StopReplyStop: multiple entries for register field [{0:x}]", Reg);262 263    auto RegValOr = parseRegisterValue(RegInfos[Reg], Val[0], Endian);264    if (!RegValOr)265      return RegValOr.takeError();266    Result[Reg] = std::move(*RegValOr);267  }268  return std::move(Result);269}270 271Expected<std::unique_ptr<StopReplyStop>>272StopReplyStop::create(StringRef Response, llvm::endianness Endian,273                      ArrayRef<RegisterInfo> RegInfos) {274  unsigned int Signal;275  StringRef SignalStr = Response.take_front(2);276  Response = Response.drop_front(2);277  if (!to_integer(SignalStr, Signal, 16))278    return make_parsing_error("StopReply: stop signal");279 280  auto Elements = SplitPairList(Response);281  for (StringRef Field :282       {"name", "reason", "thread", "threads", "thread-pcs"}) {283    // This will insert an empty field if there is none. In the future, we284    // should probably differentiate between these fields not being present and285    // them being empty, but right now no tests depends on this.286    if (Elements.insert({Field, {""}}).first->second.size() != 1)287      return make_parsing_error(288          "StopReply: got multiple responses for the {0} field", Field);289  }290  StringRef Name = Elements["name"][0];291  StringRef Reason = Elements["reason"][0];292 293  lldb::tid_t Thread;294  if (!to_integer(Elements["thread"][0], Thread, 16))295    return make_parsing_error("StopReply: thread");296 297  SmallVector<StringRef, 20> Threads;298  SmallVector<StringRef, 20> Pcs;299  Elements["threads"][0].split(Threads, ',');300  Elements["thread-pcs"][0].split(Pcs, ',');301  if (Threads.size() != Pcs.size())302    return make_parsing_error("StopReply: thread/PC count mismatch");303 304  RegisterMap ThreadPcs;305  const RegisterInfo *PcInfo = find_if(RegInfos, [](const RegisterInfo &Info) {306    return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC;307  });308  assert(PcInfo);309 310  for (auto ThreadPc : zip(Threads, Pcs)) {311    lldb::tid_t Id;312    if (!to_integer(std::get<0>(ThreadPc), Id, 16))313      return make_parsing_error("StopReply: Thread id '{0}'",314                                std::get<0>(ThreadPc));315 316    auto PcOr = parseRegisterValue(*PcInfo, std::get<1>(ThreadPc), Endian,317                                   /*ZeroPad*/ true);318    if (!PcOr)319      return PcOr.takeError();320    ThreadPcs[Id] = std::move(*PcOr);321  }322 323  auto RegistersOr = parseRegisters(Elements, Endian, RegInfos);324  if (!RegistersOr)325    return RegistersOr.takeError();326 327  return std::make_unique<StopReplyStop>(Signal, Thread, Name,328                                          std::move(ThreadPcs),329                                          std::move(*RegistersOr), Reason);330}331 332Expected<std::unique_ptr<StopReplyExit>>333StopReplyExit::create(StringRef Response) {334  uint8_t Status;335  if (!to_integer(Response, Status, 16))336    return make_parsing_error("StopReply: exit status");337  return std::make_unique<StopReplyExit>(Status);338}339 340//====== Globals ===============================================================341Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,342                                                   StringRef str) {343  SmallVector<StringRef, 20> elements;344  str.split(elements, ';');345 346  StringMap<StringRef> pairs;347  for (StringRef s : elements) {348    std::pair<StringRef, StringRef> pair = s.split(':');349    if (pairs.count(pair.first))350      return make_parsing_error("{0}: Duplicate Key: {1}", caller, pair.first);351 352    pairs.insert(pair);353  }354 355  return pairs;356}357 358StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {359  SmallVector<StringRef, 20> elements;360  str.split(elements, ';');361 362  StringMap<SmallVector<StringRef, 2>> pairs;363  for (StringRef s : elements) {364    std::pair<StringRef, StringRef> pair = s.split(':');365    pairs[pair.first].push_back(pair.second);366  }367 368  return pairs;369}370} // namespace llgs_tests371 372std::ostream &lldb_private::operator<<(std::ostream &OS,373                                       const RegisterValue &RegVal) {374  ArrayRef<uint8_t> Bytes(static_cast<const uint8_t *>(RegVal.GetBytes()),375                          RegVal.GetByteSize());376  return OS << formatv("RegisterValue[{0}]: {1:@[x-2]}", RegVal.GetByteSize(),377                       make_range(Bytes.begin(), Bytes.end()))378                   .str();379}380