1//===-- ProtocolTypes.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/ProtocolTypes.h"
10#include "JSONUtils.h"
11#include "lldb/lldb-types.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/ADT/StringRef.h"
14#include "llvm/Support/ErrorHandling.h"
15#include "llvm/Support/JSON.h"
16#include <optional>
17
18using namespace llvm;
19
20namespace lldb_dap::protocol {
21
22bool fromJSON(const json::Value &Params, Source::PresentationHint &PH,
23 json::Path P) {
24 auto rawHint = Params.getAsString();
25 if (!rawHint) {
26 P.report(Message: "expected a string");
27 return false;
28 }
29 std::optional<Source::PresentationHint> hint =
30 StringSwitch<std::optional<Source::PresentationHint>>(*rawHint)
31 .Case(S: "normal", Value: Source::eSourcePresentationHintNormal)
32 .Case(S: "emphasize", Value: Source::eSourcePresentationHintEmphasize)
33 .Case(S: "deemphasize", Value: Source::eSourcePresentationHintDeemphasize)
34 .Default(Value: std::nullopt);
35 if (!hint) {
36 P.report(Message: "unexpected value");
37 return false;
38 }
39 PH = *hint;
40 return true;
41}
42
43bool fromJSON(const json::Value &Params, Source &S, json::Path P) {
44 json::ObjectMapper O(Params, P);
45 return O && O.map(Prop: "name", Out&: S.name) && O.map(Prop: "path", Out&: S.path) &&
46 O.map(Prop: "presentationHint", Out&: S.presentationHint) &&
47 O.map(Prop: "sourceReference", Out&: S.sourceReference);
48}
49
50llvm::json::Value toJSON(Source::PresentationHint hint) {
51 switch (hint) {
52 case Source::eSourcePresentationHintNormal:
53 return "normal";
54 case Source::eSourcePresentationHintEmphasize:
55 return "emphasize";
56 case Source::eSourcePresentationHintDeemphasize:
57 return "deemphasize";
58 }
59 llvm_unreachable("unhandled presentation hint.");
60}
61
62llvm::json::Value toJSON(const Source &S) {
63 json::Object result;
64 if (S.name)
65 result.insert(E: {.K: "name", .V: *S.name});
66 if (S.path)
67 result.insert(E: {.K: "path", .V: *S.path});
68 if (S.sourceReference)
69 result.insert(E: {.K: "sourceReference", .V: *S.sourceReference});
70 if (S.presentationHint)
71 result.insert(E: {.K: "presentationHint", .V: *S.presentationHint});
72
73 return result;
74}
75
76bool fromJSON(const llvm::json::Value &Params, ExceptionBreakpointsFilter &EBF,
77 llvm::json::Path P) {
78 json::ObjectMapper O(Params, P);
79 return O && O.map(Prop: "filter", Out&: EBF.filter) && O.map(Prop: "label", Out&: EBF.label) &&
80 O.mapOptional(Prop: "description", Out&: EBF.description) &&
81 O.mapOptional(Prop: "default", Out&: EBF.defaultState) &&
82 O.mapOptional(Prop: "supportsCondition", Out&: EBF.supportsCondition) &&
83 O.mapOptional(Prop: "conditionDescription", Out&: EBF.conditionDescription);
84}
85
86json::Value toJSON(const ExceptionBreakpointsFilter &EBF) {
87 json::Object result{{.K: "filter", .V: EBF.filter}, {.K: "label", .V: EBF.label}};
88
89 if (EBF.description)
90 result.insert(E: {.K: "description", .V: *EBF.description});
91 if (EBF.defaultState)
92 result.insert(E: {.K: "default", .V: *EBF.defaultState});
93 if (EBF.supportsCondition)
94 result.insert(E: {.K: "supportsCondition", .V: *EBF.supportsCondition});
95 if (EBF.conditionDescription)
96 result.insert(E: {.K: "conditionDescription", .V: *EBF.conditionDescription});
97
98 return result;
99}
100
101bool fromJSON(const json::Value &Params, ColumnType &CT, json::Path P) {
102 auto rawColumnType = Params.getAsString();
103 if (!rawColumnType) {
104 P.report(Message: "expected a string");
105 return false;
106 }
107 std::optional<ColumnType> columnType =
108 StringSwitch<std::optional<ColumnType>>(*rawColumnType)
109 .Case(S: "string", Value: eColumnTypeString)
110 .Case(S: "number", Value: eColumnTypeNumber)
111 .Case(S: "boolean", Value: eColumnTypeBoolean)
112 .Case(S: "unixTimestampUTC", Value: eColumnTypeTimestamp)
113 .Default(Value: std::nullopt);
114 if (!columnType) {
115 P.report(Message: "unexpected value, expected 'string', 'number', 'boolean', or "
116 "'unixTimestampUTC'");
117 return false;
118 }
119 CT = *columnType;
120 return true;
121}
122
123json::Value toJSON(const ColumnType &T) {
124 switch (T) {
125 case eColumnTypeString:
126 return "string";
127 case eColumnTypeNumber:
128 return "number";
129 case eColumnTypeBoolean:
130 return "boolean";
131 case eColumnTypeTimestamp:
132 return "unixTimestampUTC";
133 }
134 llvm_unreachable("unhandled column type.");
135}
136
137bool fromJSON(const llvm::json::Value &Params, ColumnDescriptor &CD,
138 llvm::json::Path P) {
139 llvm::json::ObjectMapper O(Params, P);
140 return O && O.map(Prop: "attributeName", Out&: CD.attributeName) &&
141 O.map(Prop: "label", Out&: CD.label) && O.mapOptional(Prop: "format", Out&: CD.format) &&
142 O.mapOptional(Prop: "type", Out&: CD.type) && O.mapOptional(Prop: "width", Out&: CD.width);
143}
144
145json::Value toJSON(const ColumnDescriptor &CD) {
146 json::Object result{{.K: "attributeName", .V: CD.attributeName}, {.K: "label", .V: CD.label}};
147
148 if (CD.format)
149 result.insert(E: {.K: "format", .V: *CD.format});
150 if (CD.type)
151 result.insert(E: {.K: "type", .V: *CD.type});
152 if (CD.width)
153 result.insert(E: {.K: "width", .V: *CD.width});
154
155 return result;
156}
157
158json::Value toJSON(const ChecksumAlgorithm &CA) {
159 switch (CA) {
160 case eChecksumAlgorithmMD5:
161 return "MD5";
162 case eChecksumAlgorithmSHA1:
163 return "SHA1";
164 case eChecksumAlgorithmSHA256:
165 return "SHA256";
166 case eChecksumAlgorithmTimestamp:
167 return "timestamp";
168 }
169 llvm_unreachable("unhandled checksum algorithm.");
170}
171
172bool fromJSON(const llvm::json::Value &Params, ChecksumAlgorithm &CA,
173 llvm::json::Path P) {
174 auto rawAlgorithm = Params.getAsString();
175 if (!rawAlgorithm) {
176 P.report(Message: "expected a string");
177 return false;
178 }
179
180 std::optional<ChecksumAlgorithm> algorithm =
181 llvm::StringSwitch<std::optional<ChecksumAlgorithm>>(*rawAlgorithm)
182 .Case(S: "MD5", Value: eChecksumAlgorithmMD5)
183 .Case(S: "SHA1", Value: eChecksumAlgorithmSHA1)
184 .Case(S: "SHA256", Value: eChecksumAlgorithmSHA256)
185 .Case(S: "timestamp", Value: eChecksumAlgorithmTimestamp)
186 .Default(Value: std::nullopt);
187
188 if (!algorithm) {
189 P.report(
190 Message: "unexpected value, expected 'MD5', 'SHA1', 'SHA256', or 'timestamp'");
191 return false;
192 }
193
194 CA = *algorithm;
195 return true;
196}
197
198json::Value toJSON(const BreakpointModeApplicability &BMA) {
199 switch (BMA) {
200 case eBreakpointModeApplicabilitySource:
201 return "source";
202 case eBreakpointModeApplicabilityException:
203 return "exception";
204 case eBreakpointModeApplicabilityData:
205 return "data";
206 case eBreakpointModeApplicabilityInstruction:
207 return "instruction";
208 }
209 llvm_unreachable("unhandled breakpoint mode applicability.");
210}
211
212bool fromJSON(const llvm::json::Value &Params, BreakpointModeApplicability &BMA,
213 llvm::json::Path P) {
214 auto rawApplicability = Params.getAsString();
215 if (!rawApplicability) {
216 P.report(Message: "expected a string");
217 return false;
218 }
219 std::optional<BreakpointModeApplicability> applicability =
220 llvm::StringSwitch<std::optional<BreakpointModeApplicability>>(
221 *rawApplicability)
222 .Case(S: "source", Value: eBreakpointModeApplicabilitySource)
223 .Case(S: "exception", Value: eBreakpointModeApplicabilityException)
224 .Case(S: "data", Value: eBreakpointModeApplicabilityData)
225 .Case(S: "instruction", Value: eBreakpointModeApplicabilityInstruction)
226 .Default(Value: std::nullopt);
227 if (!applicability) {
228 P.report(Message: "unexpected value, expected 'source', 'exception', 'data', or "
229 "'instruction'");
230 return false;
231 }
232 BMA = *applicability;
233 return true;
234}
235
236json::Value toJSON(const BreakpointMode &BM) {
237 json::Object result{
238 {.K: "mode", .V: BM.mode},
239 {.K: "label", .V: BM.label},
240 {.K: "appliesTo", .V: BM.appliesTo},
241 };
242
243 if (BM.description)
244 result.insert(E: {.K: "description", .V: *BM.description});
245
246 return result;
247}
248
249bool fromJSON(const llvm::json::Value &Params, BreakpointMode &BM,
250 llvm::json::Path P) {
251 llvm::json::ObjectMapper O(Params, P);
252 return O && O.map(Prop: "mode", Out&: BM.mode) && O.map(Prop: "label", Out&: BM.label) &&
253 O.mapOptional(Prop: "description", Out&: BM.description) &&
254 O.map(Prop: "appliesTo", Out&: BM.appliesTo);
255}
256
257static llvm::StringLiteral ToString(AdapterFeature feature) {
258 switch (feature) {
259 case eAdapterFeatureANSIStyling:
260 return "supportsANSIStyling";
261 case eAdapterFeatureBreakpointLocationsRequest:
262 return "supportsBreakpointLocationsRequest";
263 case eAdapterFeatureCancelRequest:
264 return "supportsCancelRequest";
265 case eAdapterFeatureClipboardContext:
266 return "supportsClipboardContext";
267 case eAdapterFeatureCompletionsRequest:
268 return "supportsCompletionsRequest";
269 case eAdapterFeatureConditionalBreakpoints:
270 return "supportsConditionalBreakpoints";
271 case eAdapterFeatureConfigurationDoneRequest:
272 return "supportsConfigurationDoneRequest";
273 case eAdapterFeatureDataBreakpointBytes:
274 return "supportsDataBreakpointBytes";
275 case eAdapterFeatureDataBreakpoints:
276 return "supportsDataBreakpoints";
277 case eAdapterFeatureDelayedStackTraceLoading:
278 return "supportsDelayedStackTraceLoading";
279 case eAdapterFeatureDisassembleRequest:
280 return "supportsDisassembleRequest";
281 case eAdapterFeatureEvaluateForHovers:
282 return "supportsEvaluateForHovers";
283 case eAdapterFeatureExceptionFilterOptions:
284 return "supportsExceptionFilterOptions";
285 case eAdapterFeatureExceptionInfoRequest:
286 return "supportsExceptionInfoRequest";
287 case eAdapterFeatureExceptionOptions:
288 return "supportsExceptionOptions";
289 case eAdapterFeatureFunctionBreakpoints:
290 return "supportsFunctionBreakpoints";
291 case eAdapterFeatureGotoTargetsRequest:
292 return "supportsGotoTargetsRequest";
293 case eAdapterFeatureHitConditionalBreakpoints:
294 return "supportsHitConditionalBreakpoints";
295 case eAdapterFeatureInstructionBreakpoints:
296 return "supportsInstructionBreakpoints";
297 case eAdapterFeatureLoadedSourcesRequest:
298 return "supportsLoadedSourcesRequest";
299 case eAdapterFeatureLogPoints:
300 return "supportsLogPoints";
301 case eAdapterFeatureModulesRequest:
302 return "supportsModulesRequest";
303 case eAdapterFeatureReadMemoryRequest:
304 return "supportsReadMemoryRequest";
305 case eAdapterFeatureRestartFrame:
306 return "supportsRestartFrame";
307 case eAdapterFeatureRestartRequest:
308 return "supportsRestartRequest";
309 case eAdapterFeatureSetExpression:
310 return "supportsSetExpression";
311 case eAdapterFeatureSetVariable:
312 return "supportsSetVariable";
313 case eAdapterFeatureSingleThreadExecutionRequests:
314 return "supportsSingleThreadExecutionRequests";
315 case eAdapterFeatureStepBack:
316 return "supportsStepBack";
317 case eAdapterFeatureStepInTargetsRequest:
318 return "supportsStepInTargetsRequest";
319 case eAdapterFeatureSteppingGranularity:
320 return "supportsSteppingGranularity";
321 case eAdapterFeatureTerminateRequest:
322 return "supportsTerminateRequest";
323 case eAdapterFeatureTerminateThreadsRequest:
324 return "supportsTerminateThreadsRequest";
325 case eAdapterFeatureSuspendDebuggee:
326 return "supportSuspendDebuggee";
327 case eAdapterFeatureValueFormattingOptions:
328 return "supportsValueFormattingOptions";
329 case eAdapterFeatureWriteMemoryRequest:
330 return "supportsWriteMemoryRequest";
331 case eAdapterFeatureTerminateDebuggee:
332 return "supportTerminateDebuggee";
333 }
334 llvm_unreachable("unhandled adapter feature.");
335}
336
337llvm::json::Value toJSON(const AdapterFeature &feature) {
338 return ToString(feature);
339}
340
341bool fromJSON(const llvm::json::Value &Params, AdapterFeature &feature,
342 llvm::json::Path P) {
343 auto rawFeature = Params.getAsString();
344 if (!rawFeature) {
345 P.report(Message: "expected a string");
346 return false;
347 }
348
349 std::optional<AdapterFeature> parsedFeature =
350 llvm::StringSwitch<std::optional<AdapterFeature>>(*rawFeature)
351 .Case(S: "supportsANSIStyling", Value: eAdapterFeatureANSIStyling)
352 .Case(S: "supportsBreakpointLocationsRequest",
353 Value: eAdapterFeatureBreakpointLocationsRequest)
354 .Case(S: "supportsCancelRequest", Value: eAdapterFeatureCancelRequest)
355 .Case(S: "supportsClipboardContext", Value: eAdapterFeatureClipboardContext)
356 .Case(S: "supportsCompletionsRequest", Value: eAdapterFeatureCompletionsRequest)
357 .Case(S: "supportsConditionalBreakpoints",
358 Value: eAdapterFeatureConditionalBreakpoints)
359 .Case(S: "supportsConfigurationDoneRequest",
360 Value: eAdapterFeatureConfigurationDoneRequest)
361 .Case(S: "supportsDataBreakpointBytes",
362 Value: eAdapterFeatureDataBreakpointBytes)
363 .Case(S: "supportsDataBreakpoints", Value: eAdapterFeatureDataBreakpoints)
364 .Case(S: "supportsDelayedStackTraceLoading",
365 Value: eAdapterFeatureDelayedStackTraceLoading)
366 .Case(S: "supportsDisassembleRequest", Value: eAdapterFeatureDisassembleRequest)
367 .Case(S: "supportsEvaluateForHovers", Value: eAdapterFeatureEvaluateForHovers)
368 .Case(S: "supportsExceptionFilterOptions",
369 Value: eAdapterFeatureExceptionFilterOptions)
370 .Case(S: "supportsExceptionInfoRequest",
371 Value: eAdapterFeatureExceptionInfoRequest)
372 .Case(S: "supportsExceptionOptions", Value: eAdapterFeatureExceptionOptions)
373 .Case(S: "supportsFunctionBreakpoints",
374 Value: eAdapterFeatureFunctionBreakpoints)
375 .Case(S: "supportsGotoTargetsRequest", Value: eAdapterFeatureGotoTargetsRequest)
376 .Case(S: "supportsHitConditionalBreakpoints",
377 Value: eAdapterFeatureHitConditionalBreakpoints)
378 .Case(S: "supportsInstructionBreakpoints",
379 Value: eAdapterFeatureInstructionBreakpoints)
380 .Case(S: "supportsLoadedSourcesRequest",
381 Value: eAdapterFeatureLoadedSourcesRequest)
382 .Case(S: "supportsLogPoints", Value: eAdapterFeatureLogPoints)
383 .Case(S: "supportsModulesRequest", Value: eAdapterFeatureModulesRequest)
384 .Case(S: "supportsReadMemoryRequest", Value: eAdapterFeatureReadMemoryRequest)
385 .Case(S: "supportsRestartFrame", Value: eAdapterFeatureRestartFrame)
386 .Case(S: "supportsRestartRequest", Value: eAdapterFeatureRestartRequest)
387 .Case(S: "supportsSetExpression", Value: eAdapterFeatureSetExpression)
388 .Case(S: "supportsSetVariable", Value: eAdapterFeatureSetVariable)
389 .Case(S: "supportsSingleThreadExecutionRequests",
390 Value: eAdapterFeatureSingleThreadExecutionRequests)
391 .Case(S: "supportsStepBack", Value: eAdapterFeatureStepBack)
392 .Case(S: "supportsStepInTargetsRequest",
393 Value: eAdapterFeatureStepInTargetsRequest)
394 .Case(S: "supportsSteppingGranularity",
395 Value: eAdapterFeatureSteppingGranularity)
396 .Case(S: "supportsTerminateRequest", Value: eAdapterFeatureTerminateRequest)
397 .Case(S: "supportsTerminateThreadsRequest",
398 Value: eAdapterFeatureTerminateThreadsRequest)
399 .Case(S: "supportSuspendDebuggee", Value: eAdapterFeatureSuspendDebuggee)
400 .Case(S: "supportsValueFormattingOptions",
401 Value: eAdapterFeatureValueFormattingOptions)
402 .Case(S: "supportsWriteMemoryRequest", Value: eAdapterFeatureWriteMemoryRequest)
403 .Case(S: "supportTerminateDebuggee", Value: eAdapterFeatureTerminateDebuggee)
404 .Default(Value: std::nullopt);
405
406 if (!parsedFeature) {
407 P.report(Message: "unexpected value for AdapterFeature");
408 return false;
409 }
410
411 feature = *parsedFeature;
412 return true;
413}
414
415json::Value toJSON(const Capabilities &C) {
416 json::Object result;
417
418 for (const auto &feature : C.supportedFeatures)
419 result.insert(E: {.K: ToString(feature), .V: true});
420
421 if (C.exceptionBreakpointFilters && !C.exceptionBreakpointFilters->empty())
422 result.insert(
423 E: {.K: "exceptionBreakpointFilters", .V: *C.exceptionBreakpointFilters});
424 if (C.completionTriggerCharacters && !C.completionTriggerCharacters->empty())
425 result.insert(
426 E: {.K: "completionTriggerCharacters", .V: *C.completionTriggerCharacters});
427 if (C.additionalModuleColumns && !C.additionalModuleColumns->empty())
428 result.insert(E: {.K: "additionalModuleColumns", .V: *C.additionalModuleColumns});
429 if (C.supportedChecksumAlgorithms && !C.supportedChecksumAlgorithms->empty())
430 result.insert(
431 E: {.K: "supportedChecksumAlgorithms", .V: *C.supportedChecksumAlgorithms});
432 if (C.breakpointModes && !C.breakpointModes->empty())
433 result.insert(E: {.K: "breakpointModes", .V: *C.breakpointModes});
434
435 // lldb-dap extensions
436 if (C.lldbExtVersion && !C.lldbExtVersion->empty())
437 result.insert(E: {.K: "$__lldb_version", .V: *C.lldbExtVersion});
438
439 return result;
440}
441
442bool fromJSON(const json::Value &Params, Scope::PresentationHint &PH,
443 json::Path P) {
444 auto rawHint = Params.getAsString();
445 if (!rawHint) {
446 P.report(Message: "expected a string");
447 return false;
448 }
449 const std::optional<Scope::PresentationHint> hint =
450 StringSwitch<std::optional<Scope::PresentationHint>>(*rawHint)
451 .Case(S: "arguments", Value: Scope::eScopePresentationHintArguments)
452 .Case(S: "locals", Value: Scope::eScopePresentationHintLocals)
453 .Case(S: "registers", Value: Scope::eScopePresentationHintRegisters)
454 .Case(S: "returnValue", Value: Scope::eScopePresentationHintReturnValue)
455 .Default(Value: std::nullopt);
456 if (!hint) {
457 P.report(Message: "unexpected value");
458 return false;
459 }
460 PH = *hint;
461 return true;
462}
463
464bool fromJSON(const json::Value &Params, Scope &S, json::Path P) {
465 json::ObjectMapper O(Params, P);
466 return O && O.map(Prop: "name", Out&: S.name) &&
467 O.mapOptional(Prop: "presentationHint", Out&: S.presentationHint) &&
468 O.map(Prop: "variablesReference", Out&: S.variablesReference) &&
469 O.mapOptional(Prop: "namedVariables", Out&: S.namedVariables) &&
470 O.map(Prop: "indexedVariables", Out&: S.indexedVariables) &&
471 O.mapOptional(Prop: "source", Out&: S.source) && O.map(Prop: "expensive", Out&: S.expensive) &&
472 O.mapOptional(Prop: "line", Out&: S.line) && O.mapOptional(Prop: "column", Out&: S.column) &&
473 O.mapOptional(Prop: "endLine", Out&: S.endLine) &&
474 O.mapOptional(Prop: "endColumn", Out&: S.endColumn);
475}
476
477llvm::json::Value toJSON(const Scope &SC) {
478 llvm::json::Object result{{.K: "name", .V: SC.name},
479 {.K: "variablesReference", .V: SC.variablesReference},
480 {.K: "expensive", .V: SC.expensive}};
481
482 if (SC.presentationHint.has_value()) {
483 llvm::StringRef presentationHint;
484 switch (*SC.presentationHint) {
485 case Scope::eScopePresentationHintArguments:
486 presentationHint = "arguments";
487 break;
488 case Scope::eScopePresentationHintLocals:
489 presentationHint = "locals";
490 break;
491 case Scope::eScopePresentationHintRegisters:
492 presentationHint = "registers";
493 break;
494 case Scope::eScopePresentationHintReturnValue:
495 presentationHint = "returnValue";
496 break;
497 }
498
499 result.insert(E: {.K: "presentationHint", .V: presentationHint});
500 }
501
502 if (SC.namedVariables.has_value())
503 result.insert(E: {.K: "namedVariables", .V: SC.namedVariables});
504
505 if (SC.indexedVariables.has_value())
506 result.insert(E: {.K: "indexedVariables", .V: SC.indexedVariables});
507
508 if (SC.source.has_value())
509 result.insert(E: {.K: "source", .V: SC.source});
510
511 if (SC.line.has_value())
512 result.insert(E: {.K: "line", .V: SC.line});
513
514 if (SC.column.has_value())
515 result.insert(E: {.K: "column", .V: SC.column});
516
517 if (SC.endLine.has_value())
518 result.insert(E: {.K: "endLine", .V: SC.endLine});
519
520 if (SC.endColumn.has_value())
521 result.insert(E: {.K: "endColumn", .V: SC.endColumn});
522
523 return result;
524}
525
526bool fromJSON(const llvm::json::Value &Params, Capabilities &C,
527 llvm::json::Path P) {
528 auto *Object = Params.getAsObject();
529 if (!Object) {
530 P.report(Message: "expected an object");
531 return false;
532 }
533 // Check for the presence of supported features.
534 for (unsigned i = eAdapterFeatureFirst; i <= eAdapterFeatureLast; ++i) {
535 AdapterFeature feature = static_cast<AdapterFeature>(i);
536 if (Object->getBoolean(K: ToString(feature)))
537 C.supportedFeatures.insert(V: feature);
538 }
539 llvm::json::ObjectMapper O(Params, P);
540 return O &&
541 O.mapOptional(Prop: "exceptionBreakpointFilters",
542 Out&: C.exceptionBreakpointFilters) &&
543 O.mapOptional(Prop: "completionTriggerCharacters",
544 Out&: C.completionTriggerCharacters) &&
545 O.mapOptional(Prop: "additionalModuleColumns", Out&: C.additionalModuleColumns) &&
546 O.mapOptional(Prop: "supportedChecksumAlgorithms",
547 Out&: C.supportedChecksumAlgorithms) &&
548 O.mapOptional(Prop: "breakpointModes", Out&: C.breakpointModes) &&
549 O.mapOptional(Prop: "$__lldb_version", Out&: C.lldbExtVersion);
550}
551
552bool fromJSON(const llvm::json::Value &Params, SteppingGranularity &SG,
553 llvm::json::Path P) {
554 auto raw_granularity = Params.getAsString();
555 if (!raw_granularity) {
556 P.report(Message: "expected a string");
557 return false;
558 }
559 std::optional<SteppingGranularity> granularity =
560 StringSwitch<std::optional<SteppingGranularity>>(*raw_granularity)
561 .Case(S: "statement", Value: eSteppingGranularityStatement)
562 .Case(S: "line", Value: eSteppingGranularityLine)
563 .Case(S: "instruction", Value: eSteppingGranularityInstruction)
564 .Default(Value: std::nullopt);
565 if (!granularity) {
566 P.report(Message: "unexpected value");
567 return false;
568 }
569 SG = *granularity;
570 return true;
571}
572
573llvm::json::Value toJSON(const SteppingGranularity &SG) {
574 switch (SG) {
575 case eSteppingGranularityStatement:
576 return "statement";
577 case eSteppingGranularityLine:
578 return "line";
579 case eSteppingGranularityInstruction:
580 return "instruction";
581 }
582 llvm_unreachable("unhandled stepping granularity.");
583}
584
585bool fromJSON(const json::Value &Params, Thread &T, json::Path P) {
586 json::ObjectMapper O(Params, P);
587 return O && O.map(Prop: "id", Out&: T.id) && O.map(Prop: "name", Out&: T.name);
588}
589
590json::Value toJSON(const Thread &T) {
591 return json::Object{{.K: "id", .V: T.id}, {.K: "name", .V: T.name}};
592}
593
594bool fromJSON(const llvm::json::Value &Params, ValueFormat &VF,
595 llvm::json::Path P) {
596 json::ObjectMapper O(Params, P);
597 return O && O.mapOptional(Prop: "hex", Out&: VF.hex);
598}
599
600json::Value toJSON(const BreakpointLocation &B) {
601 json::Object result;
602
603 result.insert(E: {.K: "line", .V: B.line});
604 if (B.column)
605 result.insert(E: {.K: "column", .V: *B.column});
606 if (B.endLine)
607 result.insert(E: {.K: "endLine", .V: *B.endLine});
608 if (B.endColumn)
609 result.insert(E: {.K: "endColumn", .V: *B.endColumn});
610
611 return result;
612}
613
614llvm::json::Value toJSON(const BreakpointReason &BR) {
615 switch (BR) {
616 case BreakpointReason::eBreakpointReasonPending:
617 return "pending";
618 case BreakpointReason::eBreakpointReasonFailed:
619 return "failed";
620 }
621 llvm_unreachable("unhandled breakpoint reason.");
622}
623
624bool fromJSON(const llvm::json::Value &Params, BreakpointReason &BR,
625 llvm::json::Path P) {
626 auto rawReason = Params.getAsString();
627 if (!rawReason) {
628 P.report(Message: "expected a string");
629 return false;
630 }
631 std::optional<BreakpointReason> reason =
632 llvm::StringSwitch<std::optional<BreakpointReason>>(*rawReason)
633 .Case(S: "pending", Value: BreakpointReason::eBreakpointReasonPending)
634 .Case(S: "failed", Value: BreakpointReason::eBreakpointReasonFailed)
635 .Default(Value: std::nullopt);
636 if (!reason) {
637 P.report(Message: "unexpected value, expected 'pending' or 'failed'");
638 return false;
639 }
640 BR = *reason;
641 return true;
642}
643
644json::Value toJSON(const Breakpoint &BP) {
645 json::Object result{{.K: "verified", .V: BP.verified}};
646
647 if (BP.id)
648 result.insert(E: {.K: "id", .V: *BP.id});
649 if (BP.message)
650 result.insert(E: {.K: "message", .V: *BP.message});
651 if (BP.source)
652 result.insert(E: {.K: "source", .V: *BP.source});
653 if (BP.line)
654 result.insert(E: {.K: "line", .V: *BP.line});
655 if (BP.column)
656 result.insert(E: {.K: "column", .V: *BP.column});
657 if (BP.endLine)
658 result.insert(E: {.K: "endLine", .V: *BP.endLine});
659 if (BP.endColumn)
660 result.insert(E: {.K: "endColumn", .V: *BP.endColumn});
661 if (BP.instructionReference)
662 result.insert(E: {.K: "instructionReference", .V: *BP.instructionReference});
663 if (BP.offset)
664 result.insert(E: {.K: "offset", .V: *BP.offset});
665 if (BP.reason) {
666 result.insert(E: {.K: "reason", .V: *BP.reason});
667 }
668
669 return result;
670}
671
672bool fromJSON(const llvm::json::Value &Params, Breakpoint &BP,
673 llvm::json::Path P) {
674 llvm::json::ObjectMapper O(Params, P);
675 return O && O.mapOptional(Prop: "id", Out&: BP.id) && O.map(Prop: "verified", Out&: BP.verified) &&
676 O.mapOptional(Prop: "message", Out&: BP.message) &&
677 O.mapOptional(Prop: "source", Out&: BP.source) && O.mapOptional(Prop: "line", Out&: BP.line) &&
678 O.mapOptional(Prop: "column", Out&: BP.column) &&
679 O.mapOptional(Prop: "endLine", Out&: BP.endLine) &&
680 O.mapOptional(Prop: "endColumn", Out&: BP.endColumn) &&
681 O.mapOptional(Prop: "instructionReference", Out&: BP.instructionReference) &&
682 O.mapOptional(Prop: "offset", Out&: BP.offset) &&
683 O.mapOptional(Prop: "reason", Out&: BP.reason);
684}
685
686bool fromJSON(const llvm::json::Value &Params, SourceBreakpoint &SB,
687 llvm::json::Path P) {
688 llvm::json::ObjectMapper O(Params, P);
689 return O && O.map(Prop: "line", Out&: SB.line) && O.mapOptional(Prop: "column", Out&: SB.column) &&
690 O.mapOptional(Prop: "condition", Out&: SB.condition) &&
691 O.mapOptional(Prop: "hitCondition", Out&: SB.hitCondition) &&
692 O.mapOptional(Prop: "logMessage", Out&: SB.logMessage) &&
693 O.mapOptional(Prop: "mode", Out&: SB.mode);
694}
695
696llvm::json::Value toJSON(const SourceBreakpoint &SB) {
697 llvm::json::Object result{{.K: "line", .V: SB.line}};
698
699 if (SB.column)
700 result.insert(E: {.K: "column", .V: *SB.column});
701 if (SB.condition)
702 result.insert(E: {.K: "condition", .V: *SB.condition});
703 if (SB.hitCondition)
704 result.insert(E: {.K: "hitCondition", .V: *SB.hitCondition});
705 if (SB.logMessage)
706 result.insert(E: {.K: "logMessage", .V: *SB.logMessage});
707 if (SB.mode)
708 result.insert(E: {.K: "mode", .V: *SB.mode});
709
710 return result;
711}
712
713bool fromJSON(const llvm::json::Value &Params, FunctionBreakpoint &FB,
714 llvm::json::Path P) {
715 llvm::json::ObjectMapper O(Params, P);
716 return O && O.map(Prop: "name", Out&: FB.name) &&
717 O.mapOptional(Prop: "condition", Out&: FB.condition) &&
718 O.mapOptional(Prop: "hitCondition", Out&: FB.hitCondition);
719}
720
721llvm::json::Value toJSON(const FunctionBreakpoint &FB) {
722 llvm::json::Object result{{.K: "name", .V: FB.name}};
723
724 if (FB.condition)
725 result.insert(E: {.K: "condition", .V: *FB.condition});
726 if (FB.hitCondition)
727 result.insert(E: {.K: "hitCondition", .V: *FB.hitCondition});
728
729 return result;
730}
731
732bool fromJSON(const llvm::json::Value &Params, DataBreakpointAccessType &DBAT,
733 llvm::json::Path P) {
734 auto rawAccessType = Params.getAsString();
735 if (!rawAccessType) {
736 P.report(Message: "expected a string");
737 return false;
738 }
739 std::optional<DataBreakpointAccessType> accessType =
740 StringSwitch<std::optional<DataBreakpointAccessType>>(*rawAccessType)
741 .Case(S: "read", Value: eDataBreakpointAccessTypeRead)
742 .Case(S: "write", Value: eDataBreakpointAccessTypeWrite)
743 .Case(S: "readWrite", Value: eDataBreakpointAccessTypeReadWrite)
744 .Default(Value: std::nullopt);
745 if (!accessType) {
746 P.report(Message: "unexpected value, expected 'read', 'write', or 'readWrite'");
747 return false;
748 }
749 DBAT = *accessType;
750 return true;
751}
752
753llvm::json::Value toJSON(const DataBreakpointAccessType &DBAT) {
754 switch (DBAT) {
755 case eDataBreakpointAccessTypeRead:
756 return "read";
757 case eDataBreakpointAccessTypeWrite:
758 return "write";
759 case eDataBreakpointAccessTypeReadWrite:
760 return "readWrite";
761 }
762 llvm_unreachable("unhandled data breakpoint access type.");
763}
764
765bool fromJSON(const llvm::json::Value &Params, DataBreakpoint &DBI,
766 llvm::json::Path P) {
767 llvm::json::ObjectMapper O(Params, P);
768 return O && O.map(Prop: "dataId", Out&: DBI.dataId) &&
769 O.mapOptional(Prop: "accessType", Out&: DBI.accessType) &&
770 O.mapOptional(Prop: "condition", Out&: DBI.condition) &&
771 O.mapOptional(Prop: "hitCondition", Out&: DBI.hitCondition);
772}
773
774llvm::json::Value toJSON(const DataBreakpoint &DBI) {
775 llvm::json::Object result{{.K: "dataId", .V: DBI.dataId}};
776
777 if (DBI.accessType)
778 result.insert(E: {.K: "accessType", .V: *DBI.accessType});
779 if (DBI.condition)
780 result.insert(E: {.K: "condition", .V: *DBI.condition});
781 if (DBI.hitCondition)
782 result.insert(E: {.K: "hitCondition", .V: *DBI.hitCondition});
783
784 return result;
785}
786
787bool fromJSON(const llvm::json::Value &Params, InstructionBreakpoint &IB,
788 llvm::json::Path P) {
789 llvm::json::ObjectMapper O(Params, P);
790 return O && O.map(Prop: "instructionReference", Out&: IB.instructionReference) &&
791 O.mapOptional(Prop: "offset", Out&: IB.offset) &&
792 O.mapOptional(Prop: "condition", Out&: IB.condition) &&
793 O.mapOptional(Prop: "hitCondition", Out&: IB.hitCondition) &&
794 O.mapOptional(Prop: "mode", Out&: IB.mode);
795}
796
797bool fromJSON(const llvm::json::Value &Params,
798 DisassembledInstruction::PresentationHint &PH,
799 llvm::json::Path P) {
800 auto rawHint = Params.getAsString();
801 if (!rawHint) {
802 P.report(Message: "expected a string");
803 return false;
804 }
805 std::optional<DisassembledInstruction::PresentationHint> hint =
806 StringSwitch<std::optional<DisassembledInstruction::PresentationHint>>(
807 *rawHint)
808 .Case(S: "normal", Value: DisassembledInstruction::
809 eDisassembledInstructionPresentationHintNormal)
810 .Case(S: "invalid", Value: DisassembledInstruction::
811 eDisassembledInstructionPresentationHintInvalid)
812 .Default(Value: std::nullopt);
813 if (!hint) {
814 P.report(Message: "unexpected value");
815 return false;
816 }
817 PH = *hint;
818 return true;
819}
820
821llvm::json::Value toJSON(const DisassembledInstruction::PresentationHint &PH) {
822 switch (PH) {
823 case DisassembledInstruction::eDisassembledInstructionPresentationHintNormal:
824 return "normal";
825 case DisassembledInstruction::eDisassembledInstructionPresentationHintInvalid:
826 return "invalid";
827 }
828 llvm_unreachable("unhandled presentation hint.");
829}
830
831bool fromJSON(const llvm::json::Value &Params, DisassembledInstruction &DI,
832 llvm::json::Path P) {
833 llvm::json::ObjectMapper O(Params, P);
834 std::string raw_address;
835 if (!O || !O.map(Prop: "address", Out&: raw_address))
836 return false;
837
838 std::optional<lldb::addr_t> address = DecodeMemoryReference(memoryReference: raw_address);
839 if (!address) {
840 P.field(Field: "address").report(Message: "expected string encoded uint64_t");
841 return false;
842 }
843
844 DI.address = *address;
845
846 return O.map(Prop: "instruction", Out&: DI.instruction) &&
847 O.mapOptional(Prop: "instructionBytes", Out&: DI.instructionBytes) &&
848 O.mapOptional(Prop: "symbol", Out&: DI.symbol) &&
849 O.mapOptional(Prop: "location", Out&: DI.location) &&
850 O.mapOptional(Prop: "line", Out&: DI.line) && O.mapOptional(Prop: "column", Out&: DI.column) &&
851 O.mapOptional(Prop: "endLine", Out&: DI.endLine) &&
852 O.mapOptional(Prop: "endColumn", Out&: DI.endColumn) &&
853 O.mapOptional(Prop: "presentationHint", Out&: DI.presentationHint);
854}
855
856llvm::json::Value toJSON(const DisassembledInstruction &DI) {
857 llvm::json::Object result{{.K: "instruction", .V: DI.instruction}};
858 if (DI.address == LLDB_INVALID_ADDRESS) {
859 // VS Code has explicit comparisons to the string "-1" in order to check for
860 // invalid instructions. See
861 // https://github.com/microsoft/vscode/blob/main/src/vs/workbench/contrib/debug/browser/disassemblyView.ts
862 result.insert(E: {.K: "address", .V: "-1"});
863 } else {
864 result.insert(E: {.K: "address", .V: "0x" + llvm::utohexstr(X: DI.address)});
865 }
866
867 if (DI.instructionBytes)
868 result.insert(E: {.K: "instructionBytes", .V: *DI.instructionBytes});
869 if (DI.symbol)
870 result.insert(E: {.K: "symbol", .V: *DI.symbol});
871 if (DI.location)
872 result.insert(E: {.K: "location", .V: *DI.location});
873 if (DI.line)
874 result.insert(E: {.K: "line", .V: *DI.line});
875 if (DI.column)
876 result.insert(E: {.K: "column", .V: *DI.column});
877 if (DI.endLine)
878 result.insert(E: {.K: "endLine", .V: *DI.endLine});
879 if (DI.endColumn)
880 result.insert(E: {.K: "endColumn", .V: *DI.endColumn});
881 if (DI.presentationHint)
882 result.insert(E: {.K: "presentationHint", .V: *DI.presentationHint});
883
884 return result;
885}
886
887} // namespace lldb_dap::protocol
888

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