diff --git a/gdb/python/lib/gdb/dap/breakpoint.py b/gdb/python/lib/gdb/dap/breakpoint.py
index 33aa18e65bc..c67bb471daf 100644
--- a/gdb/python/lib/gdb/dap/breakpoint.py
+++ b/gdb/python/lib/gdb/dap/breakpoint.py
@@ -24,7 +24,7 @@ from typing import Optional, Sequence
 
 from .server import request, capability, send_event
 from .sources import make_source
-from .startup import in_gdb_thread, log_stack
+from .startup import in_gdb_thread, log_stack, parse_and_eval, DAPException
 from .typecheck import type_check
 
 
@@ -168,7 +168,7 @@ def _set_breakpoints_callback(kind, specs, creator):
                 bp.ignore_count = 0
             else:
                 bp.ignore_count = int(
-                    gdb.parse_and_eval(hit_condition, global_context=True)
+                    parse_and_eval(hit_condition, global_context=True)
                 )
 
             # Reaching this spot means success.
@@ -212,6 +212,7 @@ class _PrintBreakpoint(gdb.Breakpoint):
                 # have already been stripped by the placement of the
                 # regex capture in the 'split' call.
                 try:
+                    # No real need to use the DAP parse_and_eval here.
                     val = gdb.parse_and_eval(item)
                     output += str(val)
                 except Exception as e:
@@ -360,12 +361,13 @@ def _catch_exception(filterId, **args):
     if filterId in ("assert", "exception", "throw", "rethrow", "catch"):
         cmd = "-catch-" + filterId
     else:
-        raise Exception("Invalid exception filterID: " + str(filterId))
+        raise DAPException("Invalid exception filterID: " + str(filterId))
     result = gdb.execute_mi(cmd)
     # A little lame that there's no more direct way.
     for bp in gdb.breakpoints():
         if bp.number == result["bkptno"]:
             return bp
+    # Not a DAPException because this is definitely unexpected.
     raise Exception("Could not find catchpoint after creating")
 
 
diff --git a/gdb/python/lib/gdb/dap/evaluate.py b/gdb/python/lib/gdb/dap/evaluate.py
index d39e7879205..eb38baf3973 100644
--- a/gdb/python/lib/gdb/dap/evaluate.py
+++ b/gdb/python/lib/gdb/dap/evaluate.py
@@ -20,7 +20,7 @@ from typing import Optional
 
 from .frames import select_frame
 from .server import capability, request, client_bool_capability
-from .startup import in_gdb_thread
+from .startup import in_gdb_thread, parse_and_eval, DAPException
 from .varref import find_variable, VariableReference, apply_format
 
 
@@ -37,7 +37,7 @@ def _evaluate(expr, frame_id, value_format):
         if frame_id is not None:
             select_frame(frame_id)
             global_context = False
-        val = gdb.parse_and_eval(expr, global_context=global_context)
+        val = parse_and_eval(expr, global_context=global_context)
         ref = EvaluateResult(val)
         return ref.to_object()
 
@@ -89,7 +89,7 @@ def eval_request(
         # Ignore the format for repl evaluation.
         return _repl(expression, frameId)
     else:
-        raise Exception('unknown evaluate context "' + context + '"')
+        raise DAPException('unknown evaluate context "' + context + '"')
 
 
 @request("variables")
@@ -119,8 +119,8 @@ def set_expression(
         if frameId is not None:
             select_frame(frameId)
             global_context = False
-        lhs = gdb.parse_and_eval(expression, global_context=global_context)
-        rhs = gdb.parse_and_eval(value, global_context=global_context)
+        lhs = parse_and_eval(expression, global_context=global_context)
+        rhs = parse_and_eval(value, global_context=global_context)
         lhs.assign(rhs)
         return _SetResult(lhs).to_object()
 
@@ -133,6 +133,6 @@ def set_variable(
     with apply_format(format):
         var = find_variable(variablesReference)
         lhs = var.find_child_by_name(name)
-        rhs = gdb.parse_and_eval(value)
+        rhs = parse_and_eval(value)
         lhs.assign(rhs)
         return lhs.to_object()
diff --git a/gdb/python/lib/gdb/dap/launch.py b/gdb/python/lib/gdb/dap/launch.py
index 7014047ff51..a8adb125707 100644
--- a/gdb/python/lib/gdb/dap/launch.py
+++ b/gdb/python/lib/gdb/dap/launch.py
@@ -20,7 +20,7 @@ from typing import Mapping, Optional, Sequence
 
 from .events import exec_and_expect_stop, expect_process
 from .server import request, capability
-from .startup import exec_and_log
+from .startup import exec_and_log, DAPException
 
 
 # The program being launched, or None.  This should only be accessed
@@ -69,7 +69,7 @@ def attach(*, pid: Optional[int] = None, target: Optional[str] = None, **args):
     elif target is not None:
         cmd = "target remote " + target
     else:
-        raise Exception("attach requires either 'pid' or 'target'")
+        raise DAPException("attach requires either 'pid' or 'target'")
     expect_process("attach")
     exec_and_log(cmd)
 
diff --git a/gdb/python/lib/gdb/dap/sources.py b/gdb/python/lib/gdb/dap/sources.py
index 821205cedd1..d73a3f8c5b1 100644
--- a/gdb/python/lib/gdb/dap/sources.py
+++ b/gdb/python/lib/gdb/dap/sources.py
@@ -18,7 +18,7 @@ import os
 import gdb
 
 from .server import request, capability
-from .startup import in_gdb_thread
+from .startup import in_gdb_thread, DAPException
 
 
 # The next available source reference ID.  Must be greater than 0.
@@ -68,11 +68,11 @@ def decode_source(source):
     if "path" in source:
         return source["path"]
     if "sourceReference" not in source:
-        raise Exception("either 'path' or 'sourceReference' must appear in Source")
+        raise DAPException("either 'path' or 'sourceReference' must appear in Source")
     ref = source["sourceReference"]
     global _id_map
     if ref not in _id_map:
-        raise Exception("no sourceReference " + str(ref))
+        raise DAPException("no sourceReference " + str(ref))
     return _id_map[ref]["path"]
 
 
diff --git a/gdb/python/lib/gdb/dap/startup.py b/gdb/python/lib/gdb/dap/startup.py
index 1d3b94762a6..64a46597bf4 100644
--- a/gdb/python/lib/gdb/dap/startup.py
+++ b/gdb/python/lib/gdb/dap/startup.py
@@ -39,6 +39,24 @@ _gdb_thread = threading.current_thread()
 _dap_thread = None
 
 
+# "Known" exceptions are wrapped in a DAP exception, so that, by
+# default, only rogue exceptions are logged -- this is then used by
+# the test suite.
+class DAPException(Exception):
+    pass
+
+
+# Wrapper for gdb.parse_and_eval that turns exceptions into
+# DAPException.
+def parse_and_eval(expression, global_context=False):
+    try:
+        return gdb.parse_and_eval(expression, global_context=global_context)
+    except Exception as e:
+        # Be sure to preserve the summary, as this can propagate to
+        # the client.
+        raise DAPException(str(e)) from e
+
+
 def start_thread(name, target, args=()):
     """Start a new thread, invoking TARGET with *ARGS there.
     This is a helper function that ensures that any GDB signals are
diff --git a/gdb/python/lib/gdb/dap/varref.py b/gdb/python/lib/gdb/dap/varref.py
index 8f0a070498c..c75afe3848e 100644
--- a/gdb/python/lib/gdb/dap/varref.py
+++ b/gdb/python/lib/gdb/dap/varref.py
@@ -14,7 +14,7 @@
 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
 import gdb
-from .startup import in_gdb_thread
+from .startup import in_gdb_thread, DAPException
 from .server import client_bool_capability
 from abc import ABC, abstractmethod
 from collections import defaultdict
@@ -165,7 +165,7 @@ class BaseReference(ABC):
         # map here.
         if name in self.by_name:
             return self.by_name[name]
-        raise Exception("no variable named '" + name + "'")
+        raise DAPException("no variable named '" + name + "'")
 
 
 class VariableReference(BaseReference):
@@ -271,5 +271,5 @@ def find_variable(ref):
     # Variable references are offset by 1.
     ref = ref - 1
     if ref < 0 or ref > len(all_variables):
-        raise Exception("invalid variablesReference")
+        raise DAPException("invalid variablesReference")
     return all_variables[ref]
