]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blob - gdb/python/lib/gdb/dap/evaluate.py
Implement DAP setExpression request
[thirdparty/binutils-gdb.git] / gdb / python / lib / gdb / dap / evaluate.py
1 # Copyright 2022, 2023 Free Software Foundation, Inc.
2
3 # This program is free software; you can redistribute it and/or modify
4 # it under the terms of the GNU General Public License as published by
5 # the Free Software Foundation; either version 3 of the License, or
6 # (at your option) any later version.
7 #
8 # This program is distributed in the hope that it will be useful,
9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 # GNU General Public License for more details.
12 #
13 # You should have received a copy of the GNU General Public License
14 # along with this program. If not, see <http://www.gnu.org/licenses/>.
15
16 import gdb
17 import gdb.printing
18
19 # This is deprecated in 3.9, but required in older versions.
20 from typing import Optional
21
22 from .frames import frame_for_id
23 from .server import capability, request
24 from .startup import send_gdb_with_response, in_gdb_thread
25 from .varref import find_variable, VariableReference
26
27
28 class EvaluateResult(VariableReference):
29 def __init__(self, value):
30 super().__init__(None, value, "result")
31
32
33 # Helper function to evaluate an expression in a certain frame.
34 @in_gdb_thread
35 def _evaluate(expr, frame_id):
36 global_context = True
37 if frame_id is not None:
38 frame = frame_for_id(frame_id)
39 frame.select()
40 global_context = False
41 val = gdb.parse_and_eval(expr, global_context=global_context)
42 ref = EvaluateResult(val)
43 return ref.to_object()
44
45
46 # Helper function to perform an assignment.
47 @in_gdb_thread
48 def _set_expression(expression, value, frame_id):
49 global_context = True
50 if frame_id is not None:
51 frame = frame_for_id(frame_id)
52 frame.select()
53 global_context = False
54 lhs = gdb.parse_and_eval(expression, global_context=global_context)
55 rhs = gdb.parse_and_eval(value, global_context=global_context)
56 lhs.assign(rhs)
57 return EvaluateResult(lhs).to_object()
58
59
60 # Helper function to evaluate a gdb command in a certain frame.
61 @in_gdb_thread
62 def _repl(command, frame_id):
63 if frame_id is not None:
64 frame = frame_for_id(frame_id)
65 frame.select()
66 val = gdb.execute(command, from_tty=True, to_string=True)
67 return {
68 "result": val,
69 "variablesReference": 0,
70 }
71
72
73 # FIXME supportsVariableType handling
74 @request("evaluate")
75 def eval_request(
76 *,
77 expression: str,
78 frameId: Optional[int] = None,
79 context: str = "variables",
80 **args,
81 ):
82 if context in ("watch", "variables"):
83 # These seem to be expression-like.
84 return send_gdb_with_response(lambda: _evaluate(expression, frameId))
85 elif context == "repl":
86 return send_gdb_with_response(lambda: _repl(expression, frameId))
87 else:
88 raise Exception(f'unknown evaluate context "{context}"')
89
90
91 @in_gdb_thread
92 def _variables(ref, start, count):
93 var = find_variable(ref)
94 children = var.fetch_children(start, count)
95 return [x.to_object() for x in children]
96
97
98 @request("variables")
99 # Note that we ignore the 'filter' field. That seems to be
100 # specific to javascript.
101 def variables(*, variablesReference: int, start: int = 0, count: int = 0, **args):
102 result = send_gdb_with_response(
103 lambda: _variables(variablesReference, start, count)
104 )
105 return {"variables": result}
106
107
108 @capability("supportsSetExpression")
109 @request("setExpression")
110 def set_expression(
111 *, expression: str, value: str, frameId: Optional[int] = None, **args
112 ):
113 return send_gdb_with_response(lambda: _set_expression(expression, value, frameId))