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-exception
6//
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(caller: "ProcessInfo", s: response);
23 if (!elements_or_error)
24 return elements_or_error.takeError();
25
26 auto &elements = *elements_or_error;
27 if (elements["pid"].getAsInteger(Radix: 16, Result&: process_info.m_pid))
28 return make_parsing_error(format: "ProcessInfo: pid");
29 if (elements["parent-pid"].getAsInteger(Radix: 16, Result&: process_info.m_parent_pid))
30 return make_parsing_error(format: "ProcessInfo: parent-pid");
31 if (elements["real-uid"].getAsInteger(Radix: 16, Result&: process_info.m_real_uid))
32 return make_parsing_error(format: "ProcessInfo: real-uid");
33 if (elements["real-gid"].getAsInteger(Radix: 16, Result&: process_info.m_real_gid))
34 return make_parsing_error(format: "ProcessInfo: real-uid");
35 if (elements["effective-uid"].getAsInteger(Radix: 16, Result&: process_info.m_effective_uid))
36 return make_parsing_error(format: "ProcessInfo: effective-uid");
37 if (elements["effective-gid"].getAsInteger(Radix: 16, Result&: process_info.m_effective_gid))
38 return make_parsing_error(format: "ProcessInfo: effective-gid");
39 if (elements["ptrsize"].getAsInteger(Radix: 10, Result&: process_info.m_ptrsize))
40 return make_parsing_error(format: "ProcessInfo: ptrsize");
41
42 process_info.m_triple = fromHex(Input: 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 else
49 return make_parsing_error(format: "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(Val: 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(idx: i);
80 if (!MaybeKeyStr)
81 return make_parsing_error(format: "JThreadsInfo: Invalid Key at index {0}", args&: i);
82
83 StringRef KeyStr = *MaybeKeyStr;
84 StringRef ValueStr;
85 Dict.GetValueForKeyAsString(key: KeyStr, result&: ValueStr);
86 unsigned int Register;
87 if (!llvm::to_integer(S: KeyStr, Num&: Register, Base: 10))
88 return make_parsing_error(format: "JThreadsInfo: register key[{0}]", args&: i);
89
90 auto RegValOr =
91 parseRegisterValue(Info: RegInfos[Register], HexValue: ValueStr, Endian: 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(json_text: Response);
104 StructuredData::Array *array = json->GetAsArray();
105 if (!array)
106 return make_parsing_error(format: "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(idx: i);
111 if (!maybe_thread_info)
112 return make_parsing_error(format: "JThreadsInfo: JSON obj at {0}", args&: i);
113
114 StructuredData::Dictionary *thread_info = *maybe_thread_info;
115 StringRef name, reason;
116 thread_info->GetValueForKeyAsString(key: "name", result&: name);
117 thread_info->GetValueForKeyAsString(key: "reason", result&: reason);
118 uint64_t signal;
119 thread_info->GetValueForKeyAsInteger(key: "signal", result&: signal);
120 uint64_t tid;
121 thread_info->GetValueForKeyAsInteger(key: "tid", result&: tid);
122
123 StructuredData::Dictionary *register_dict;
124 thread_info->GetValueForKeyAsDictionary(key: "registers", result&: register_dict);
125 if (!register_dict)
126 return make_parsing_error(format: "JThreadsInfo: registers JSON obj");
127
128 auto RegsOr = parseRegisters(Dict: *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(caller: "RegisterInfoParser", s: Response);
144 if (!ElementsOr)
145 return ElementsOr.takeError();
146 auto &Elements = *ElementsOr;
147
148 RegisterInfo Info = {
149 .name: nullptr, // Name
150 .alt_name: nullptr, // Alt name
151 .byte_size: 0, // byte size
152 .byte_offset: 0, // offset
153 .encoding: eEncodingUint, // encoding
154 .format: eFormatHex, // format
155 .kinds: {
156 LLDB_INVALID_REGNUM, // eh_frame reg num
157 LLDB_INVALID_REGNUM, // DWARF reg num
158 LLDB_INVALID_REGNUM, // generic reg num
159 LLDB_INVALID_REGNUM, // process plugin reg num
160 LLDB_INVALID_REGNUM // native register number
161 },
162 .value_regs: nullptr,
163 .invalidate_regs: nullptr,
164 .flags_type: nullptr,
165 };
166 Info.name = ConstString(Elements["name"]).GetCString();
167 if (!Info.name)
168 return make_parsing_error(format: "qRegisterInfo: name");
169
170 Info.alt_name = ConstString(Elements["alt-name"]).GetCString();
171
172 if (!to_integer(S: Elements["bitsize"], Num&: Info.byte_size, Base: 10))
173 return make_parsing_error(format: "qRegisterInfo: bit-size");
174 Info.byte_size /= CHAR_BIT;
175
176 if (!to_integer(S: Elements["offset"], Num&: Info.byte_offset, Base: 10))
177 Info.byte_offset = LLDB_INVALID_INDEX32;
178
179 Info.encoding = Args::StringToEncoding(s: Elements["encoding"]);
180 if (Info.encoding == eEncodingInvalid)
181 return make_parsing_error(format: "qRegisterInfo: encoding");
182
183 Info.format = StringSwitch<Format>(Elements["format"])
184 .Case(S: "binary", Value: eFormatBinary)
185 .Case(S: "decimal", Value: eFormatDecimal)
186 .Case(S: "hex", Value: eFormatHex)
187 .Case(S: "float", Value: eFormatFloat)
188 .Case(S: "vector-sint8", Value: eFormatVectorOfSInt8)
189 .Case(S: "vector-uint8", Value: eFormatVectorOfUInt8)
190 .Case(S: "vector-sint16", Value: eFormatVectorOfSInt16)
191 .Case(S: "vector-uint16", Value: eFormatVectorOfUInt16)
192 .Case(S: "vector-sint32", Value: eFormatVectorOfSInt32)
193 .Case(S: "vector-uint32", Value: eFormatVectorOfUInt32)
194 .Case(S: "vector-float32", Value: eFormatVectorOfFloat32)
195 .Case(S: "vector-uint64", Value: eFormatVectorOfUInt64)
196 .Case(S: "vector-uint128", Value: eFormatVectorOfUInt128)
197 .Default(Value: eFormatInvalid);
198 if (Info.format == eFormatInvalid)
199 return make_parsing_error(format: "qRegisterInfo: format");
200
201 Info.kinds[eRegisterKindGeneric] =
202 Args::StringToGenericRegister(s: 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(I: Storage.begin(), NumToInsert: Info.byte_size * 2 - HexValue.size(), Elt: '0');
214 Storage += HexValue;
215 HexValue = Storage;
216 }
217
218 SmallVector<uint8_t, 64> Bytes(HexValue.size() / 2);
219 StringExtractor(HexValue).GetHexBytes(dest: Bytes, fail_fill_value: '\xcc');
220 RegisterValue Value;
221 Status ST;
222 Value.SetFromMemoryData(reg_info: Info, src: Bytes.data(), src_len: Bytes.size(),
223 src_byte_order: Endian == llvm::endianness::little ? eByteOrderLittle
224 : eByteOrderBig,
225 error&: 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(format: "StopReply: Invalid packet");
237 if (Response.consume_front(Prefix: "T"))
238 return StopReplyStop::create(Response, Endian, RegInfos);
239 if (Response.consume_front(Prefix: "W"))
240 return StopReplyExit::create(response: Response);
241 return make_parsing_error(format: "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(S: Key, Num&: Reg, Base: 16))
257 continue;
258
259 if (Val.size() != 1)
260 return make_parsing_error(
261 format: "StopReplyStop: multiple entries for register field [{0:x}]", args&: Reg);
262
263 auto RegValOr = parseRegisterValue(Info: RegInfos[Reg], HexValue: 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(N: 2);
276 Response = Response.drop_front(N: 2);
277 if (!to_integer(S: SignalStr, Num&: Signal, Base: 16))
278 return make_parsing_error(format: "StopReply: stop signal");
279
280 auto Elements = SplitPairList(s: 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, we
284 // should probably differentiate between these fields not being present and
285 // them being empty, but right now no tests depends on this.
286 if (Elements.insert(KV: {Field, {""}}).first->second.size() != 1)
287 return make_parsing_error(
288 format: "StopReply: got multiple responses for the {0} field", args&: Field);
289 }
290 StringRef Name = Elements["name"][0];
291 StringRef Reason = Elements["reason"][0];
292
293 lldb::tid_t Thread;
294 if (!to_integer(S: Elements["thread"][0], Num&: Thread, Base: 16))
295 return make_parsing_error(format: "StopReply: thread");
296
297 SmallVector<StringRef, 20> Threads;
298 SmallVector<StringRef, 20> Pcs;
299 Elements["threads"][0].split(A&: Threads, Separator: ',');
300 Elements["thread-pcs"][0].split(A&: Pcs, Separator: ',');
301 if (Threads.size() != Pcs.size())
302 return make_parsing_error(format: "StopReply: thread/PC count mismatch");
303
304 RegisterMap ThreadPcs;
305 const RegisterInfo *PcInfo = find_if(Range&: RegInfos, P: [](const RegisterInfo &Info) {
306 return Info.kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_PC;
307 });
308 assert(PcInfo);
309
310 for (auto ThreadPc : zip(t&: Threads, u&: Pcs)) {
311 lldb::tid_t Id;
312 if (!to_integer(S: std::get<0>(t&: ThreadPc), Num&: Id, Base: 16))
313 return make_parsing_error(format: "StopReply: Thread id '{0}'",
314 args&: std::get<0>(t&: ThreadPc));
315
316 auto PcOr = parseRegisterValue(Info: *PcInfo, HexValue: std::get<1>(t&: 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>(args&: Signal, args&: Thread, args&: Name,
328 args: std::move(ThreadPcs),
329 args: std::move(*RegistersOr), args&: Reason);
330}
331
332Expected<std::unique_ptr<StopReplyExit>>
333StopReplyExit::create(StringRef Response) {
334 uint8_t Status;
335 if (!to_integer(S: Response, Num&: Status, Base: 16))
336 return make_parsing_error(format: "StopReply: exit status");
337 return std::make_unique<StopReplyExit>(args&: Status);
338}
339
340//====== Globals ===============================================================
341Expected<StringMap<StringRef>> SplitUniquePairList(StringRef caller,
342 StringRef str) {
343 SmallVector<StringRef, 20> elements;
344 str.split(A&: elements, Separator: ';');
345
346 StringMap<StringRef> pairs;
347 for (StringRef s : elements) {
348 std::pair<StringRef, StringRef> pair = s.split(Separator: ':');
349 if (pairs.count(Key: pair.first))
350 return make_parsing_error(format: "{0}: Duplicate Key: {1}", args&: caller, args&: pair.first);
351
352 pairs.insert(KV: pair);
353 }
354
355 return pairs;
356}
357
358StringMap<SmallVector<StringRef, 2>> SplitPairList(StringRef str) {
359 SmallVector<StringRef, 20> elements;
360 str.split(A&: elements, Separator: ';');
361
362 StringMap<SmallVector<StringRef, 2>> pairs;
363 for (StringRef s : elements) {
364 std::pair<StringRef, StringRef> pair = s.split(Separator: ':');
365 pairs[pair.first].push_back(Elt: pair.second);
366 }
367
368 return pairs;
369}
370} // namespace llgs_tests
371
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(Fmt: "RegisterValue[{0}]: {1:@[x-2]}", Vals: RegVal.GetByteSize(),
377 Vals: make_range(x: Bytes.begin(), y: Bytes.end()))
378 .str();
379}
380

source code of lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp