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

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