1//===-- ProtocolRequests.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 "Protocol/ProtocolRequests.h"
10#include "JSONUtils.h"
11#include "lldb/lldb-defines.h"
12#include "llvm/ADT/DenseMap.h"
13#include "llvm/ADT/StringMap.h"
14#include "llvm/ADT/StringRef.h"
15#include "llvm/Support/Base64.h"
16#include "llvm/Support/JSON.h"
17#include <utility>
18
19using namespace llvm;
20
21// The 'env' field is either an object as a map of strings or as an array of
22// strings formatted like 'key=value'.
23static bool parseEnv(const json::Value &Params, StringMap<std::string> &env,
24 json::Path P) {
25 const json::Object *O = Params.getAsObject();
26 if (!O) {
27 P.report(Message: "expected object");
28 return false;
29 }
30
31 const json::Value *value = O->get(K: "env");
32 if (!value)
33 return true;
34
35 if (const json::Object *env_obj = value->getAsObject()) {
36 for (const auto &kv : *env_obj) {
37 const std::optional<StringRef> value = kv.second.getAsString();
38 if (!value) {
39 P.field(Field: "env").field(Field: kv.first).report(Message: "expected string value");
40 return false;
41 }
42 env.insert(KV: {kv.first.str(), value->str()});
43 }
44 return true;
45 }
46
47 if (const json::Array *env_arr = value->getAsArray()) {
48 for (size_t i = 0; i < env_arr->size(); ++i) {
49 const std::optional<StringRef> value = (*env_arr)[i].getAsString();
50 if (!value) {
51 P.field(Field: "env").index(Index: i).report(Message: "expected string");
52 return false;
53 }
54 std::pair<StringRef, StringRef> kv = value->split(Separator: "=");
55 env.insert(KV: {kv.first, kv.second.str()});
56 }
57
58 return true;
59 }
60
61 P.field(Field: "env").report(Message: "invalid format, expected array or object");
62 return false;
63}
64
65static bool parseTimeout(const json::Value &Params, std::chrono::seconds &S,
66 json::Path P) {
67 const json::Object *O = Params.getAsObject();
68 if (!O) {
69 P.report(Message: "expected object");
70 return false;
71 }
72
73 const json::Value *value = O->get(K: "timeout");
74 if (!value)
75 return true;
76 std::optional<double> timeout = value->getAsNumber();
77 if (!timeout) {
78 P.field(Field: "timeout").report(Message: "expected number");
79 return false;
80 }
81
82 S = std::chrono::duration_cast<std::chrono::seconds>(
83 d: std::chrono::duration<double>(*value->getAsNumber()));
84 return true;
85}
86
87static bool
88parseSourceMap(const json::Value &Params,
89 std::vector<std::pair<std::string, std::string>> &sourceMap,
90 json::Path P) {
91 const json::Object *O = Params.getAsObject();
92 if (!O) {
93 P.report(Message: "expected object");
94 return false;
95 }
96
97 const json::Value *value = O->get(K: "sourceMap");
98 if (!value)
99 return true;
100
101 if (const json::Object *map_obj = value->getAsObject()) {
102 for (const auto &kv : *map_obj) {
103 const std::optional<StringRef> value = kv.second.getAsString();
104 if (!value) {
105 P.field(Field: "sourceMap").field(Field: kv.first).report(Message: "expected string value");
106 return false;
107 }
108 sourceMap.emplace_back(args: std::make_pair(x: kv.first.str(), y: value->str()));
109 }
110 return true;
111 }
112
113 if (const json::Array *env_arr = value->getAsArray()) {
114 for (size_t i = 0; i < env_arr->size(); ++i) {
115 const json::Array *kv = (*env_arr)[i].getAsArray();
116 if (!kv) {
117 P.field(Field: "sourceMap").index(Index: i).report(Message: "expected array");
118 return false;
119 }
120 if (kv->size() != 2) {
121 P.field(Field: "sourceMap").index(Index: i).report(Message: "expected array of pairs");
122 return false;
123 }
124 const std::optional<StringRef> first = (*kv)[0].getAsString();
125 if (!first) {
126 P.field(Field: "sourceMap").index(Index: 0).report(Message: "expected string");
127 return false;
128 }
129 const std::optional<StringRef> second = (*kv)[1].getAsString();
130 if (!second) {
131 P.field(Field: "sourceMap").index(Index: 1).report(Message: "expected string");
132 return false;
133 }
134 sourceMap.emplace_back(args: std::make_pair(x: *first, y: second->str()));
135 }
136
137 return true;
138 }
139
140 P.report(Message: "invalid format, expected array or object");
141 return false;
142}
143
144namespace lldb_dap::protocol {
145
146bool fromJSON(const json::Value &Params, CancelArguments &CA, json::Path P) {
147 json::ObjectMapper O(Params, P);
148 return O && O.map(Prop: "requestId", Out&: CA.requestId) &&
149 O.map(Prop: "progressId", Out&: CA.progressId);
150}
151
152bool fromJSON(const json::Value &Params, DisconnectArguments &DA,
153 json::Path P) {
154 json::ObjectMapper O(Params, P);
155 return O && O.mapOptional(Prop: "restart", Out&: DA.restart) &&
156 O.mapOptional(Prop: "terminateDebuggee", Out&: DA.terminateDebuggee) &&
157 O.mapOptional(Prop: "suspendDebuggee", Out&: DA.suspendDebuggee);
158}
159
160bool fromJSON(const json::Value &Params, PathFormat &PF, json::Path P) {
161 auto rawPathFormat = Params.getAsString();
162 if (!rawPathFormat) {
163 P.report(Message: "expected a string");
164 return false;
165 }
166
167 std::optional<PathFormat> pathFormat =
168 StringSwitch<std::optional<PathFormat>>(*rawPathFormat)
169 .Case(S: "path", Value: ePatFormatPath)
170 .Case(S: "uri", Value: ePathFormatURI)
171 .Default(Value: std::nullopt);
172 if (!pathFormat) {
173 P.report(Message: "unexpected value, expected 'path' or 'uri'");
174 return false;
175 }
176
177 PF = *pathFormat;
178 return true;
179}
180
181static const StringMap<ClientFeature> ClientFeatureByKey{
182 {"supportsVariableType", eClientFeatureVariableType},
183 {"supportsVariablePaging", eClientFeatureVariablePaging},
184 {"supportsRunInTerminalRequest", eClientFeatureRunInTerminalRequest},
185 {"supportsMemoryReferences", eClientFeatureMemoryReferences},
186 {"supportsProgressReporting", eClientFeatureProgressReporting},
187 {"supportsInvalidatedEvent", eClientFeatureInvalidatedEvent},
188 {"supportsMemoryEvent", eClientFeatureMemoryEvent},
189 {"supportsArgsCanBeInterpretedByShell",
190 eClientFeatureArgsCanBeInterpretedByShell},
191 {"supportsStartDebuggingRequest", eClientFeatureStartDebuggingRequest},
192 {"supportsANSIStyling", eClientFeatureANSIStyling}};
193
194bool fromJSON(const json::Value &Params, InitializeRequestArguments &IRA,
195 json::Path P) {
196 json::ObjectMapper OM(Params, P);
197 if (!OM)
198 return false;
199
200 const json::Object *O = Params.getAsObject();
201
202 for (auto &kv : ClientFeatureByKey) {
203 const json::Value *value_ref = O->get(K: kv.first());
204 if (!value_ref)
205 continue;
206
207 const std::optional<bool> value = value_ref->getAsBoolean();
208 if (!value) {
209 P.field(Field: kv.first()).report(Message: "expected bool");
210 return false;
211 }
212
213 if (*value)
214 IRA.supportedFeatures.insert(V: kv.second);
215 }
216
217 return OM.map(Prop: "adapterID", Out&: IRA.adapterID) &&
218 OM.map(Prop: "clientID", Out&: IRA.clientID) &&
219 OM.map(Prop: "clientName", Out&: IRA.clientName) && OM.map(Prop: "locale", Out&: IRA.locale) &&
220 OM.map(Prop: "linesStartAt1", Out&: IRA.linesStartAt1) &&
221 OM.map(Prop: "columnsStartAt1", Out&: IRA.columnsStartAt1) &&
222 OM.map(Prop: "pathFormat", Out&: IRA.pathFormat) &&
223 OM.map(Prop: "$__lldb_sourceInitFile", Out&: IRA.lldbExtSourceInitFile);
224}
225
226bool fromJSON(const json::Value &Params, Configuration &C, json::Path P) {
227 json::ObjectMapper O(Params, P);
228 return O.mapOptional(Prop: "debuggerRoot", Out&: C.debuggerRoot) &&
229 O.mapOptional(Prop: "enableAutoVariableSummaries",
230 Out&: C.enableAutoVariableSummaries) &&
231 O.mapOptional(Prop: "enableSyntheticChildDebugging",
232 Out&: C.enableSyntheticChildDebugging) &&
233 O.mapOptional(Prop: "displayExtendedBacktrace",
234 Out&: C.displayExtendedBacktrace) &&
235 O.mapOptional(Prop: "stopOnEntry", Out&: C.stopOnEntry) &&
236 O.mapOptional(Prop: "commandEscapePrefix", Out&: C.commandEscapePrefix) &&
237 O.mapOptional(Prop: "customFrameFormat", Out&: C.customFrameFormat) &&
238 O.mapOptional(Prop: "customThreadFormat", Out&: C.customThreadFormat) &&
239 O.mapOptional(Prop: "sourcePath", Out&: C.sourcePath) &&
240 O.mapOptional(Prop: "initCommands", Out&: C.initCommands) &&
241 O.mapOptional(Prop: "preRunCommands", Out&: C.preRunCommands) &&
242 O.mapOptional(Prop: "postRunCommands", Out&: C.postRunCommands) &&
243 O.mapOptional(Prop: "stopCommands", Out&: C.stopCommands) &&
244 O.mapOptional(Prop: "exitCommands", Out&: C.exitCommands) &&
245 O.mapOptional(Prop: "terminateCommands", Out&: C.terminateCommands) &&
246 O.mapOptional(Prop: "program", Out&: C.program) &&
247 O.mapOptional(Prop: "targetTriple", Out&: C.targetTriple) &&
248 O.mapOptional(Prop: "platformName", Out&: C.platformName) &&
249 parseSourceMap(Params, sourceMap&: C.sourceMap, P) &&
250 parseTimeout(Params, S&: C.timeout, P);
251}
252
253bool fromJSON(const json::Value &Params, BreakpointLocationsArguments &BLA,
254 json::Path P) {
255 json::ObjectMapper O(Params, P);
256 return O && O.map(Prop: "source", Out&: BLA.source) && O.map(Prop: "line", Out&: BLA.line) &&
257 O.mapOptional(Prop: "column", Out&: BLA.column) &&
258 O.mapOptional(Prop: "endLine", Out&: BLA.endLine) &&
259 O.mapOptional(Prop: "endColumn", Out&: BLA.endColumn);
260}
261
262json::Value toJSON(const BreakpointLocationsResponseBody &BLRB) {
263 return json::Object{{.K: "breakpoints", .V: BLRB.breakpoints}};
264}
265
266bool fromJSON(const json::Value &Params, Console &C, json::Path P) {
267 auto oldFormatConsole = Params.getAsBoolean();
268 if (oldFormatConsole) {
269 C = *oldFormatConsole ? eConsoleIntegratedTerminal : eConsoleInternal;
270 return true;
271 }
272 auto newFormatConsole = Params.getAsString();
273 if (!newFormatConsole) {
274 P.report(Message: "expected a string");
275 return false;
276 }
277
278 std::optional<Console> console =
279 StringSwitch<std::optional<Console>>(*newFormatConsole)
280 .Case(S: "internalConsole", Value: eConsoleInternal)
281 .Case(S: "integratedTerminal", Value: eConsoleIntegratedTerminal)
282 .Case(S: "externalTerminal", Value: eConsoleExternalTerminal)
283 .Default(Value: std::nullopt);
284 if (!console) {
285 P.report(Message: "unexpected value, expected 'internalConsole', "
286 "'integratedTerminal' or 'externalTerminal'");
287 return false;
288 }
289
290 C = *console;
291 return true;
292}
293
294bool fromJSON(const json::Value &Params, LaunchRequestArguments &LRA,
295 json::Path P) {
296 json::ObjectMapper O(Params, P);
297 return O && fromJSON(Params, C&: LRA.configuration, P) &&
298 O.mapOptional(Prop: "noDebug", Out&: LRA.noDebug) &&
299 O.mapOptional(Prop: "launchCommands", Out&: LRA.launchCommands) &&
300 O.mapOptional(Prop: "cwd", Out&: LRA.cwd) && O.mapOptional(Prop: "args", Out&: LRA.args) &&
301 O.mapOptional(Prop: "detachOnError", Out&: LRA.detachOnError) &&
302 O.mapOptional(Prop: "disableASLR", Out&: LRA.disableASLR) &&
303 O.mapOptional(Prop: "disableSTDIO", Out&: LRA.disableSTDIO) &&
304 O.mapOptional(Prop: "shellExpandArguments", Out&: LRA.shellExpandArguments) &&
305 O.mapOptional(Prop: "runInTerminal", Out&: LRA.console) &&
306 O.mapOptional(Prop: "console", Out&: LRA.console) && parseEnv(Params, env&: LRA.env, P);
307}
308
309bool fromJSON(const json::Value &Params, AttachRequestArguments &ARA,
310 json::Path P) {
311 json::ObjectMapper O(Params, P);
312 return O && fromJSON(Params, C&: ARA.configuration, P) &&
313 O.mapOptional(Prop: "attachCommands", Out&: ARA.attachCommands) &&
314 O.mapOptional(Prop: "pid", Out&: ARA.pid) &&
315 O.mapOptional(Prop: "waitFor", Out&: ARA.waitFor) &&
316 O.mapOptional(Prop: "gdb-remote-port", Out&: ARA.gdbRemotePort) &&
317 O.mapOptional(Prop: "gdb-remote-hostname", Out&: ARA.gdbRemoteHostname) &&
318 O.mapOptional(Prop: "coreFile", Out&: ARA.coreFile);
319}
320
321bool fromJSON(const json::Value &Params, ContinueArguments &CA, json::Path P) {
322 json::ObjectMapper O(Params, P);
323 return O && O.map(Prop: "threadId", Out&: CA.threadId) &&
324 O.mapOptional(Prop: "singleThread", Out&: CA.singleThread);
325}
326
327json::Value toJSON(const ContinueResponseBody &CRB) {
328 json::Object Body{{.K: "allThreadsContinued", .V: CRB.allThreadsContinued}};
329 return std::move(Body);
330}
331
332bool fromJSON(const json::Value &Params, SetVariableArguments &SVA,
333 json::Path P) {
334 json::ObjectMapper O(Params, P);
335 return O && O.map(Prop: "variablesReference", Out&: SVA.variablesReference) &&
336 O.map(Prop: "name", Out&: SVA.name) && O.map(Prop: "value", Out&: SVA.value) &&
337 O.mapOptional(Prop: "format", Out&: SVA.format);
338}
339
340json::Value toJSON(const SetVariableResponseBody &SVR) {
341 json::Object Body{{.K: "value", .V: SVR.value}};
342
343 if (!SVR.type.empty())
344 Body.insert(E: {.K: "type", .V: SVR.type});
345 if (SVR.variablesReference)
346 Body.insert(E: {.K: "variablesReference", .V: SVR.variablesReference});
347 if (SVR.namedVariables)
348 Body.insert(E: {.K: "namedVariables", .V: SVR.namedVariables});
349 if (SVR.indexedVariables)
350 Body.insert(E: {.K: "indexedVariables", .V: SVR.indexedVariables});
351 if (SVR.memoryReference != LLDB_INVALID_ADDRESS)
352 Body.insert(
353 E: {.K: "memoryReference", .V: EncodeMemoryReference(addr: SVR.memoryReference)});
354 if (SVR.valueLocationReference)
355 Body.insert(E: {.K: "valueLocationReference", .V: SVR.valueLocationReference});
356
357 return json::Value(std::move(Body));
358}
359
360bool fromJSON(const json::Value &Params, ScopesArguments &SCA, json::Path P) {
361 json::ObjectMapper O(Params, P);
362 return O && O.map(Prop: "frameId", Out&: SCA.frameId);
363}
364
365json::Value toJSON(const ScopesResponseBody &SCR) {
366 return json::Object{{.K: "scopes", .V: SCR.scopes}};
367}
368
369bool fromJSON(const json::Value &Params, SourceArguments &SA, json::Path P) {
370 json::ObjectMapper O(Params, P);
371 return O && O.map(Prop: "source", Out&: SA.source) &&
372 O.map(Prop: "sourceReference", Out&: SA.sourceReference);
373}
374
375json::Value toJSON(const SourceResponseBody &SA) {
376 json::Object Result{{.K: "content", .V: SA.content}};
377
378 if (SA.mimeType)
379 Result.insert(E: {.K: "mimeType", .V: SA.mimeType});
380
381 return std::move(Result);
382}
383
384bool fromJSON(const json::Value &Params, NextArguments &NA, json::Path P) {
385 json::ObjectMapper OM(Params, P);
386 return OM && OM.map(Prop: "threadId", Out&: NA.threadId) &&
387 OM.mapOptional(Prop: "singleThread", Out&: NA.singleThread) &&
388 OM.mapOptional(Prop: "granularity", Out&: NA.granularity);
389}
390
391bool fromJSON(const json::Value &Params, StepInArguments &SIA, json::Path P) {
392 json::ObjectMapper OM(Params, P);
393 return OM && OM.map(Prop: "threadId", Out&: SIA.threadId) &&
394 OM.map(Prop: "targetId", Out&: SIA.targetId) &&
395 OM.mapOptional(Prop: "singleThread", Out&: SIA.singleThread) &&
396 OM.mapOptional(Prop: "granularity", Out&: SIA.granularity);
397}
398
399bool fromJSON(const llvm::json::Value &Params, StepInTargetsArguments &SITA,
400 llvm::json::Path P) {
401 json::ObjectMapper OM(Params, P);
402 return OM && OM.map(Prop: "frameId", Out&: SITA.frameId);
403}
404
405llvm::json::Value toJSON(const StepInTargetsResponseBody &SITR) {
406 return llvm::json::Object{{.K: "targets", .V: SITR.targets}};
407}
408
409bool fromJSON(const json::Value &Params, StepOutArguments &SOA, json::Path P) {
410 json::ObjectMapper OM(Params, P);
411 return OM && OM.map(Prop: "threadId", Out&: SOA.threadId) &&
412 OM.mapOptional(Prop: "singleThread", Out&: SOA.singleThread) &&
413 OM.mapOptional(Prop: "granularity", Out&: SOA.granularity);
414}
415
416bool fromJSON(const json::Value &Params, SetBreakpointsArguments &SBA,
417 json::Path P) {
418 json::ObjectMapper O(Params, P);
419 return O && O.map(Prop: "source", Out&: SBA.source) &&
420 O.map(Prop: "breakpoints", Out&: SBA.breakpoints) && O.map(Prop: "lines", Out&: SBA.lines) &&
421 O.map(Prop: "sourceModified", Out&: SBA.sourceModified);
422}
423
424json::Value toJSON(const SetBreakpointsResponseBody &SBR) {
425 return json::Object{{.K: "breakpoints", .V: SBR.breakpoints}};
426}
427
428bool fromJSON(const json::Value &Params, SetFunctionBreakpointsArguments &SFBA,
429 json::Path P) {
430 json::ObjectMapper O(Params, P);
431 return O && O.map(Prop: "breakpoints", Out&: SFBA.breakpoints);
432}
433
434json::Value toJSON(const SetFunctionBreakpointsResponseBody &SFBR) {
435 return json::Object{{.K: "breakpoints", .V: SFBR.breakpoints}};
436}
437
438bool fromJSON(const json::Value &Params,
439 SetInstructionBreakpointsArguments &SIBA, json::Path P) {
440 json::ObjectMapper O(Params, P);
441 return O && O.map(Prop: "breakpoints", Out&: SIBA.breakpoints);
442}
443
444json::Value toJSON(const SetInstructionBreakpointsResponseBody &SIBR) {
445 return json::Object{{.K: "breakpoints", .V: SIBR.breakpoints}};
446}
447
448bool fromJSON(const json::Value &Params, DataBreakpointInfoArguments &DBIA,
449 json::Path P) {
450 json::ObjectMapper O(Params, P);
451 return O && O.map(Prop: "variablesReference", Out&: DBIA.variablesReference) &&
452 O.map(Prop: "name", Out&: DBIA.name) && O.map(Prop: "frameId", Out&: DBIA.frameId) &&
453 O.map(Prop: "bytes", Out&: DBIA.bytes) && O.map(Prop: "asAddress", Out&: DBIA.asAddress) &&
454 O.map(Prop: "mode", Out&: DBIA.mode);
455}
456
457json::Value toJSON(const DataBreakpointInfoResponseBody &DBIRB) {
458 json::Object result{{.K: "dataId", .V: DBIRB.dataId},
459 {.K: "description", .V: DBIRB.description}};
460
461 if (DBIRB.accessTypes)
462 result["accessTypes"] = *DBIRB.accessTypes;
463 if (DBIRB.canPersist)
464 result["canPersist"] = *DBIRB.canPersist;
465
466 return result;
467}
468
469bool fromJSON(const json::Value &Params, SetDataBreakpointsArguments &SDBA,
470 json::Path P) {
471 json::ObjectMapper O(Params, P);
472 return O && O.map(Prop: "breakpoints", Out&: SDBA.breakpoints);
473}
474
475json::Value toJSON(const SetDataBreakpointsResponseBody &SDBR) {
476 return json::Object{{.K: "breakpoints", .V: SDBR.breakpoints}};
477}
478
479bool fromJSON(const json::Value &Params, SetExceptionBreakpointsArguments &Args,
480 json::Path P) {
481 json::ObjectMapper O(Params, P);
482 return O && O.map(Prop: "filters", Out&: Args.filters) &&
483 O.mapOptional(Prop: "filterOptions", Out&: Args.filterOptions);
484}
485
486json::Value toJSON(const SetExceptionBreakpointsResponseBody &B) {
487 json::Object result;
488 if (!B.breakpoints.empty())
489 result.insert(E: {.K: "breakpoints", .V: B.breakpoints});
490 return result;
491}
492
493json::Value toJSON(const ThreadsResponseBody &TR) {
494 return json::Object{{.K: "threads", .V: TR.threads}};
495}
496
497bool fromJSON(const llvm::json::Value &Params, DisassembleArguments &DA,
498 llvm::json::Path P) {
499 json::ObjectMapper O(Params, P);
500 return O &&
501 DecodeMemoryReference(v: Params, key: "memoryReference", out&: DA.memoryReference, path: P,
502 /*required=*/true) &&
503 O.mapOptional(Prop: "offset", Out&: DA.offset) &&
504 O.mapOptional(Prop: "instructionOffset", Out&: DA.instructionOffset) &&
505 O.map(Prop: "instructionCount", Out&: DA.instructionCount) &&
506 O.mapOptional(Prop: "resolveSymbols", Out&: DA.resolveSymbols);
507}
508
509json::Value toJSON(const DisassembleResponseBody &DRB) {
510 return json::Object{{.K: "instructions", .V: DRB.instructions}};
511}
512
513bool fromJSON(const json::Value &Params, ReadMemoryArguments &RMA,
514 json::Path P) {
515 json::ObjectMapper O(Params, P);
516 return O &&
517 DecodeMemoryReference(v: Params, key: "memoryReference", out&: RMA.memoryReference,
518 path: P, /*required=*/true) &&
519 O.map(Prop: "count", Out&: RMA.count) && O.mapOptional(Prop: "offset", Out&: RMA.offset);
520}
521
522json::Value toJSON(const ReadMemoryResponseBody &RMR) {
523 json::Object result{{.K: "address", .V: EncodeMemoryReference(addr: RMR.address)}};
524
525 if (RMR.unreadableBytes != 0)
526 result.insert(E: {.K: "unreadableBytes", .V: RMR.unreadableBytes});
527 if (!RMR.data.empty())
528 result.insert(E: {.K: "data", .V: llvm::encodeBase64(Bytes: RMR.data)});
529
530 return result;
531}
532
533bool fromJSON(const json::Value &Params, ModulesArguments &MA, json::Path P) {
534 json::ObjectMapper O(Params, P);
535 return O && O.mapOptional(Prop: "startModule", Out&: MA.startModule) &&
536 O.mapOptional(Prop: "moduleCount", Out&: MA.moduleCount);
537}
538
539json::Value toJSON(const ModulesResponseBody &MR) {
540 json::Object result{{.K: "modules", .V: MR.modules}};
541 if (MR.totalModules != 0)
542 result.insert(E: {.K: "totalModules", .V: MR.totalModules});
543
544 return result;
545}
546
547bool fromJSON(const json::Value &Param, VariablesArguments::VariablesFilter &VA,
548 json::Path Path) {
549 auto rawFilter = Param.getAsString();
550 if (!rawFilter) {
551 Path.report(Message: "expected a string");
552 return false;
553 }
554 std::optional<VariablesArguments::VariablesFilter> filter =
555 StringSwitch<std::optional<VariablesArguments::VariablesFilter>>(
556 *rawFilter)
557 .Case(S: "indexed", Value: VariablesArguments::eVariablesFilterIndexed)
558 .Case(S: "named", Value: VariablesArguments::eVariablesFilterNamed)
559 .Default(Value: std::nullopt);
560 if (!filter) {
561 Path.report(Message: "unexpected value, expected 'named' or 'indexed'");
562 return false;
563 }
564
565 VA = *filter;
566 return true;
567}
568
569bool fromJSON(const json::Value &Param, VariablesArguments &VA,
570 json::Path Path) {
571 json::ObjectMapper O(Param, Path);
572 return O && O.map(Prop: "variablesReference", Out&: VA.variablesReference) &&
573 O.mapOptional(Prop: "filter", Out&: VA.filter) &&
574 O.mapOptional(Prop: "start", Out&: VA.start) && O.mapOptional(Prop: "count", Out&: VA.count) &&
575 O.mapOptional(Prop: "format", Out&: VA.format);
576}
577
578json::Value toJSON(const VariablesResponseBody &VRB) {
579 return json::Object{{.K: "variables", .V: VRB.variables}};
580}
581
582bool fromJSON(const json::Value &Params, WriteMemoryArguments &WMA,
583 json::Path P) {
584 json::ObjectMapper O(Params, P);
585
586 return O &&
587 DecodeMemoryReference(v: Params, key: "memoryReference", out&: WMA.memoryReference,
588 path: P, /*required=*/true) &&
589 O.mapOptional(Prop: "allowPartial", Out&: WMA.allowPartial) &&
590 O.mapOptional(Prop: "offset", Out&: WMA.offset) && O.map(Prop: "data", Out&: WMA.data);
591}
592
593json::Value toJSON(const WriteMemoryResponseBody &WMR) {
594 json::Object result;
595
596 if (WMR.bytesWritten != 0)
597 result.insert(E: {.K: "bytesWritten", .V: WMR.bytesWritten});
598 return result;
599}
600
601} // namespace lldb_dap::protocol
602

source code of lldb/tools/lldb-dap/Protocol/ProtocolRequests.cpp