from .server import request, capability
from .startup import send_gdb_with_response, in_gdb_thread
from .state import set_thread
+from .varref import apply_format
# Helper function to compute a stack trace.
@in_gdb_thread
-def _backtrace(thread_id, levels, startFrame):
- set_thread(thread_id)
- frames = []
- if levels == 0:
- # Zero means all remaining frames.
- high = -1
- else:
- # frame_iterator uses an inclusive range, so subtract one.
- high = startFrame + levels - 1
- try:
- frame_iter = frame_iterator(gdb.newest_frame(), startFrame, high)
- except gdb.error:
- frame_iter = ()
- for current_frame in frame_iter:
- pc = current_frame.address()
- newframe = {
- "id": frame_id(current_frame),
- "name": current_frame.function(),
- # This must always be supplied, but we will set it
- # correctly later if that is possible.
- "line": 0,
- # GDB doesn't support columns.
- "column": 0,
- "instructionPointerReference": hex(pc),
- }
- objfile = gdb.current_progspace().objfile_for_address(pc)
- if objfile is not None:
- newframe["moduleId"] = module_id(objfile)
- line = current_frame.line()
- if line is not None:
- newframe["line"] = line
- filename = current_frame.filename()
- if filename is not None:
- newframe["source"] = {
- "name": os.path.basename(filename),
- "path": filename,
- # We probably don't need this but it doesn't hurt
- # to be explicit.
- "sourceReference": 0,
+def _backtrace(thread_id, levels, startFrame, value_format):
+ with apply_format(value_format):
+ set_thread(thread_id)
+ frames = []
+ if levels == 0:
+ # Zero means all remaining frames.
+ high = -1
+ else:
+ # frame_iterator uses an inclusive range, so subtract one.
+ high = startFrame + levels - 1
+ try:
+ frame_iter = frame_iterator(gdb.newest_frame(), startFrame, high)
+ except gdb.error:
+ frame_iter = ()
+ for current_frame in frame_iter:
+ pc = current_frame.address()
+ newframe = {
+ "id": frame_id(current_frame),
+ "name": current_frame.function(),
+ # This must always be supplied, but we will set it
+ # correctly later if that is possible.
+ "line": 0,
+ # GDB doesn't support columns.
+ "column": 0,
+ "instructionPointerReference": hex(pc),
}
- frames.append(newframe)
- # Note that we do not calculate totalFrames here. Its absence
- # tells the client that it may simply ask for frames until a
- # response yields fewer frames than requested.
- return {
- "stackFrames": frames,
- }
+ objfile = gdb.current_progspace().objfile_for_address(pc)
+ if objfile is not None:
+ newframe["moduleId"] = module_id(objfile)
+ line = current_frame.line()
+ if line is not None:
+ newframe["line"] = line
+ filename = current_frame.filename()
+ if filename is not None:
+ newframe["source"] = {
+ "name": os.path.basename(filename),
+ "path": filename,
+ # We probably don't need this but it doesn't hurt
+ # to be explicit.
+ "sourceReference": 0,
+ }
+ frames.append(newframe)
+ # Note that we do not calculate totalFrames here. Its absence
+ # tells the client that it may simply ask for frames until a
+ # response yields fewer frames than requested.
+ return {
+ "stackFrames": frames,
+ }
@request("stackTrace")
@capability("supportsDelayedStackTraceLoading")
-def stacktrace(*, levels: int = 0, startFrame: int = 0, threadId: int, **extra):
- return send_gdb_with_response(lambda: _backtrace(threadId, levels, startFrame))
+def stacktrace(
+ *, levels: int = 0, startFrame: int = 0, threadId: int, format=None, **extra
+):
+ return send_gdb_with_response(
+ lambda: _backtrace(threadId, levels, startFrame, format)
+ )
from .frames import select_frame
from .server import capability, request, client_bool_capability
from .startup import send_gdb_with_response, in_gdb_thread
-from .varref import find_variable, VariableReference
+from .varref import find_variable, VariableReference, apply_format
class EvaluateResult(VariableReference):
# Helper function to evaluate an expression in a certain frame.
@in_gdb_thread
-def _evaluate(expr, frame_id):
- global_context = True
- if frame_id is not None:
- select_frame(frame_id)
- global_context = False
- val = gdb.parse_and_eval(expr, global_context=global_context)
- ref = EvaluateResult(val)
- return ref.to_object()
+def _evaluate(expr, frame_id, value_format):
+ with apply_format(value_format):
+ global_context = True
+ if frame_id is not None:
+ select_frame(frame_id)
+ global_context = False
+ val = gdb.parse_and_eval(expr, global_context=global_context)
+ ref = EvaluateResult(val)
+ return ref.to_object()
# Like _evaluate but ensure that the expression cannot cause side
# effects.
@in_gdb_thread
-def _eval_for_hover(expr, frame_id):
+def _eval_for_hover(expr, frame_id, value_format):
with gdb.with_parameter("may-write-registers", "off"):
with gdb.with_parameter("may-write-memory", "off"):
with gdb.with_parameter("may-call-functions", "off"):
- return _evaluate(expr, frame_id)
+ return _evaluate(expr, frame_id, value_format)
class _SetResult(VariableReference):
# Helper function to perform an assignment.
@in_gdb_thread
-def _set_expression(expression, value, frame_id):
- global_context = True
- if frame_id is not None:
- select_frame(frame_id)
- global_context = False
- lhs = gdb.parse_and_eval(expression, global_context=global_context)
- rhs = gdb.parse_and_eval(value, global_context=global_context)
- lhs.assign(rhs)
- return _SetResult(lhs).to_object()
+def _set_expression(expression, value, frame_id, value_format):
+ with apply_format(value_format):
+ global_context = True
+ if frame_id is not None:
+ select_frame(frame_id)
+ global_context = False
+ lhs = gdb.parse_and_eval(expression, global_context=global_context)
+ rhs = gdb.parse_and_eval(value, global_context=global_context)
+ lhs.assign(rhs)
+ return _SetResult(lhs).to_object()
# Helper function to evaluate a gdb command in a certain frame.
@request("evaluate")
@capability("supportsEvaluateForHovers")
+@capability("supportsValueFormattingOptions")
def eval_request(
*,
expression: str,
frameId: Optional[int] = None,
context: str = "variables",
+ format=None,
**args,
):
if context in ("watch", "variables"):
# These seem to be expression-like.
- return send_gdb_with_response(lambda: _evaluate(expression, frameId))
+ return send_gdb_with_response(lambda: _evaluate(expression, frameId, format))
elif context == "hover":
- return send_gdb_with_response(lambda: _eval_for_hover(expression, frameId))
+ return send_gdb_with_response(
+ lambda: _eval_for_hover(expression, frameId, format)
+ )
elif context == "repl":
+ # Ignore the format for repl evaluation.
return send_gdb_with_response(lambda: _repl(expression, frameId))
else:
raise Exception('unknown evaluate context "' + context + '"')
@in_gdb_thread
-def _variables(ref, start, count):
- var = find_variable(ref)
- children = var.fetch_children(start, count)
- return [x.to_object() for x in children]
+def _variables(ref, start, count, value_format):
+ with apply_format(value_format):
+ var = find_variable(ref)
+ children = var.fetch_children(start, count)
+ return [x.to_object() for x in children]
@request("variables")
# Note that we ignore the 'filter' field. That seems to be
# specific to javascript.
-def variables(*, variablesReference: int, start: int = 0, count: int = 0, **args):
+def variables(
+ *, variablesReference: int, start: int = 0, count: int = 0, format=None, **args
+):
# This behavior was clarified here:
# https://github.com/microsoft/debug-adapter-protocol/pull/394
if not client_bool_capability("supportsVariablePaging"):
start = 0
count = 0
result = send_gdb_with_response(
- lambda: _variables(variablesReference, start, count)
+ lambda: _variables(variablesReference, start, count, format)
)
return {"variables": result}
@capability("supportsSetExpression")
@request("setExpression")
def set_expression(
- *, expression: str, value: str, frameId: Optional[int] = None, **args
+ *, expression: str, value: str, frameId: Optional[int] = None, format=None, **args
):
- return send_gdb_with_response(lambda: _set_expression(expression, value, frameId))
+ return send_gdb_with_response(
+ lambda: _set_expression(expression, value, frameId, format)
+ )