[Lldb-commits] [lldb] [lldb] Inline expression evaluator error visualization (PR #106470)

Adrian Prantl via lldb-commits lldb-commits at lists.llvm.org
Wed Aug 28 17:41:29 PDT 2024


https://github.com/adrian-prantl updated https://github.com/llvm/llvm-project/pull/106470

>From 9f014cf845712914a68419a18ace0aecbc13c30b Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Wed, 28 Aug 2024 10:04:33 -0700
Subject: [PATCH 1/2] [lldb] Add Status::Detail to store expression evaluator
 diagnostics [NFC]

This patch is a reworking of Pete Lawrence's (@PortalPete) proposal
for better expression evaluator error messages:
https://github.com/llvm/llvm-project/pull/80938

This patch is preparatory patch for improving the rendering of
expression evaluator diagnostics. Currently diagnostics are rendered
into a string and the command interpreter layer then textually parses
words like "error:" to (sometimes) color the output accordingly. In
order to enable user interfaces to do better with diagnostics, we need
to store them in a machine-readable fromat. This patch does this by
adding a Status::Detail vector to Status that is used when the error
type is eErrorTypeExpression. I tried my best to minimize the overhead
this adds to Status in all other use-cases.

Right now the extra information is not used by the CommandInterpreter,
this will be added in a follow-up patch!
---
 .../lldb/Expression/DiagnosticManager.h       | 50 ++++++++-----------
 lldb/include/lldb/Utility/Status.h            | 50 ++++++++++++++++++-
 lldb/source/Expression/DiagnosticManager.cpp  | 27 ++++++++++
 lldb/source/Expression/UserExpression.cpp     | 26 +++++-----
 .../ExpressionParser/Clang/ClangDiagnostic.h  |  5 +-
 .../Clang/ClangExpressionParser.cpp           | 47 ++++++++++++++---
 lldb/source/Utility/Status.cpp                | 25 ++++++++--
 .../TestModulesCompileError.py                |  2 +-
 .../Expression/DiagnosticManagerTest.cpp      | 12 ++---
 9 files changed, 180 insertions(+), 64 deletions(-)

diff --git a/lldb/include/lldb/Expression/DiagnosticManager.h b/lldb/include/lldb/Expression/DiagnosticManager.h
index d49b7c99b114fb..252492ce8f776a 100644
--- a/lldb/include/lldb/Expression/DiagnosticManager.h
+++ b/lldb/include/lldb/Expression/DiagnosticManager.h
@@ -12,6 +12,8 @@
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-types.h"
 
+#include "lldb/Utility/Status.h"
+
 #include "llvm/ADT/STLExtras.h"
 #include "llvm/ADT/StringRef.h"
 
@@ -49,37 +51,28 @@ class Diagnostic {
     }
   }
 
-  Diagnostic(llvm::StringRef message, lldb::Severity severity,
-             DiagnosticOrigin origin, uint32_t compiler_id)
-      : m_message(message), m_severity(severity), m_origin(origin),
-        m_compiler_id(compiler_id) {}
-
-  Diagnostic(const Diagnostic &rhs)
-      : m_message(rhs.m_message), m_severity(rhs.m_severity),
-        m_origin(rhs.m_origin), m_compiler_id(rhs.m_compiler_id) {}
+  Diagnostic(DiagnosticOrigin origin, uint32_t compiler_id,
+             Status::Detail detail)
+      : m_origin(origin), m_compiler_id(compiler_id), m_detail(detail) {}
 
   virtual ~Diagnostic() = default;
 
   virtual bool HasFixIts() const { return false; }
 
-  lldb::Severity GetSeverity() const { return m_severity; }
+  lldb::Severity GetSeverity() const { return m_detail.severity; }
 
   uint32_t GetCompilerID() const { return m_compiler_id; }
 
-  llvm::StringRef GetMessage() const { return m_message; }
+  llvm::StringRef GetMessage() const { return m_detail.message; }
+  Status::Detail GetDetail() const { return m_detail; }
 
-  void AppendMessage(llvm::StringRef message,
-                     bool precede_with_newline = true) {
-    if (precede_with_newline)
-      m_message.push_back('\n');
-    m_message += message;
-  }
+  void AppendMessage(llvm::StringRef message, bool precede_with_newline = true);
 
 protected:
-  std::string m_message;
-  lldb::Severity m_severity;
   DiagnosticOrigin m_origin;
-  uint32_t m_compiler_id; // Compiler-specific diagnostic ID
+  /// Compiler-specific diagnostic ID.
+  uint32_t m_compiler_id;
+  Status::Detail m_detail;
 };
 
 typedef std::vector<std::unique_ptr<Diagnostic>> DiagnosticList;
@@ -102,10 +95,7 @@ class DiagnosticManager {
 
   void AddDiagnostic(llvm::StringRef message, lldb::Severity severity,
                      DiagnosticOrigin origin,
-                     uint32_t compiler_id = LLDB_INVALID_COMPILER_ID) {
-    m_diagnostics.emplace_back(
-        std::make_unique<Diagnostic>(message, severity, origin, compiler_id));
-  }
+                     uint32_t compiler_id = LLDB_INVALID_COMPILER_ID);
 
   void AddDiagnostic(std::unique_ptr<Diagnostic> diagnostic) {
     if (diagnostic)
@@ -130,13 +120,17 @@ class DiagnosticManager {
       m_diagnostics.back()->AppendMessage(str);
   }
 
-  // Returns a string containing errors in this format:
-  //
-  // "error: error text\n
-  // warning: warning text\n
-  // remark text\n"
+  /// Returns a string containing errors in this format:
+  ///
+  ///     "error: error text\n
+  ///     warning: warning text\n
+  ///     remark text\n"
+  LLVM_DEPRECATED("Use GetAsStatus instead", "GetAsStatus()")
   std::string GetString(char separator = '\n');
 
+  /// Copies the diagnostics into an lldb::Status.
+  Status GetAsStatus(lldb::ExpressionResults result);
+
   void Dump(Log *log);
 
   const std::string &GetFixedExpression() { return m_fixed_expression; }
diff --git a/lldb/include/lldb/Utility/Status.h b/lldb/include/lldb/Utility/Status.h
index b304291ffae00e..5a9683e09c6e53 100644
--- a/lldb/include/lldb/Utility/Status.h
+++ b/lldb/include/lldb/Utility/Status.h
@@ -9,6 +9,7 @@
 #ifndef LLDB_UTILITY_STATUS_H
 #define LLDB_UTILITY_STATUS_H
 
+#include "lldb/Utility/FileSpec.h"
 #include "lldb/lldb-defines.h"
 #include "lldb/lldb-enumerations.h"
 #include "llvm/ADT/StringRef.h"
@@ -47,7 +48,34 @@ class Status {
   /// into ValueType.
   typedef uint32_t ValueType;
 
-  Status();
+  /// A customizable "detail" for an error. For example, expression
+  /// evaluation failures often have more than one diagnostic that the
+  /// UI layer might want to render differently.
+  ///
+  /// Running example:
+  ///   (lldb) expr 1+x
+  ///   error: <user expression 0>:1:3: use of undeclared identifier 'foo'
+  ///   1+foo
+  ///     ^
+  struct Detail {
+    struct SourceLocation {
+      FileSpec file;
+      unsigned line = 0;
+      uint16_t column = 0;
+      uint16_t length = 0;
+      bool in_user_input = false;
+    };
+    /// Contains {{}, 1, 3, 3, true} in the example above.
+    std::optional<SourceLocation> source_location;
+    /// Contains eSeverityError in the example above.
+    lldb::Severity severity = lldb::eSeverityInfo;
+    /// Contains "use of undeclared identifier 'x'" in the example above.
+    std::string message;
+    /// Contains the fully rendered error message.
+    std::string rendered;
+  };
+
+  Status() = default;
 
   /// Initialize the error object with a generic success value.
   ///
@@ -57,7 +85,8 @@ class Status {
   /// \param[in] type
   ///     The type for \a err.
   explicit Status(ValueType err, lldb::ErrorType type = lldb::eErrorTypeGeneric,
-                  std::string msg = {});
+                  std::string msg = {})
+      : m_code(err), m_type(type), m_string(std::move(msg)) {}
 
   Status(std::error_code EC);
 
@@ -83,6 +112,12 @@ class Status {
     return Status(result, lldb::eErrorTypeExpression, msg);
   }
 
+  static Status
+  FromExpressionErrorDetails(lldb::ExpressionResults result,
+                             llvm::SmallVectorImpl<Detail> &&details) {
+    return Status(result, lldb::eErrorTypeExpression, std::move(details));
+  }
+
   /// Set the current error to errno.
   ///
   /// Update the error value to be \c errno and update the type to be \c
@@ -144,13 +179,24 @@ class Status {
   ///     success (non-erro), \b false otherwise.
   bool Success() const;
 
+  /// Get the list of details for this error. If this is non-empty,
+  /// clients can use this to render more appealing error messages
+  /// from the details. If you just want a pre-rendered string, use
+  /// AsCString() instead. Currently details are only used for
+  /// eErrorTypeExpression.
+  llvm::ArrayRef<Detail> GetDetails() const;
+
 protected:
+  /// Separate so the main constructor doesn't need to deal with the array.
+  Status(ValueType err, lldb::ErrorType type,
+         llvm::SmallVectorImpl<Detail> &&details);
   /// Status code as an integer value.
   ValueType m_code = 0;
   /// The type of the above error code.
   lldb::ErrorType m_type = lldb::eErrorTypeInvalid;
   /// A string representation of the error code.
   mutable std::string m_string;
+  llvm::SmallVector<Detail, 0> m_details;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Expression/DiagnosticManager.cpp b/lldb/source/Expression/DiagnosticManager.cpp
index a8330138f3d53b..5c20eba1dbd07e 100644
--- a/lldb/source/Expression/DiagnosticManager.cpp
+++ b/lldb/source/Expression/DiagnosticManager.cpp
@@ -65,6 +65,23 @@ std::string DiagnosticManager::GetString(char separator) {
   return ret;
 }
 
+Status DiagnosticManager::GetAsStatus(lldb::ExpressionResults result) {
+  llvm::SmallVector<Status::Detail, 0> details;
+  details.reserve(m_diagnostics.size());
+  for (const auto &diagnostic : m_diagnostics)
+    details.push_back(diagnostic->GetDetail());
+  return Status::FromExpressionErrorDetails(result, std::move(details));
+}
+
+void DiagnosticManager::AddDiagnostic(llvm::StringRef message,
+                                      lldb::Severity severity,
+                                      DiagnosticOrigin origin,
+                                      uint32_t compiler_id) {
+  m_diagnostics.emplace_back(std::make_unique<Diagnostic>(
+      origin, compiler_id,
+      Status::Detail{{}, severity, message.str(), message.str()}));
+}
+
 size_t DiagnosticManager::Printf(lldb::Severity severity, const char *format,
                                  ...) {
   StreamString ss;
@@ -85,3 +102,13 @@ void DiagnosticManager::PutString(lldb::Severity severity,
     return;
   AddDiagnostic(str, severity, eDiagnosticOriginLLDB);
 }
+
+void Diagnostic::AppendMessage(llvm::StringRef message,
+                               bool precede_with_newline) {
+  if (precede_with_newline) {
+    m_detail.message.push_back('\n');
+    m_detail.rendered.push_back('\n');
+  }
+  m_detail.message += message;
+  m_detail.rendered += message;
+}
diff --git a/lldb/source/Expression/UserExpression.cpp b/lldb/source/Expression/UserExpression.cpp
index c2889e4c986bfe..159714489ad111 100644
--- a/lldb/source/Expression/UserExpression.cpp
+++ b/lldb/source/Expression/UserExpression.cpp
@@ -328,18 +328,19 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,
     }
 
     if (!parse_success) {
-      std::string msg;
-      {
-        llvm::raw_string_ostream os(msg);
-        if (!diagnostic_manager.Diagnostics().empty())
-          os << diagnostic_manager.GetString();
-        else
-          os << "expression failed to parse (no further compiler diagnostics)";
-        if (target->GetEnableNotifyAboutFixIts() && fixed_expression &&
-            !fixed_expression->empty())
-          os << "\nfixed expression suggested:\n  " << *fixed_expression;
+      if (target->GetEnableNotifyAboutFixIts() && fixed_expression &&
+          !fixed_expression->empty()) {
+        std::string fixit =
+            "fixed expression suggested:\n  " + *fixed_expression;
+        diagnostic_manager.AddDiagnostic(fixit, lldb::eSeverityInfo,
+                                         eDiagnosticOriginLLDB);
       }
-      error = Status::FromExpressionError(execution_results, msg);
+      if (!diagnostic_manager.Diagnostics().size())
+        error = Status::FromExpressionError(
+            execution_results,
+            "expression failed to parse (no further compiler diagnostics)");
+      else
+        error = diagnostic_manager.GetAsStatus(execution_results);
     }
   }
 
@@ -384,8 +385,7 @@ UserExpression::Evaluate(ExecutionContext &exe_ctx,
           error = Status::FromExpressionError(
               execution_results, "expression failed to execute, unknown error");
         else
-          error = Status::FromExpressionError(execution_results,
-                                              diagnostic_manager.GetString());
+          error = diagnostic_manager.GetAsStatus(execution_results);
       } else {
         if (expr_result) {
           result_valobj_sp = expr_result->GetValueObject();
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h b/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
index 21abd71cc34eeb..f6e635afbf68ca 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangDiagnostic.h
@@ -29,9 +29,8 @@ class ClangDiagnostic : public Diagnostic {
     return diag->getKind() == eDiagnosticOriginClang;
   }
 
-  ClangDiagnostic(llvm::StringRef message, lldb::Severity severity,
-                  uint32_t compiler_id)
-      : Diagnostic(message, severity, eDiagnosticOriginClang, compiler_id) {}
+  ClangDiagnostic(Status::Detail detail, uint32_t compiler_id)
+      : Diagnostic(eDiagnosticOriginClang, compiler_id, detail) {}
 
   ~ClangDiagnostic() override = default;
 
diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
index 90f26de939a478..6b524250bbf4de 100644
--- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
+++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp
@@ -26,6 +26,7 @@
 #include "clang/Frontend/FrontendActions.h"
 #include "clang/Frontend/FrontendDiagnostic.h"
 #include "clang/Frontend/FrontendPluginRegistry.h"
+#include "clang/Frontend/TextDiagnostic.h"
 #include "clang/Frontend/TextDiagnosticBuffer.h"
 #include "clang/Frontend/TextDiagnosticPrinter.h"
 #include "clang/Lex/Preprocessor.h"
@@ -212,20 +213,20 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
     m_passthrough->HandleDiagnostic(DiagLevel, Info);
     m_os->flush();
 
-    lldb::Severity severity;
+    Status::Detail detail;
     bool make_new_diagnostic = true;
 
     switch (DiagLevel) {
     case DiagnosticsEngine::Level::Fatal:
     case DiagnosticsEngine::Level::Error:
-      severity = lldb::eSeverityError;
+      detail.severity = lldb::eSeverityError;
       break;
     case DiagnosticsEngine::Level::Warning:
-      severity = lldb::eSeverityWarning;
+      detail.severity = lldb::eSeverityWarning;
       break;
     case DiagnosticsEngine::Level::Remark:
     case DiagnosticsEngine::Level::Ignored:
-      severity = lldb::eSeverityInfo;
+      detail.severity = lldb::eSeverityInfo;
       break;
     case DiagnosticsEngine::Level::Note:
       m_manager->AppendMessageToDiagnostic(m_output);
@@ -254,14 +255,46 @@ class ClangDiagnosticManagerAdapter : public clang::DiagnosticConsumer {
       std::string stripped_output =
           std::string(llvm::StringRef(m_output).trim());
 
-      auto new_diagnostic = std::make_unique<ClangDiagnostic>(
-          stripped_output, severity, Info.getID());
+      // Translate the source location.
+      if (Info.hasSourceManager()) {
+        Status::Detail::SourceLocation loc;
+        clang::SourceManager &sm = Info.getSourceManager();
+        const clang::SourceLocation sloc = Info.getLocation();
+        if (sloc.isValid()) {
+          const clang::FullSourceLoc fsloc(sloc, sm);
+          clang::PresumedLoc PLoc = fsloc.getPresumedLoc(true);
+          StringRef filename =
+              PLoc.isValid() ? PLoc.getFilename() : StringRef{};
+          loc.file = FileSpec(filename);
+          loc.line = fsloc.getSpellingLineNumber();
+          loc.column = fsloc.getSpellingColumnNumber();
+          // A heuristic detecting the #line 1 "<user expression 1>".
+          loc.in_user_input = filename.starts_with("<user expression ");
+          // Find the range of the primary location.
+          for (const auto &range : Info.getRanges()) {
+            if (range.getBegin() == sloc) {
+              // FIXME: This is probably not handling wide characters correctly.
+              unsigned end_col = sm.getSpellingColumnNumber(range.getEnd());
+              if (end_col > loc.column)
+                loc.length = end_col - loc.column;
+              break;
+            }
+          }
+          detail.source_location = loc;
+        }
+      }
+      llvm::SmallString<0> msg;
+      Info.FormatDiagnostic(msg);
+      detail.message = msg.str();
+      detail.rendered = stripped_output;
+      auto new_diagnostic =
+          std::make_unique<ClangDiagnostic>(detail, Info.getID());
 
       // Don't store away warning fixits, since the compiler doesn't have
       // enough context in an expression for the warning to be useful.
       // FIXME: Should we try to filter out FixIts that apply to our generated
       // code, and not the user's expression?
-      if (severity == lldb::eSeverityError)
+      if (detail.severity == lldb::eSeverityError)
         AddAllFixIts(new_diagnostic.get(), Info);
 
       m_manager->AddDiagnostic(std::move(new_diagnostic));
diff --git a/lldb/source/Utility/Status.cpp b/lldb/source/Utility/Status.cpp
index 7260b7b3e0a03e..3b552e5540df61 100644
--- a/lldb/source/Utility/Status.cpp
+++ b/lldb/source/Utility/Status.cpp
@@ -37,10 +37,9 @@ class raw_ostream;
 using namespace lldb;
 using namespace lldb_private;
 
-Status::Status() {}
-
-Status::Status(ValueType err, ErrorType type, std::string msg)
-    : m_code(err), m_type(type), m_string(std::move(msg)) {}
+Status::Status(ValueType err, ErrorType type,
+               llvm::SmallVectorImpl<Status::Detail> &&details)
+    : m_code(err), m_type(type), m_details(std::move(details)) {}
 
 // This logic is confusing because c++ calls the traditional (posix) errno codes
 // "generic errors", while we use the term "generic" to mean completely
@@ -133,6 +132,19 @@ static std::string RetrieveWin32ErrorString(uint32_t error_code) {
 }
 #endif
 
+static const char *StringForSeverity(lldb::Severity severity) {
+  switch (severity) {
+  // this should be exhaustive
+  case lldb::eSeverityError:
+    return "error: ";
+  case lldb::eSeverityWarning:
+    return "warning: ";
+  case lldb::eSeverityInfo:
+    return "";
+  }
+  llvm_unreachable("switch needs another case for lldb::Severity enum");
+}
+
 // Get the error value as a NULL C string. The error string will be fetched and
 // cached on demand. The cached error string value will remain until the error
 // value is changed or cleared.
@@ -159,6 +171,11 @@ const char *Status::AsCString(const char *default_error_str) const {
 #endif
       break;
 
+    case eErrorTypeExpression: {
+      llvm::raw_string_ostream stream(m_string);
+      for (const auto &detail : m_details)
+        stream << StringForSeverity(detail.severity) << detail.rendered << '\n';
+    } break;
     default:
       break;
     }
diff --git a/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py b/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py
index 620b6e44fc852a..36e302be2525b5 100644
--- a/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py
+++ b/lldb/test/API/lang/objc/modules-compile-error/TestModulesCompileError.py
@@ -21,7 +21,7 @@ def test(self):
             "expr @import LLDBTestModule",
             error=True,
             substrs=[
-                "module.h:4:1: use of undeclared identifier 'syntax_error_for_lldb_to_find'",
+                "module.h:4:1: error: use of undeclared identifier 'syntax_error_for_lldb_to_find'",
                 "syntax_error_for_lldb_to_find // comment that tests source printing",
                 "could not build module 'LLDBTestModule'",
             ],
diff --git a/lldb/unittests/Expression/DiagnosticManagerTest.cpp b/lldb/unittests/Expression/DiagnosticManagerTest.cpp
index 05fe7c164d6818..bf554020ad8924 100644
--- a/lldb/unittests/Expression/DiagnosticManagerTest.cpp
+++ b/lldb/unittests/Expression/DiagnosticManagerTest.cpp
@@ -19,8 +19,8 @@ class FixItDiag : public Diagnostic {
 
 public:
   FixItDiag(llvm::StringRef msg, bool has_fixits)
-      : Diagnostic(msg, lldb::eSeverityError,
-                   DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id),
+      : Diagnostic(DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id,
+                   Status::Detail{{}, lldb::eSeverityError, msg.str(), {}}),
         m_has_fixits(has_fixits) {}
   bool HasFixIts() const override { return m_has_fixits; }
 };
@@ -30,8 +30,8 @@ namespace {
 class TextDiag : public Diagnostic {
 public:
   TextDiag(llvm::StringRef msg, lldb::Severity severity)
-      : Diagnostic(msg, severity, DiagnosticOrigin::eDiagnosticOriginLLDB,
-                   custom_diag_id) {}
+      : Diagnostic(DiagnosticOrigin::eDiagnosticOriginLLDB, custom_diag_id,
+                   Status::Detail{{}, severity, msg.str(), {}}) {}
 };
 } // namespace
 
@@ -42,8 +42,8 @@ TEST(DiagnosticManagerTest, AddDiagnostic) {
   std::string msg = "foo bar has happened";
   lldb::Severity severity = lldb::eSeverityError;
   DiagnosticOrigin origin = DiagnosticOrigin::eDiagnosticOriginLLDB;
-  auto diag =
-      std::make_unique<Diagnostic>(msg, severity, origin, custom_diag_id);
+  auto diag = std::make_unique<Diagnostic>(
+      origin, custom_diag_id, Status::Detail{{}, severity, msg, {}});
   mgr.AddDiagnostic(std::move(diag));
   EXPECT_EQ(1U, mgr.Diagnostics().size());
   const Diagnostic *got = mgr.Diagnostics().front().get();

>From 697e5e6a7d8644ff1dc372dac9b7e195454ea1c8 Mon Sep 17 00:00:00 2001
From: Adrian Prantl <aprantl at apple.com>
Date: Wed, 28 Aug 2024 16:19:21 -0700
Subject: [PATCH 2/2] [lldb] Inline expression evaluator error visualization
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

This patch is a reworking of Pete Lawrence's (@PortalPete) proposal
for better expression evaluator error messages:
https://github.com/llvm/llvm-project/pull/80938

Before:

```
$ lldb -o "expr a+b"
(lldb) expr a+b
error: <user expression 0>:1:1: use of undeclared identifier 'a'
a+b
^
error: <user expression 0>:1:3: use of undeclared identifier 'b'
a+b
  ^
```

After:

```
(lldb) expr a+b
            ^ ^
            │ ╰─ error: use of undeclared identifier 'b'
            ╰─ error: use of undeclared identifier 'a'
```

This eliminates the confusing `<user expression 0>:1:3` source
location and avoids echoing the expression to the console again, which
results in a cleaner presentation that makes it easier to grasp what's
going on.
---
 lldb/include/lldb/Interpreter/CommandAlias.h  |   2 +-
 lldb/include/lldb/Interpreter/CommandObject.h |  17 ++-
 .../lldb/Interpreter/CommandObjectMultiword.h |   8 +-
 lldb/source/API/SBCommandInterpreter.cpp      |   2 +-
 lldb/source/Commands/CommandObjectApropos.cpp |   2 +-
 lldb/source/Commands/CommandObjectApropos.h   |   2 +-
 .../Commands/CommandObjectBreakpoint.cpp      |  26 ++--
 .../CommandObjectBreakpointCommand.cpp        |   7 +-
 .../source/Commands/CommandObjectCommands.cpp |  30 ++---
 .../Commands/CommandObjectDWIMPrint.cpp       |   2 +-
 lldb/source/Commands/CommandObjectDWIMPrint.h |   2 +-
 .../Commands/CommandObjectDiagnostics.cpp     |   2 +-
 .../Commands/CommandObjectDisassemble.cpp     |   2 +-
 .../Commands/CommandObjectDisassemble.h       |   2 +-
 .../Commands/CommandObjectExpression.cpp      | 126 ++++++++++++++++--
 .../source/Commands/CommandObjectExpression.h |  11 +-
 lldb/source/Commands/CommandObjectFrame.cpp   |  20 +--
 lldb/source/Commands/CommandObjectGUI.cpp     |   2 +-
 lldb/source/Commands/CommandObjectGUI.h       |   2 +-
 lldb/source/Commands/CommandObjectHelp.cpp    |   2 +-
 lldb/source/Commands/CommandObjectHelp.h      |   2 +-
 lldb/source/Commands/CommandObjectLanguage.h  |   2 +-
 lldb/source/Commands/CommandObjectLog.cpp     |  18 +--
 lldb/source/Commands/CommandObjectMemory.cpp  |  10 +-
 .../Commands/CommandObjectMemoryTag.cpp       |   4 +-
 .../Commands/CommandObjectMultiword.cpp       |   7 +-
 .../source/Commands/CommandObjectPlatform.cpp |  44 +++---
 lldb/source/Commands/CommandObjectPlugin.cpp  |   2 +-
 lldb/source/Commands/CommandObjectProcess.cpp |  28 ++--
 lldb/source/Commands/CommandObjectQuit.cpp    |   2 +-
 lldb/source/Commands/CommandObjectQuit.h      |   2 +-
 .../Commands/CommandObjectRegexCommand.cpp    |   2 +-
 .../Commands/CommandObjectRegexCommand.h      |   2 +-
 .../source/Commands/CommandObjectRegister.cpp |   6 +-
 .../Commands/CommandObjectScripting.cpp       |   4 +-
 lldb/source/Commands/CommandObjectSession.cpp |   4 +-
 .../source/Commands/CommandObjectSettings.cpp |  22 +--
 lldb/source/Commands/CommandObjectSource.cpp  |   8 +-
 lldb/source/Commands/CommandObjectStats.cpp   |   6 +-
 lldb/source/Commands/CommandObjectTarget.cpp  |  62 ++++-----
 lldb/source/Commands/CommandObjectThread.cpp  |  26 ++--
 .../Commands/CommandObjectThreadUtil.cpp      |   4 +-
 .../source/Commands/CommandObjectThreadUtil.h |   4 +-
 lldb/source/Commands/CommandObjectTrace.cpp   |   8 +-
 lldb/source/Commands/CommandObjectType.cpp    |  30 ++---
 lldb/source/Commands/CommandObjectVersion.cpp |   2 +-
 lldb/source/Commands/CommandObjectVersion.h   |   2 +-
 .../Commands/CommandObjectWatchpoint.cpp      |  16 +--
 .../CommandObjectWatchpointCommand.cpp        |   6 +-
 lldb/source/Interpreter/CommandAlias.cpp      |   1 +
 .../source/Interpreter/CommandInterpreter.cpp |   9 +-
 lldb/source/Interpreter/CommandObject.cpp     |   6 +-
 .../ItaniumABI/ItaniumABILanguageRuntime.cpp  |   2 +-
 .../AppleObjCRuntime/AppleObjCRuntimeV2.cpp   |   4 +-
 .../Process/MacOSX-Kernel/ProcessKDP.cpp      |   2 +-
 .../Process/gdb-remote/ProcessGDBRemote.cpp   |  10 +-
 .../Process/minidump/ProcessMinidump.cpp      |   4 +-
 .../DarwinLog/StructuredDataDarwinLog.cpp     |   4 +-
 .../ctf/CommandObjectThreadTraceExportCTF.cpp |   2 +-
 .../ctf/CommandObjectThreadTraceExportCTF.h   |   2 +-
 lldb/source/Utility/Status.cpp                |   4 +-
 .../TestPersistentVariables.py                |   4 +-
 .../TestStaticInitializers.py                 |   2 +-
 .../TestTemplateFunctions.py                  |   2 +-
 .../test/API/lang/mixed/TestMixedLanguages.py |   2 +-
 lldb/test/Shell/Expr/TestObjCIDCast.test      |   2 +-
 .../test/Shell/Expr/TestObjCInCXXContext.test |   2 +-
 .../NativePDB/incomplete-tag-type.cpp         |   4 +-
 lldb/unittests/Interpreter/CMakeLists.txt     |   1 +
 .../TestCommandObjectExpression.cpp           |  27 ++++
 .../Interpreter/TestCommandPaths.cpp          |   3 +-
 71 files changed, 433 insertions(+), 270 deletions(-)
 create mode 100644 lldb/unittests/Interpreter/TestCommandObjectExpression.cpp

diff --git a/lldb/include/lldb/Interpreter/CommandAlias.h b/lldb/include/lldb/Interpreter/CommandAlias.h
index 7b59ea0a74bb9e..778d656a845506 100644
--- a/lldb/include/lldb/Interpreter/CommandAlias.h
+++ b/lldb/include/lldb/Interpreter/CommandAlias.h
@@ -56,7 +56,7 @@ class CommandAlias : public CommandObject {
 
   void SetHelpLong(llvm::StringRef str) override;
 
-  void Execute(const char *args_string, CommandReturnObject &result) override;
+  void Execute(const char *args_string,                        std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override;
 
   lldb::CommandObjectSP GetUnderlyingCommand() {
     return m_underlying_command_sp;
diff --git a/lldb/include/lldb/Interpreter/CommandObject.h b/lldb/include/lldb/Interpreter/CommandObject.h
index 20c4769af90338..9319b15f1be4dc 100644
--- a/lldb/include/lldb/Interpreter/CommandObject.h
+++ b/lldb/include/lldb/Interpreter/CommandObject.h
@@ -340,7 +340,11 @@ class CommandObject : public std::enable_shared_from_this<CommandObject> {
       return false;
   }
 
+  /// \param offset_in_command is on what column \c args_string
+  /// appears, if applicable. This enables diagnostics that refer back
+  /// to the user input.
   virtual void Execute(const char *args_string,
+                       std::optional<uint16_t> offset_in_command,
                        CommandReturnObject &result) = 0;
 
 protected:
@@ -421,10 +425,14 @@ class CommandObjectParsed : public CommandObject {
 
   ~CommandObjectParsed() override = default;
 
-  void Execute(const char *args_string, CommandReturnObject &result) override;
+  void Execute(const char *args_string,
+               std::optional<uint16_t> offset_in_command,
+               CommandReturnObject &result) override;
 
 protected:
-  virtual void DoExecute(Args &command, CommandReturnObject &result) = 0;
+  virtual void DoExecute(Args &command,
+                         std::optional<uint16_t> offset_in_command,
+                         CommandReturnObject &result) = 0;
 
   bool WantsRawCommandString() override { return false; }
 };
@@ -438,10 +446,13 @@ class CommandObjectRaw : public CommandObject {
 
   ~CommandObjectRaw() override = default;
 
-  void Execute(const char *args_string, CommandReturnObject &result) override;
+  void Execute(const char *args_string,
+               std::optional<uint16_t> offset_in_command,
+               CommandReturnObject &result) override;
 
 protected:
   virtual void DoExecute(llvm::StringRef command,
+                         std::optional<uint16_t> offset_in_command,
                          CommandReturnObject &result) = 0;
 
   bool WantsRawCommandString() override { return true; }
diff --git a/lldb/include/lldb/Interpreter/CommandObjectMultiword.h b/lldb/include/lldb/Interpreter/CommandObjectMultiword.h
index bceb7f0e51edb6..6f7c798dfeae69 100644
--- a/lldb/include/lldb/Interpreter/CommandObjectMultiword.h
+++ b/lldb/include/lldb/Interpreter/CommandObjectMultiword.h
@@ -59,7 +59,9 @@ class CommandObjectMultiword : public CommandObject {
   std::optional<std::string> GetRepeatCommand(Args &current_command_args,
                                               uint32_t index) override;
 
-  void Execute(const char *args_string, CommandReturnObject &result) override;
+  void Execute(const char *args_string,
+               std::optional<uint16_t> offset_in_command,
+               CommandReturnObject &result) override;
 
   bool IsRemovable() const override { return m_can_be_removed; }
 
@@ -129,7 +131,9 @@ class CommandObjectProxy : public CommandObject {
   ///     Execute is called) and \a GetProxyCommandObject returned null.
   virtual llvm::StringRef GetUnsupportedError();
 
-  void Execute(const char *args_string, CommandReturnObject &result) override;
+  void Execute(const char *args_string,
+               std::optional<uint16_t> offset_in_command,
+               CommandReturnObject &result) override;
 
 protected:
   // These two want to iterate over the subcommand dictionary.
diff --git a/lldb/source/API/SBCommandInterpreter.cpp b/lldb/source/API/SBCommandInterpreter.cpp
index 7a35473283684c..d9d769456ae594 100644
--- a/lldb/source/API/SBCommandInterpreter.cpp
+++ b/lldb/source/API/SBCommandInterpreter.cpp
@@ -71,7 +71,7 @@ class CommandPluginInterfaceImplementation : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     SBCommandReturnObject sb_return(result);
     SBCommandInterpreter sb_interpreter(&m_interpreter);
     SBDebugger debugger_sb(m_interpreter.GetDebugger().shared_from_this());
diff --git a/lldb/source/Commands/CommandObjectApropos.cpp b/lldb/source/Commands/CommandObjectApropos.cpp
index d663f2bd923fe2..13d1225f83fe6e 100644
--- a/lldb/source/Commands/CommandObjectApropos.cpp
+++ b/lldb/source/Commands/CommandObjectApropos.cpp
@@ -26,7 +26,7 @@ CommandObjectApropos::CommandObjectApropos(CommandInterpreter &interpreter)
 
 CommandObjectApropos::~CommandObjectApropos() = default;
 
-void CommandObjectApropos::DoExecute(Args &args, CommandReturnObject &result) {
+void CommandObjectApropos::DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) {
   const size_t argc = args.GetArgumentCount();
 
   if (argc == 1) {
diff --git a/lldb/source/Commands/CommandObjectApropos.h b/lldb/source/Commands/CommandObjectApropos.h
index f43420c1815d90..da83701cb15a7b 100644
--- a/lldb/source/Commands/CommandObjectApropos.h
+++ b/lldb/source/Commands/CommandObjectApropos.h
@@ -23,7 +23,7 @@ class CommandObjectApropos : public CommandObjectParsed {
   ~CommandObjectApropos() override;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command,               std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Commands/CommandObjectBreakpoint.cpp b/lldb/source/Commands/CommandObjectBreakpoint.cpp
index abde27b2b53ad8..46aad494e27a4e 100644
--- a/lldb/source/Commands/CommandObjectBreakpoint.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpoint.cpp
@@ -538,7 +538,7 @@ class CommandObjectBreakpointSet : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target =
         m_dummy_options.m_use_dummy ? GetDummyTarget() : GetTarget();
 
@@ -839,7 +839,7 @@ class CommandObjectBreakpointModify : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = m_dummy_opts.m_use_dummy ? GetDummyTarget() : GetTarget();
 
     std::unique_lock<std::recursive_mutex> lock;
@@ -903,7 +903,7 @@ class CommandObjectBreakpointEnable : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     std::unique_lock<std::recursive_mutex> lock;
@@ -1010,7 +1010,7 @@ the second re-enables the first location.");
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     std::unique_lock<std::recursive_mutex> lock;
     target.GetBreakpointList().GetListMutex(lock);
@@ -1148,7 +1148,7 @@ class CommandObjectBreakpointList : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = m_options.m_use_dummy ? GetDummyTarget() : GetTarget();
 
     const BreakpointList &breakpoints =
@@ -1267,7 +1267,7 @@ class CommandObjectBreakpointClear : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     // The following are the various types of breakpoints that could be
@@ -1416,7 +1416,7 @@ class CommandObjectBreakpointDelete : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = m_options.m_use_dummy ? GetDummyTarget() : GetTarget();
     result.Clear();
     
@@ -1669,7 +1669,7 @@ class CommandObjectBreakpointNameConfigure : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
 
     const size_t argc = command.GetArgumentCount();
     if (argc == 0) {
@@ -1758,7 +1758,7 @@ class CommandObjectBreakpointNameAdd : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (!m_name_options.m_name.OptionWasSet()) {
       result.AppendError("No name option provided.");
       return;
@@ -1832,7 +1832,7 @@ class CommandObjectBreakpointNameDelete : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (!m_name_options.m_name.OptionWasSet()) {
       result.AppendError("No name option provided.");
       return;
@@ -1896,7 +1896,7 @@ class CommandObjectBreakpointNameList : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target =
         m_name_options.m_use_dummy ? GetDummyTarget() : GetTarget();
 
@@ -2209,7 +2209,7 @@ class CommandObjectBreakpointRead : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     std::unique_lock<std::recursive_mutex> lock;
@@ -2319,7 +2319,7 @@ class CommandObjectBreakpointWrite : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     std::unique_lock<std::recursive_mutex> lock;
diff --git a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
index b668cd0f7c22f0..08b72bc26c3b75 100644
--- a/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectBreakpointCommand.cpp
@@ -319,9 +319,8 @@ are no syntax errors may indicate that a function was declared but never called.
     bool m_stop_on_error;
     bool m_use_dummy;
   };
-
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = m_options.m_use_dummy ? GetDummyTarget() : GetTarget();
 
     const BreakpointList &breakpoints = target.GetBreakpointList();
@@ -479,7 +478,7 @@ class CommandObjectBreakpointCommandDelete : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = m_options.m_use_dummy ? GetDummyTarget() : GetTarget();
 
     const BreakpointList &breakpoints = target.GetBreakpointList();
@@ -546,7 +545,7 @@ class CommandObjectBreakpointCommandList : public CommandObjectParsed {
   ~CommandObjectBreakpointCommandList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     const BreakpointList &breakpoints = target.GetBreakpointList();
diff --git a/lldb/source/Commands/CommandObjectCommands.cpp b/lldb/source/Commands/CommandObjectCommands.cpp
index f8f2b97eb898fa..961bae2dd1d55b 100644
--- a/lldb/source/Commands/CommandObjectCommands.cpp
+++ b/lldb/source/Commands/CommandObjectCommands.cpp
@@ -110,7 +110,7 @@ class CommandObjectCommandsSource : public CommandObjectParsed {
     OptionValueBoolean m_cmd_relative_to_command_file;
   };
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command,                std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override {
     if (command.GetArgumentCount() != 1) {
       result.AppendErrorWithFormat(
           "'%s' takes exactly one executable filename argument.\n",
@@ -370,7 +370,7 @@ other command as far as there is only one alias command match.");
   ~CommandObjectCommandsAlias() override = default;
 
 protected:
-  void DoExecute(llvm::StringRef raw_command_line,
+  void DoExecute(llvm::StringRef raw_command_line, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     if (raw_command_line.empty()) {
       result.AppendError("'command alias' requires at least two arguments");
@@ -625,7 +625,7 @@ class CommandObjectCommandsUnalias : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args,                std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override {
     CommandObject::CommandMap::iterator pos;
     CommandObject *cmd_obj;
 
@@ -701,7 +701,7 @@ class CommandObjectCommandsDelete : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args,                std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override {
     CommandObject::CommandMap::iterator pos;
 
     if (args.empty()) {
@@ -825,7 +825,7 @@ a number follows 'f':"
     }
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
     if (argc == 0) {
       result.AppendError("usage: 'command regex <command-name> "
@@ -1082,7 +1082,7 @@ class CommandObjectPythonFunction : public CommandObjectRaw {
   bool WantsCompletion() override { return true; }
 
 protected:
-  void DoExecute(llvm::StringRef raw_command_line,
+  void DoExecute(llvm::StringRef raw_command_line, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
 
@@ -1190,7 +1190,7 @@ class CommandObjectScriptingObjectRaw : public CommandObjectRaw {
   }
 
 protected:
-  void DoExecute(llvm::StringRef raw_command_line,
+  void DoExecute(llvm::StringRef raw_command_line, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
 
@@ -1931,7 +1931,7 @@ class CommandObjectScriptingObjectParsed : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args,
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     ScriptInterpreter *scripter = GetDebugger().GetScriptInterpreter();
 
@@ -2023,7 +2023,7 @@ class CommandObjectCommandsScriptImport : public CommandObjectParsed {
     bool silent = false;
   };
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.empty()) {
       result.AppendError("command script import needs one or more arguments");
       return;
@@ -2250,7 +2250,7 @@ class CommandObjectCommandsScriptAdd : public CommandObjectParsed,
     io_handler.SetIsDone(true);
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (GetDebugger().GetScriptLanguage() != lldb::eScriptLanguagePython) {
       result.AppendError("only scripting language supported for scripted "
                          "commands is currently Python");
@@ -2373,7 +2373,7 @@ class CommandObjectCommandsScriptList : public CommandObjectParsed {
 
   ~CommandObjectCommandsScriptList() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     m_interpreter.GetHelp(result, CommandInterpreter::eCommandTypesUserDef);
 
     result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -2391,7 +2391,7 @@ class CommandObjectCommandsScriptClear : public CommandObjectParsed {
   ~CommandObjectCommandsScriptClear() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     m_interpreter.RemoveAllUser();
 
     result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -2420,7 +2420,7 @@ class CommandObjectCommandsScriptDelete : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
 
     llvm::StringRef root_cmd = command[0].ref();
     size_t num_args = command.GetArgumentCount();
@@ -2604,7 +2604,7 @@ class CommandObjectCommandsContainerAdd : public CommandObjectParsed {
     std::string m_long_help;
     bool m_overwrite = false;
   };
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     size_t num_args = command.GetArgumentCount();
 
     if (num_args == 0) {
@@ -2684,7 +2684,7 @@ class CommandObjectCommandsContainerDelete : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     size_t num_args = command.GetArgumentCount();
 
     if (num_args == 0) {
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.cpp b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
index b7cd955e00203d..0d4893c1b12a79 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.cpp
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.cpp
@@ -50,7 +50,7 @@ CommandObjectDWIMPrint::CommandObjectDWIMPrint(CommandInterpreter &interpreter)
 
 Options *CommandObjectDWIMPrint::GetOptions() { return &m_option_group; }
 
-void CommandObjectDWIMPrint::DoExecute(StringRef command,
+void CommandObjectDWIMPrint::DoExecute(StringRef command,std::optional<uint16_t> offset_in_command,
                                        CommandReturnObject &result) {
   m_option_group.NotifyOptionParsingStarting(&m_exe_ctx);
   OptionsWithRaw args{command};
diff --git a/lldb/source/Commands/CommandObjectDWIMPrint.h b/lldb/source/Commands/CommandObjectDWIMPrint.h
index 01ba9c225e3301..a5b401856e618e 100644
--- a/lldb/source/Commands/CommandObjectDWIMPrint.h
+++ b/lldb/source/Commands/CommandObjectDWIMPrint.h
@@ -40,7 +40,7 @@ class CommandObjectDWIMPrint : public CommandObjectRaw {
   bool WantsCompletion() override { return true; }
 
 private:
-  void DoExecute(llvm::StringRef command, CommandReturnObject &result) override;
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 
   OptionGroupOptions m_option_group;
   OptionGroupFormat m_format_options = lldb::eFormatDefault;
diff --git a/lldb/source/Commands/CommandObjectDiagnostics.cpp b/lldb/source/Commands/CommandObjectDiagnostics.cpp
index ac87f869f01272..85e9fca3f01dd2 100644
--- a/lldb/source/Commands/CommandObjectDiagnostics.cpp
+++ b/lldb/source/Commands/CommandObjectDiagnostics.cpp
@@ -77,7 +77,7 @@ class CommandObjectDiagnosticsDump : public CommandObjectParsed {
     return Diagnostics::CreateUniqueDirectory();
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args,                std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override {
     llvm::Expected<FileSpec> directory = GetDirectory();
 
     if (!directory) {
diff --git a/lldb/source/Commands/CommandObjectDisassemble.cpp b/lldb/source/Commands/CommandObjectDisassemble.cpp
index 250f849ac04c55..0b0488f71b64a2 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.cpp
+++ b/lldb/source/Commands/CommandObjectDisassemble.cpp
@@ -438,7 +438,7 @@ CommandObjectDisassemble::GetRangesForSelectedMode(
   return CommandObjectDisassemble::GetPCRanges();
 }
 
-void CommandObjectDisassemble::DoExecute(Args &command,
+void CommandObjectDisassemble::DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
                                          CommandReturnObject &result) {
   Target &target = GetTarget();
 
diff --git a/lldb/source/Commands/CommandObjectDisassemble.h b/lldb/source/Commands/CommandObjectDisassemble.h
index 2e4d46dd0ec586..1a553bc6b03122 100644
--- a/lldb/source/Commands/CommandObjectDisassemble.h
+++ b/lldb/source/Commands/CommandObjectDisassemble.h
@@ -73,7 +73,7 @@ class CommandObjectDisassemble : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 
   llvm::Expected<std::vector<AddressRange>>
   GetRangesForSelectedMode(CommandReturnObject &result);
diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp
index 771194638e1b65..f514c5a2a57c0c 100644
--- a/lldb/source/Commands/CommandObjectExpression.cpp
+++ b/lldb/source/Commands/CommandObjectExpression.cpp
@@ -398,10 +398,104 @@ CanBeUsedForElementCountPrinting(ValueObject &valobj) {
   return Status();
 }
 
-bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
-                                                 Stream &output_stream,
-                                                 Stream &error_stream,
-                                                 CommandReturnObject &result) {
+static llvm::raw_ostream &PrintSeverity(Stream &stream, lldb::Severity severity) {
+  llvm::HighlightColor color;
+  llvm::StringRef text;
+  switch (severity) {
+  case eSeverityError:
+    color = llvm::HighlightColor::Error;
+    text = "error: ";
+    break;
+  case eSeverityWarning:
+    color = llvm::HighlightColor::Warning;
+    text = "warning: ";
+    break;
+  case eSeverityInfo:
+    color = llvm::HighlightColor::Remark;
+    text = "note: ";
+    break;
+  }
+  return llvm::WithColor(stream.AsRawOstream(), color, llvm::ColorMode::Enable)
+         << text;
+}
+
+std::string
+CommandObjectExpression::RenderError(std::optional<uint16_t> offset_in_command,
+                                     Status error) {
+  if (error.GetDetails().empty())
+    return {};
+
+  StreamString stream(true);
+  if (!offset_in_command) {
+    for (const Status::Detail &detail : error.GetDetails()) {
+      PrintSeverity(stream, detail.severity);
+      stream << detail.rendered << '\n';
+    }
+    return stream.GetData();
+  }
+
+  // Print a line with caret indicator(s) below the lldb prompt + command.
+  const size_t padding = *offset_in_command;
+  stream << std::string(padding, ' ');
+
+  size_t offset = 1;
+  std::vector<Status::Detail> remaining_details, other_details;
+  for (const Status::Detail &detail : error.GetDetails()) {
+    if (!detail.source_location) {
+      other_details.push_back(detail);
+      continue;
+    }
+
+    auto &loc = *detail.source_location;
+    remaining_details.push_back(detail);
+    if (offset > loc.column)
+      continue;
+    stream << std::string(loc.column - offset, ' ') << '^';
+    if (loc.length > 1)
+      stream << std::string(loc.length - 1, '~');
+    offset = loc.column + 1;
+  }
+  stream << '\n';
+
+  // Work through each detail in reverse order using the vector/stack.
+  for (auto detail = remaining_details.rbegin();
+       detail != remaining_details.rend();
+       ++detail, remaining_details.pop_back()) {
+    // Get the information to print this detail and remove it from the stack.
+    // Print all the lines for all the other messages first.
+    stream << std::string(padding, ' ');
+    size_t offset = 1;
+    for (auto &remaining_detail :
+         llvm::ArrayRef(remaining_details).drop_back(1)) {
+      uint16_t column = remaining_detail.source_location->column;
+      stream << std::string(column - offset, ' ') << "│";
+      offset = column + 1;
+    }
+
+    // Print the line connecting the ^ with the error message.
+    uint16_t column = detail->source_location->column;
+    if (offset <= column)
+      stream << std::string(column - offset, ' ') << "╰─ ";
+
+    // Print a colorized string based on the message's severity type.
+    PrintSeverity(stream, detail->severity);
+
+    // Finally, print the message and start a new line.
+    stream << detail->message << '\n';
+  }
+
+  // Print the non-located details.
+  for (const Status::Detail &detail : other_details) {
+    PrintSeverity(stream, detail.severity);
+    stream << detail.message << '\n';
+  }
+
+  return stream.GetData();
+}
+
+bool CommandObjectExpression::EvaluateExpression(
+    llvm::StringRef expr, std::optional<uint16_t> offset_in_command,
+    Stream &output_stream, Stream &error_stream, CommandReturnObject &result) {
   // Don't use m_exe_ctx as this might be called asynchronously after the
   // command object DoExecute has finished when doing multi-line expression
   // that use an input reader...
@@ -486,6 +580,22 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
 
         result.SetStatus(eReturnStatusSuccessFinishResult);
       } else {
+        //llvm::StringRef command = line.empty() ? m_repeat_command : line;
+        std::string error =
+            RenderError(offset_in_command, result_valobj_sp->GetError());
+        if (!error.empty()) {
+//          // Check whether the developer just hit [Return] to repeat a command.
+//          if (line.empty()) {
+//            // Build a recreation of the prompt and the last command.
+//            std::string prompt_and_command(GetDebugger().GetPrompt());
+//            prompt_and_command += m_repeat_command;
+// 
+//            // Print the last command the developer entered for the caret line.
+//            PrintCommandOutput(io_handler, prompt_and_command, false);
+          error_stream.PutCString(error.c_str());
+        }
+        else{
+
         const char *error_cstr = result_valobj_sp->GetError().AsCString();
         if (error_cstr && error_cstr[0]) {
           const size_t error_cstr_len = strlen(error_cstr);
@@ -498,7 +608,7 @@ bool CommandObjectExpression::EvaluateExpression(llvm::StringRef expr,
         } else {
           error_stream.PutCString("error: unknown error\n");
         }
-
+        }
         result.SetStatus(eReturnStatusFailed);
       }
     }
@@ -518,7 +628,7 @@ void CommandObjectExpression::IOHandlerInputComplete(IOHandler &io_handler,
 
   CommandReturnObject return_obj(
       GetCommandInterpreter().GetDebugger().GetUseColor());
-  EvaluateExpression(line.c_str(), *output_sp, *error_sp, return_obj);
+  EvaluateExpression(line.c_str(), {}, *output_sp, *error_sp, return_obj);
   if (output_sp)
     output_sp->Flush();
   if (error_sp)
@@ -586,7 +696,7 @@ GetExprOptions(ExecutionContext &ctx,
   return expr_options;
 }
 
-void CommandObjectExpression::DoExecute(llvm::StringRef command,
+void CommandObjectExpression::DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                                         CommandReturnObject &result) {
   m_fixed_expression.clear();
   auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
@@ -666,7 +776,7 @@ void CommandObjectExpression::DoExecute(llvm::StringRef command,
   }
 
   Target &target = GetTarget();
-  if (EvaluateExpression(expr, result.GetOutputStream(),
+  if (EvaluateExpression(expr, offset_in_command, result.GetOutputStream(),
                          result.GetErrorStream(), result)) {
 
     if (!m_fixed_expression.empty() && target.GetEnableNotifyAboutFixIts()) {
diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h
index 6fccf10e5dbc1d..7be1e559b20e7a 100644
--- a/lldb/source/Commands/CommandObjectExpression.h
+++ b/lldb/source/Commands/CommandObjectExpression.h
@@ -67,6 +67,9 @@ class CommandObjectExpression : public CommandObjectRaw,
 
   void HandleCompletion(CompletionRequest &request) override;
 
+  static std::string RenderError(std::optional<uint16_t> offset_in_command,
+                                 Status error);
+
 protected:
   // IOHandler::Delegate functions
   void IOHandlerInputComplete(IOHandler &io_handler,
@@ -75,7 +78,7 @@ class CommandObjectExpression : public CommandObjectRaw,
   bool IOHandlerIsInputComplete(IOHandler &io_handler,
                                 StringList &lines) override;
 
-  void DoExecute(llvm::StringRef command, CommandReturnObject &result) override;
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 
   /// Evaluates the given expression.
   /// \param output_stream The stream to which the evaluation result will be
@@ -87,8 +90,10 @@ class CommandObjectExpression : public CommandObjectRaw,
   ///               whether the expression produced any result.
   /// \return Returns true iff the expression was successfully evaluated,
   ///         executed and the result could be printed to the output stream.
-  bool EvaluateExpression(llvm::StringRef expr, Stream &output_stream,
-                          Stream &error_stream, CommandReturnObject &result);
+  bool EvaluateExpression(llvm::StringRef expr,
+                          std::optional<uint16_t> offset_in_command,
+                          Stream &output_stream, Stream &error_stream,
+                          CommandReturnObject &result);
 
   void GetMultilineExpression();
 
diff --git a/lldb/source/Commands/CommandObjectFrame.cpp b/lldb/source/Commands/CommandObjectFrame.cpp
index d8091e8993fde1..8724fdf09d379f 100644
--- a/lldb/source/Commands/CommandObjectFrame.cpp
+++ b/lldb/source/Commands/CommandObjectFrame.cpp
@@ -121,7 +121,7 @@ class CommandObjectFrameDiagnose : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Thread *thread = m_exe_ctx.GetThreadPtr();
     StackFrameSP frame_sp = thread->GetSelectedFrame(SelectMostRelevantFrame);
 
@@ -194,7 +194,7 @@ class CommandObjectFrameInfo : public CommandObjectParsed {
   ~CommandObjectFrameInfo() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     m_exe_ctx.GetFrameRef().DumpUsingSettingsFormat(&result.GetOutputStream());
     result.SetStatus(eReturnStatusSuccessFinishResult);
   }
@@ -265,7 +265,7 @@ class CommandObjectFrameSelect : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // No need to check "thread" for validity as eCommandRequiresThread ensures
     // it is valid
     Thread *thread = m_exe_ctx.GetThreadPtr();
@@ -494,7 +494,7 @@ may even involve JITing and running code in the target program.)");
     return std::nullopt;
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // No need to check "frame" for validity as eCommandRequiresFrame ensures
     // it is valid
     StackFrame *frame = m_exe_ctx.GetFramePtr();
@@ -796,7 +796,7 @@ class CommandObjectFrameRecognizerAdd : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 
 public:
   CommandObjectFrameRecognizerAdd(CommandInterpreter &interpreter)
@@ -852,7 +852,7 @@ Process 1234 stopped
   ~CommandObjectFrameRecognizerAdd() override = default;
 };
 
-void CommandObjectFrameRecognizerAdd::DoExecute(Args &command,
+void CommandObjectFrameRecognizerAdd::DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
                                                 CommandReturnObject &result) {
 #if LLDB_ENABLE_PYTHON
   if (m_options.m_class_name.empty()) {
@@ -923,7 +923,7 @@ class CommandObjectFrameRecognizerClear : public CommandObjectParsed {
   ~CommandObjectFrameRecognizerClear() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     GetTarget().GetFrameRecognizerManager().RemoveAllRecognizers();
     result.SetStatus(eReturnStatusSuccessFinishResult);
   }
@@ -990,7 +990,7 @@ class CommandObjectFrameRecognizerDelete : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.GetArgumentCount() == 0) {
       if (!m_interpreter.Confirm(
               "About to delete all frame recognizers, do you want to do that?",
@@ -1037,7 +1037,7 @@ class CommandObjectFrameRecognizerList : public CommandObjectParsed {
   ~CommandObjectFrameRecognizerList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     bool any_printed = false;
     GetTarget().GetFrameRecognizerManager().ForEach(
         [&result,
@@ -1081,7 +1081,7 @@ class CommandObjectFrameRecognizerInfo : public CommandObjectParsed {
   ~CommandObjectFrameRecognizerInfo() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const char *frame_index_str = command.GetArgumentAtIndex(0);
     uint32_t frame_index;
     if (!llvm::to_integer(frame_index_str, frame_index)) {
diff --git a/lldb/source/Commands/CommandObjectGUI.cpp b/lldb/source/Commands/CommandObjectGUI.cpp
index b56e49b073b03e..1d7b6e8e52aa64 100644
--- a/lldb/source/Commands/CommandObjectGUI.cpp
+++ b/lldb/source/Commands/CommandObjectGUI.cpp
@@ -24,7 +24,7 @@ CommandObjectGUI::CommandObjectGUI(CommandInterpreter &interpreter)
 
 CommandObjectGUI::~CommandObjectGUI() = default;
 
-void CommandObjectGUI::DoExecute(Args &args, CommandReturnObject &result) {
+void CommandObjectGUI::DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) {
 #if LLDB_ENABLE_CURSES
   Debugger &debugger = GetDebugger();
 
diff --git a/lldb/source/Commands/CommandObjectGUI.h b/lldb/source/Commands/CommandObjectGUI.h
index fde4342724c9dd..5a9959ed547907 100644
--- a/lldb/source/Commands/CommandObjectGUI.h
+++ b/lldb/source/Commands/CommandObjectGUI.h
@@ -22,7 +22,7 @@ class CommandObjectGUI : public CommandObjectParsed {
   ~CommandObjectGUI() override;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override;
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Commands/CommandObjectHelp.cpp b/lldb/source/Commands/CommandObjectHelp.cpp
index f1dbd03fe97cbd..2fa600635d400b 100644
--- a/lldb/source/Commands/CommandObjectHelp.cpp
+++ b/lldb/source/Commands/CommandObjectHelp.cpp
@@ -63,7 +63,7 @@ CommandObjectHelp::CommandOptions::GetDefinitions() {
   return llvm::ArrayRef(g_help_options);
 }
 
-void CommandObjectHelp::DoExecute(Args &command, CommandReturnObject &result) {
+void CommandObjectHelp::DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) {
   CommandObject::CommandMap::iterator pos;
   CommandObject *cmd_obj;
   const size_t argc = command.GetArgumentCount();
diff --git a/lldb/source/Commands/CommandObjectHelp.h b/lldb/source/Commands/CommandObjectHelp.h
index 9b2c89e6654fad..029356144054f8 100644
--- a/lldb/source/Commands/CommandObjectHelp.h
+++ b/lldb/source/Commands/CommandObjectHelp.h
@@ -76,7 +76,7 @@ class CommandObjectHelp : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command,                std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override;
 
 private:
   CommandOptions m_options;
diff --git a/lldb/source/Commands/CommandObjectLanguage.h b/lldb/source/Commands/CommandObjectLanguage.h
index 2f9f8fecc80da3..11ac7d0c19ca44 100644
--- a/lldb/source/Commands/CommandObjectLanguage.h
+++ b/lldb/source/Commands/CommandObjectLanguage.h
@@ -19,7 +19,7 @@ class CommandObjectLanguage : public CommandObjectMultiword {
   ~CommandObjectLanguage() override;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result);
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result);
 };
 } // namespace lldb_private
 
diff --git a/lldb/source/Commands/CommandObjectLog.cpp b/lldb/source/Commands/CommandObjectLog.cpp
index 9eb68ddb73b6e9..bb05cf43a368a1 100644
--- a/lldb/source/Commands/CommandObjectLog.cpp
+++ b/lldb/source/Commands/CommandObjectLog.cpp
@@ -160,7 +160,7 @@ class CommandObjectLogEnable : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (args.GetArgumentCount() < 2) {
       result.AppendErrorWithFormat(
           "%s takes a log channel and one or more log types.\n",
@@ -254,7 +254,7 @@ class CommandObjectLogDisable : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (args.empty()) {
       result.AppendErrorWithFormat(
           "%s takes a log channel and one or more log types.\n",
@@ -299,7 +299,7 @@ class CommandObjectLogList : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     std::string output;
     llvm::raw_string_ostream output_stream(output);
     if (args.empty()) {
@@ -369,7 +369,7 @@ class CommandObjectLogDump : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (args.empty()) {
       result.AppendErrorWithFormat(
           "%s takes a log channel and one or more log types.\n",
@@ -424,7 +424,7 @@ class CommandObjectLogTimerEnable : public CommandObjectParsed {
   ~CommandObjectLogTimerEnable() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusFailed);
 
     if (args.GetArgumentCount() == 0) {
@@ -459,7 +459,7 @@ class CommandObjectLogTimerDisable : public CommandObjectParsed {
   ~CommandObjectLogTimerDisable() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Timer::DumpCategoryTimes(result.GetOutputStream());
     Timer::SetDisplayDepth(0);
     result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -481,7 +481,7 @@ class CommandObjectLogTimerDump : public CommandObjectParsed {
   ~CommandObjectLogTimerDump() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Timer::DumpCategoryTimes(result.GetOutputStream());
     result.SetStatus(eReturnStatusSuccessFinishResult);
 
@@ -503,7 +503,7 @@ class CommandObjectLogTimerReset : public CommandObjectParsed {
   ~CommandObjectLogTimerReset() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Timer::ResetCategoryTimes();
     result.SetStatus(eReturnStatusSuccessFinishResult);
 
@@ -534,7 +534,7 @@ class CommandObjectLogTimerIncrement : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusFailed);
 
     if (args.GetArgumentCount() == 1) {
diff --git a/lldb/source/Commands/CommandObjectMemory.cpp b/lldb/source/Commands/CommandObjectMemory.cpp
index f93081d3f45a19..46b8cc9a41cd2d 100644
--- a/lldb/source/Commands/CommandObjectMemory.cpp
+++ b/lldb/source/Commands/CommandObjectMemory.cpp
@@ -348,7 +348,7 @@ class CommandObjectMemoryRead : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // No need to check "target" for validity as eCommandRequiresTarget ensures
     // it is valid
     Target *target = m_exe_ctx.GetTargetPtr();
@@ -980,7 +980,7 @@ class CommandObjectMemoryFind : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // No need to check "process" for validity as eCommandRequiresProcess
     // ensures it is valid
     Process *process = m_exe_ctx.GetProcessPtr();
@@ -1232,7 +1232,7 @@ class CommandObjectMemoryWrite : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // No need to check "process" for validity as eCommandRequiresProcess
     // ensures it is valid
     Process *process = m_exe_ctx.GetProcessPtr();
@@ -1536,7 +1536,7 @@ class CommandObjectMemoryHistory : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc == 0 || argc > 1) {
@@ -1687,7 +1687,7 @@ class CommandObjectMemoryRegion : public CommandObjectParsed {
     }
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
     if (!process_sp) {
       m_prev_end_addr = LLDB_INVALID_ADDRESS;
diff --git a/lldb/source/Commands/CommandObjectMemoryTag.cpp b/lldb/source/Commands/CommandObjectMemoryTag.cpp
index f45d6eacab3d0e..a6755e9d2f3106 100644
--- a/lldb/source/Commands/CommandObjectMemoryTag.cpp
+++ b/lldb/source/Commands/CommandObjectMemoryTag.cpp
@@ -42,7 +42,7 @@ class CommandObjectMemoryTagRead : public CommandObjectParsed {
   ~CommandObjectMemoryTagRead() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if ((command.GetArgumentCount() < 1) || (command.GetArgumentCount() > 2)) {
       result.AppendError(
           "wrong number of arguments; expected at least <address-expression>, "
@@ -194,7 +194,7 @@ class CommandObjectMemoryTagWrite : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.GetArgumentCount() < 2) {
       result.AppendError("wrong number of arguments; expected "
                          "<address-expression> <tag> [<tag> [...]]");
diff --git a/lldb/source/Commands/CommandObjectMultiword.cpp b/lldb/source/Commands/CommandObjectMultiword.cpp
index 4efa5652a71703..2e600b9d5413b8 100644
--- a/lldb/source/Commands/CommandObjectMultiword.cpp
+++ b/lldb/source/Commands/CommandObjectMultiword.cpp
@@ -160,6 +160,7 @@ llvm::Error CommandObjectMultiword::RemoveUserSubcommand(llvm::StringRef cmd_nam
 }
 
 void CommandObjectMultiword::Execute(const char *args_string,
+                                     std::optional<uint16_t> offset_in_command,
                                      CommandReturnObject &result) {
   Args args(args_string);
   const size_t argc = args.GetArgumentCount();
@@ -188,7 +189,7 @@ void CommandObjectMultiword::Execute(const char *args_string,
     // the processed arguments.
 
     args.Shift();
-    sub_cmd_obj->Execute(args_string, result);
+    sub_cmd_obj->Execute(args_string, {}, result);
     return;
   }
 
@@ -428,10 +429,10 @@ llvm::StringRef CommandObjectProxy::GetUnsupportedError() {
   return "command is not implemented";
 }
 
-void CommandObjectProxy::Execute(const char *args_string,
+void CommandObjectProxy::Execute(const char *args_string,                       std::optional<uint16_t> offset_in_command,
                                  CommandReturnObject &result) {
   if (CommandObject *proxy_command = GetProxyCommandObject())
-    proxy_command->Execute(args_string, result);
+    proxy_command->Execute(args_string, offset_in_command, result);
   else
     result.AppendError(GetUnsupportedError());
 }
diff --git a/lldb/source/Commands/CommandObjectPlatform.cpp b/lldb/source/Commands/CommandObjectPlatform.cpp
index f849a3815278a4..f23f6826363ef2 100644
--- a/lldb/source/Commands/CommandObjectPlatform.cpp
+++ b/lldb/source/Commands/CommandObjectPlatform.cpp
@@ -168,7 +168,7 @@ class CommandObjectPlatformSelect : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (args.GetArgumentCount() == 1) {
       const char *platform_name = args.GetArgumentAtIndex(0);
       if (platform_name && platform_name[0]) {
@@ -210,7 +210,7 @@ class CommandObjectPlatformList : public CommandObjectParsed {
   ~CommandObjectPlatformList() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &ostrm = result.GetOutputStream();
     ostrm.Printf("Available platforms:\n");
 
@@ -247,7 +247,7 @@ class CommandObjectPlatformStatus : public CommandObjectParsed {
   ~CommandObjectPlatformStatus() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &ostrm = result.GetOutputStream();
 
     Target *target = GetDebugger().GetSelectedTarget().get();
@@ -281,7 +281,7 @@ class CommandObjectPlatformConnect : public CommandObjectParsed {
   ~CommandObjectPlatformConnect() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &ostrm = result.GetOutputStream();
 
     PlatformSP platform_sp(
@@ -328,7 +328,7 @@ class CommandObjectPlatformDisconnect : public CommandObjectParsed {
   ~CommandObjectPlatformDisconnect() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -387,7 +387,7 @@ class CommandObjectPlatformSettings : public CommandObjectParsed {
   ~CommandObjectPlatformSettings() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -421,7 +421,7 @@ class CommandObjectPlatformMkDir : public CommandObjectParsed {
 
   ~CommandObjectPlatformMkDir() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -469,7 +469,7 @@ class CommandObjectPlatformFOpen : public CommandObjectParsed {
 
   ~CommandObjectPlatformFOpen() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -522,7 +522,7 @@ class CommandObjectPlatformFClose : public CommandObjectParsed {
 
   ~CommandObjectPlatformFClose() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -564,7 +564,7 @@ class CommandObjectPlatformFRead : public CommandObjectParsed {
 
   ~CommandObjectPlatformFRead() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -658,7 +658,7 @@ class CommandObjectPlatformFWrite : public CommandObjectParsed {
 
   ~CommandObjectPlatformFWrite() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -812,7 +812,7 @@ class CommandObjectPlatformGetFile : public CommandObjectParsed {
           GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // If the number of arguments is incorrect, issue an error message.
     if (args.GetArgumentCount() != 2) {
       result.AppendError("required arguments missing; specify both the "
@@ -861,7 +861,7 @@ class CommandObjectPlatformGetSize : public CommandObjectParsed {
 
   ~CommandObjectPlatformGetSize() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // If the number of arguments is incorrect, issue an error message.
     if (args.GetArgumentCount() != 1) {
       result.AppendError("required argument missing; specify the source file "
@@ -909,7 +909,7 @@ class CommandObjectPlatformGetPermissions : public CommandObjectParsed {
 
   ~CommandObjectPlatformGetPermissions() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // If the number of arguments is incorrect, issue an error message.
     if (args.GetArgumentCount() != 1) {
       result.AppendError("required argument missing; specify the source file "
@@ -956,7 +956,7 @@ class CommandObjectPlatformFileExists : public CommandObjectParsed {
 
   ~CommandObjectPlatformFileExists() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // If the number of arguments is incorrect, issue an error message.
     if (args.GetArgumentCount() != 1) {
       result.AppendError("required argument missing; specify the source file "
@@ -1017,7 +1017,7 @@ class CommandObjectPlatformPutFile : public CommandObjectParsed {
           nullptr);
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const char *src = args.GetArgumentAtIndex(0);
     const char *dst = args.GetArgumentAtIndex(1);
 
@@ -1071,7 +1071,7 @@ class CommandObjectPlatformProcessLaunch : public CommandObjectParsed {
   Options *GetOptions() override { return &m_all_options; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = GetDebugger().GetSelectedTarget().get();
     PlatformSP platform_sp;
     if (target) {
@@ -1220,7 +1220,7 @@ class CommandObjectPlatformProcessList : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = GetDebugger().GetSelectedTarget().get();
     PlatformSP platform_sp;
     if (target) {
@@ -1468,7 +1468,7 @@ class CommandObjectPlatformProcessInfo : public CommandObjectParsed {
   ~CommandObjectPlatformProcessInfo() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = GetDebugger().GetSelectedTarget().get();
     PlatformSP platform_sp;
     if (target) {
@@ -1538,7 +1538,7 @@ class CommandObjectPlatformProcessAttach : public CommandObjectParsed {
 
   ~CommandObjectPlatformProcessAttach() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
     if (platform_sp) {
@@ -1675,7 +1675,7 @@ class CommandObjectPlatformShell : public CommandObjectRaw {
 
   Options *GetOptions() override { return &m_options; }
 
-  void DoExecute(llvm::StringRef raw_command_line,
+  void DoExecute(llvm::StringRef raw_command_line, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     ExecutionContext exe_ctx = GetCommandInterpreter().GetExecutionContext();
     m_options.NotifyOptionParsingStarting(&exe_ctx);
@@ -1773,7 +1773,7 @@ class CommandObjectPlatformInstall : public CommandObjectParsed {
         GetCommandInterpreter(), lldb::eDiskFileCompletion, request, nullptr);
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (args.GetArgumentCount() != 2) {
       result.AppendError("platform target-install takes two arguments");
       return;
diff --git a/lldb/source/Commands/CommandObjectPlugin.cpp b/lldb/source/Commands/CommandObjectPlugin.cpp
index f3108b8a768d2a..a447101d210e58 100644
--- a/lldb/source/Commands/CommandObjectPlugin.cpp
+++ b/lldb/source/Commands/CommandObjectPlugin.cpp
@@ -25,7 +25,7 @@ class CommandObjectPluginLoad : public CommandObjectParsed {
   ~CommandObjectPluginLoad() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     size_t argc = command.GetArgumentCount();
 
     if (argc != 1) {
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 25eb633f1e6dad..3ca005c79f858f 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -140,7 +140,7 @@ class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
   }
 
 protected:
-  void DoExecute(Args &launch_args, CommandReturnObject &result) override {
+  void DoExecute(Args &launch_args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Debugger &debugger = GetDebugger();
     Target *target = debugger.GetSelectedTarget().get();
     // If our listener is nullptr, users aren't allows to launch
@@ -301,7 +301,7 @@ class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach {
   Options *GetOptions() override { return &m_all_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     PlatformSP platform_sp(
         GetDebugger().GetPlatformList().GetSelectedPlatform());
 
@@ -481,7 +481,7 @@ class CommandObjectProcessContinue : public CommandObjectParsed {
     bool m_any_bkpts_specified = false;
   };
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
     bool synchronous_execution = m_interpreter.GetSynchronous();
     StateType state = process->GetState();
@@ -782,7 +782,7 @@ class CommandObjectProcessDetach : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
     // FIXME: This will be a Command Option:
     bool keep_stopped;
@@ -864,7 +864,7 @@ class CommandObjectProcessConnect : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.GetArgumentCount() != 1) {
       result.AppendErrorWithFormat(
           "'%s' takes exactly one argument:\nUsage: %s\n", m_cmd_name.c_str(),
@@ -999,7 +999,7 @@ class CommandObjectProcessLoad : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
 
     for (auto &entry : command.entries()) {
@@ -1080,7 +1080,7 @@ class CommandObjectProcessUnload : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
 
     for (auto &entry : command.entries()) {
@@ -1136,7 +1136,7 @@ class CommandObjectProcessSignal : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
 
     if (command.GetArgumentCount() == 1) {
@@ -1184,7 +1184,7 @@ class CommandObjectProcessInterrupt : public CommandObjectParsed {
   ~CommandObjectProcessInterrupt() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
     if (process == nullptr) {
       result.AppendError("no process to halt");
@@ -1217,7 +1217,7 @@ class CommandObjectProcessKill : public CommandObjectParsed {
   ~CommandObjectProcessKill() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
     if (process == nullptr) {
       result.AppendError("no process to kill");
@@ -1295,7 +1295,7 @@ class CommandObjectProcessSaveCore : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
     if (process_sp) {
       if (command.GetArgumentCount() == 1) {
@@ -1388,7 +1388,7 @@ class CommandObjectProcessStatus : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &strm = result.GetOutputStream();
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
 
@@ -1583,7 +1583,7 @@ class CommandObjectProcessHandle : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &signal_args, CommandReturnObject &result) override {
+  void DoExecute(Args &signal_args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     // Any signals that are being set should be added to the Target's
@@ -1790,7 +1790,7 @@ class CommandObjectProcessTraceStop : public CommandObjectParsed {
 
   ~CommandObjectProcessTraceStop() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     ProcessSP process_sp = m_exe_ctx.GetProcessSP();
 
     TraceSP trace_sp = process_sp->GetTarget().GetTrace();
diff --git a/lldb/source/Commands/CommandObjectQuit.cpp b/lldb/source/Commands/CommandObjectQuit.cpp
index 8e7830b2afc638..f98a5a195659f6 100644
--- a/lldb/source/Commands/CommandObjectQuit.cpp
+++ b/lldb/source/Commands/CommandObjectQuit.cpp
@@ -61,7 +61,7 @@ bool CommandObjectQuit::ShouldAskForConfirmation(bool &is_a_detach) {
   return should_prompt;
 }
 
-void CommandObjectQuit::DoExecute(Args &command, CommandReturnObject &result) {
+void CommandObjectQuit::DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) {
   bool is_a_detach = true;
   if (ShouldAskForConfirmation(is_a_detach)) {
     StreamString message;
diff --git a/lldb/source/Commands/CommandObjectQuit.h b/lldb/source/Commands/CommandObjectQuit.h
index c27c0d1da3b9e9..99281303fa1632 100644
--- a/lldb/source/Commands/CommandObjectQuit.h
+++ b/lldb/source/Commands/CommandObjectQuit.h
@@ -22,7 +22,7 @@ class CommandObjectQuit : public CommandObjectParsed {
   ~CommandObjectQuit() override;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override;
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 
   bool ShouldAskForConfirmation(bool &is_a_detach);
 };
diff --git a/lldb/source/Commands/CommandObjectRegexCommand.cpp b/lldb/source/Commands/CommandObjectRegexCommand.cpp
index f638d707e17e78..1fa3f3acb2bc64 100644
--- a/lldb/source/Commands/CommandObjectRegexCommand.cpp
+++ b/lldb/source/Commands/CommandObjectRegexCommand.cpp
@@ -54,7 +54,7 @@ llvm::Expected<std::string> CommandObjectRegexCommand::SubstituteVariables(
   return output.str();
 }
 
-void CommandObjectRegexCommand::DoExecute(llvm::StringRef command,
+void CommandObjectRegexCommand::DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                                           CommandReturnObject &result) {
   EntryCollection::const_iterator pos, end = m_entries.end();
   for (pos = m_entries.begin(); pos != end; ++pos) {
diff --git a/lldb/source/Commands/CommandObjectRegexCommand.h b/lldb/source/Commands/CommandObjectRegexCommand.h
index c78b0b586c3758..6e992c34a95329 100644
--- a/lldb/source/Commands/CommandObjectRegexCommand.h
+++ b/lldb/source/Commands/CommandObjectRegexCommand.h
@@ -37,7 +37,7 @@ class CommandObjectRegexCommand : public CommandObjectRaw {
   void HandleCompletion(CompletionRequest &request) override;
 
 protected:
-  void DoExecute(llvm::StringRef command, CommandReturnObject &result) override;
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override;
 
   /// Substitute variables of the format %\d+ in the input string.
   static llvm::Expected<std::string> SubstituteVariables(
diff --git a/lldb/source/Commands/CommandObjectRegister.cpp b/lldb/source/Commands/CommandObjectRegister.cpp
index 4e047ccbc10b92..3417d19e0e3493 100644
--- a/lldb/source/Commands/CommandObjectRegister.cpp
+++ b/lldb/source/Commands/CommandObjectRegister.cpp
@@ -147,7 +147,7 @@ class CommandObjectRegisterRead : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &strm = result.GetOutputStream();
     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
 
@@ -333,7 +333,7 @@ class CommandObjectRegisterWrite : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     DataExtractor reg_data;
     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
 
@@ -424,7 +424,7 @@ different for the same register when connected to different debug servers.)");
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.GetArgumentCount() != 1) {
       result.AppendError("register info takes exactly 1 argument: <reg-name>");
       return;
diff --git a/lldb/source/Commands/CommandObjectScripting.cpp b/lldb/source/Commands/CommandObjectScripting.cpp
index 9a1a2b63c7af0c..079bef3da79074 100644
--- a/lldb/source/Commands/CommandObjectScripting.cpp
+++ b/lldb/source/Commands/CommandObjectScripting.cpp
@@ -78,7 +78,7 @@ class CommandObjectScriptingRun : public CommandObjectRaw {
   };
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     // Try parsing the language option but when the command contains a raw part
     // separated by the -- delimiter.
@@ -181,7 +181,7 @@ class CommandObjectScriptingExtensionList : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &s = result.GetOutputStream();
     s.Printf("Available scripted extension templates:");
 
diff --git a/lldb/source/Commands/CommandObjectSession.cpp b/lldb/source/Commands/CommandObjectSession.cpp
index c381ba4f74f120..9290502a12d3bf 100644
--- a/lldb/source/Commands/CommandObjectSession.cpp
+++ b/lldb/source/Commands/CommandObjectSession.cpp
@@ -27,7 +27,7 @@ class CommandObjectSessionSave : public CommandObjectParsed {
   ~CommandObjectSessionSave() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     llvm::StringRef file_path;
 
     if (!args.empty())
@@ -117,7 +117,7 @@ class CommandObjectSessionHistory : public CommandObjectParsed {
     OptionValueBoolean m_clear;
   };
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (m_options.m_clear.GetCurrentValue() &&
         m_options.m_clear.OptionWasSet()) {
       m_interpreter.GetCommandHistory().Clear();
diff --git a/lldb/source/Commands/CommandObjectSettings.cpp b/lldb/source/Commands/CommandObjectSettings.cpp
index 7bbb0dd567ab1a..e2cb5941e59f64 100644
--- a/lldb/source/Commands/CommandObjectSettings.cpp
+++ b/lldb/source/Commands/CommandObjectSettings.cpp
@@ -169,7 +169,7 @@ insert-before or insert-after.");
   }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     Args cmd_args(command);
 
@@ -251,7 +251,7 @@ class CommandObjectSettingsShow : public CommandObjectParsed {
   ~CommandObjectSettingsShow() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishResult);
 
     if (!args.empty()) {
@@ -332,7 +332,7 @@ class CommandObjectSettingsWrite : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     FileSpec file_spec(m_options.m_filename);
     FileSystem::Instance().Resolve(file_spec);
     std::string path(file_spec.GetPath());
@@ -423,7 +423,7 @@ class CommandObjectSettingsRead : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     FileSpec file(m_options.m_filename);
     FileSystem::Instance().Resolve(file);
     CommandInterpreterRunOptions options;
@@ -478,7 +478,7 @@ class CommandObjectSettingsList : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishResult);
 
     const size_t argc = args.GetArgumentCount();
@@ -560,7 +560,7 @@ class CommandObjectSettingsRemove : public CommandObjectRaw {
   }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
 
@@ -665,7 +665,7 @@ class CommandObjectSettingsReplace : public CommandObjectRaw {
   }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
 
@@ -754,7 +754,7 @@ class CommandObjectSettingsInsertBefore : public CommandObjectRaw {
   }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
 
@@ -847,7 +847,7 @@ class CommandObjectSettingsInsertAfter : public CommandObjectRaw {
   }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
 
@@ -929,7 +929,7 @@ class CommandObjectSettingsAppend : public CommandObjectRaw {
   }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
     Args cmd_args(command);
@@ -1021,7 +1021,7 @@ class CommandObjectSettingsClear : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
     const size_t argc = command.GetArgumentCount();
 
diff --git a/lldb/source/Commands/CommandObjectSource.cpp b/lldb/source/Commands/CommandObjectSource.cpp
index 5ddd46ac5fdc07..1709d53b6304da 100644
--- a/lldb/source/Commands/CommandObjectSource.cpp
+++ b/lldb/source/Commands/CommandObjectSource.cpp
@@ -532,7 +532,7 @@ class CommandObjectSourceInfo : public CommandObjectParsed {
     return true;
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     uint32_t addr_byte_size = target.GetArchitecture().GetAddressByteSize();
@@ -904,7 +904,7 @@ class CommandObjectSourceList : public CommandObjectParsed {
     }
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     if (!m_options.symbol_name.empty()) {
@@ -1205,7 +1205,7 @@ class CommandObjectSourceCacheDump : public CommandObjectParsed {
   ~CommandObjectSourceCacheDump() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // Dump the debugger source cache.
     result.GetOutputStream() << "Debugger Source File Cache\n";
     SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
@@ -1231,7 +1231,7 @@ class CommandObjectSourceCacheClear : public CommandObjectParsed {
   ~CommandObjectSourceCacheClear() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // Clear the debugger cache.
     SourceManager::SourceFileCache &cache = GetDebugger().GetSourceFileCache();
     cache.Clear();
diff --git a/lldb/source/Commands/CommandObjectStats.cpp b/lldb/source/Commands/CommandObjectStats.cpp
index 53855e7d03165c..1a31161e1702c2 100644
--- a/lldb/source/Commands/CommandObjectStats.cpp
+++ b/lldb/source/Commands/CommandObjectStats.cpp
@@ -27,7 +27,7 @@ class CommandObjectStatsEnable : public CommandObjectParsed {
   ~CommandObjectStatsEnable() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (DebuggerStats::GetCollectingStats()) {
       result.AppendError("statistics already enabled");
       return;
@@ -48,7 +48,7 @@ class CommandObjectStatsDisable : public CommandObjectParsed {
   ~CommandObjectStatsDisable() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (!DebuggerStats::GetCollectingStats()) {
       result.AppendError("need to enable statistics before disabling them");
       return;
@@ -135,7 +135,7 @@ class CommandObjectStatsDump : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = nullptr;
     if (!m_options.m_all_targets)
       target = m_exe_ctx.GetTargetPtr();
diff --git a/lldb/source/Commands/CommandObjectTarget.cpp b/lldb/source/Commands/CommandObjectTarget.cpp
index 10e761fa8de1ae..23a745085fc6b6 100644
--- a/lldb/source/Commands/CommandObjectTarget.cpp
+++ b/lldb/source/Commands/CommandObjectTarget.cpp
@@ -247,7 +247,7 @@ class CommandObjectTargetCreate : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
     FileSpec core_file(m_core_file.GetOptionValue().GetCurrentValue());
     FileSpec remote_file(m_remote_file.GetOptionValue().GetCurrentValue());
@@ -472,7 +472,7 @@ class CommandObjectTargetList : public CommandObjectParsed {
   ~CommandObjectTargetList() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &strm = result.GetOutputStream();
 
     bool show_stopped_process_status = false;
@@ -498,7 +498,7 @@ class CommandObjectTargetSelect : public CommandObjectParsed {
   ~CommandObjectTargetSelect() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (args.GetArgumentCount() == 1) {
       const char *target_identifier = args.GetArgumentAtIndex(0);
       uint32_t target_idx = LLDB_INVALID_INDEX32;
@@ -582,7 +582,7 @@ class CommandObjectTargetDelete : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = args.GetArgumentCount();
     std::vector<TargetSP> delete_target_list;
     TargetList &target_list = GetDebugger().GetTargetList();
@@ -670,7 +670,7 @@ class CommandObjectTargetShowLaunchEnvironment : public CommandObjectParsed {
   ~CommandObjectTargetShowLaunchEnvironment() override = default;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = m_exe_ctx.GetTargetPtr();
     Environment env = target->GetEnvironment();
 
@@ -829,7 +829,7 @@ class CommandObjectTargetVariable : public CommandObjectParsed {
     }
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = m_exe_ctx.GetTargetPtr();
     const size_t argc = args.GetArgumentCount();
     Stream &s = result.GetOutputStream();
@@ -1026,7 +1026,7 @@ class CommandObjectTargetModulesSearchPathsAdd : public CommandObjectParsed {
   ~CommandObjectTargetModulesSearchPathsAdd() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     const size_t argc = command.GetArgumentCount();
     if (argc & 1) {
@@ -1073,7 +1073,7 @@ class CommandObjectTargetModulesSearchPathsClear : public CommandObjectParsed {
   ~CommandObjectTargetModulesSearchPathsClear() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     bool notify = true;
     target.GetImageSearchPathList().Clear(notify);
@@ -1147,7 +1147,7 @@ class CommandObjectTargetModulesSearchPathsInsert : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     size_t argc = command.GetArgumentCount();
     // check for at least 3 arguments and an odd number of parameters
@@ -1202,7 +1202,7 @@ class CommandObjectTargetModulesSearchPathsList : public CommandObjectParsed {
   ~CommandObjectTargetModulesSearchPathsList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     target.GetImageSearchPathList().Dump(&result.GetOutputStream());
     result.SetStatus(eReturnStatusSuccessFinishResult);
@@ -1224,7 +1224,7 @@ class CommandObjectTargetModulesSearchPathsQuery : public CommandObjectParsed {
   ~CommandObjectTargetModulesSearchPathsQuery() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     if (command.GetArgumentCount() != 1) {
       result.AppendError("query requires one argument\n");
@@ -1896,7 +1896,7 @@ class CommandObjectTargetModulesDumpObjfile
   ~CommandObjectTargetModulesDumpObjfile() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     uint32_t addr_byte_size = target.GetArchitecture().GetAddressByteSize();
@@ -1997,7 +1997,7 @@ class CommandObjectTargetModulesDumpSymtab
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     uint32_t num_dumped = 0;
     Mangled::NamePreference name_preference =
@@ -2095,7 +2095,7 @@ class CommandObjectTargetModulesDumpSections
   ~CommandObjectTargetModulesDumpSections() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     uint32_t num_dumped = 0;
 
@@ -2179,7 +2179,7 @@ class CommandObjectTargetModulesDumpClangPCMInfo : public CommandObjectParsed {
   ~CommandObjectTargetModulesDumpClangPCMInfo() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.GetArgumentCount() != 1) {
       result.AppendErrorWithFormat("'%s' takes exactly one pcm path argument.",
                                    m_cmd_name.c_str());
@@ -2236,7 +2236,7 @@ class CommandObjectTargetModulesDumpClangAST
   ~CommandObjectTargetModulesDumpClangAST() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     const ModuleList &module_list = target.GetImages();
@@ -2307,7 +2307,7 @@ class CommandObjectTargetModulesDumpSymfile
   ~CommandObjectTargetModulesDumpSymfile() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     uint32_t num_dumped = 0;
 
@@ -2390,7 +2390,7 @@ class CommandObjectTargetModulesDumpLineTable
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = m_exe_ctx.GetTargetPtr();
     uint32_t total_num_dumped = 0;
 
@@ -2531,7 +2531,7 @@ class CommandObjectTargetModulesDumpSeparateDebugInfoFiles
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     uint32_t num_dumped = 0;
 
@@ -2724,7 +2724,7 @@ class CommandObjectTargetModulesAdd : public CommandObjectParsed {
   OptionGroupUUID m_uuid_option_group;
   OptionGroupFile m_symbol_file;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     bool flush = false;
 
@@ -2874,7 +2874,7 @@ class CommandObjectTargetModulesLoad
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     const bool load = m_load_option.GetOptionValue().GetCurrentValue();
     const bool set_pc = m_pc_option.GetOptionValue().GetCurrentValue();
@@ -3164,7 +3164,7 @@ class CommandObjectTargetModulesList : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     const bool use_global_module_list = m_options.m_use_global_module_list;
     // Define a local module list here to ensure it lives longer than any
@@ -3508,7 +3508,7 @@ class CommandObjectTargetModulesShowUnwind : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = m_exe_ctx.GetTargetPtr();
     Process *process = m_exe_ctx.GetProcessPtr();
     ABI *abi = nullptr;
@@ -4054,7 +4054,7 @@ class CommandObjectTargetModulesLookup : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     bool syntax_error = false;
     uint32_t i;
@@ -4558,7 +4558,7 @@ class CommandObjectTargetSymbolsAdd : public CommandObjectParsed {
     return true;
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target *target = m_exe_ctx.GetTargetPtr();
     result.SetStatus(eReturnStatusFailed);
     bool flush = false;
@@ -4941,7 +4941,7 @@ Filter Options:
     io_handler.SetIsDone(true);
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     m_stop_hook_sp.reset();
 
     Target &target = GetTarget();
@@ -5080,7 +5080,7 @@ class CommandObjectTargetStopHookDelete : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     // FIXME: see if we can use the breakpoint id style parser?
     size_t num_args = command.GetArgumentCount();
@@ -5134,7 +5134,7 @@ class CommandObjectTargetStopHookEnableDisable : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     // FIXME: see if we can use the breakpoint id style parser?
     size_t num_args = command.GetArgumentCount();
@@ -5178,7 +5178,7 @@ class CommandObjectTargetStopHookList : public CommandObjectParsed {
   ~CommandObjectTargetStopHookList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     size_t num_hooks = target.GetNumStopHooks();
@@ -5243,7 +5243,7 @@ class CommandObjectTargetDumpTypesystem : public CommandObjectParsed {
   ~CommandObjectTargetDumpTypesystem() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // Go over every scratch TypeSystem and dump to the command output.
     for (lldb::TypeSystemSP ts : GetTarget().GetScratchTypeSystems())
       if (ts)
@@ -5268,7 +5268,7 @@ class CommandObjectTargetDumpSectionLoadList : public CommandObjectParsed {
   ~CommandObjectTargetDumpSectionLoadList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     target.GetSectionLoadList().Dump(result.GetOutputStream(), &target);
     result.SetStatus(eReturnStatusSuccessFinishResult);
diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp
index edbec0e305db74..fe426be97696c5 100644
--- a/lldb/source/Commands/CommandObjectThread.cpp
+++ b/lldb/source/Commands/CommandObjectThread.cpp
@@ -412,7 +412,7 @@ class CommandObjectThreadStepWithTypeAndScope : public CommandObjectParsed {
   Options *GetOptions() override { return &m_all_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
     bool synchronous_execution = m_interpreter.GetSynchronous();
 
@@ -650,7 +650,7 @@ class CommandObjectThreadContinue : public CommandObjectParsed {
 
   ~CommandObjectThreadContinue() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     bool synchronous_execution = m_interpreter.GetSynchronous();
 
     Process *process = m_exe_ctx.GetProcessPtr();
@@ -884,7 +884,7 @@ class CommandObjectThreadUntil : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     bool synchronous_execution = m_interpreter.GetSynchronous();
 
     Target *target = &GetTarget();
@@ -1180,7 +1180,7 @@ class CommandObjectThreadSelect : public CommandObjectParsed {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
     if (process == nullptr) {
       result.AppendError("no process");
@@ -1249,7 +1249,7 @@ class CommandObjectThreadList : public CommandObjectParsed {
   ~CommandObjectThreadList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Stream &strm = result.GetOutputStream();
     result.SetStatus(eReturnStatusSuccessFinishNoResult);
     Process *process = m_exe_ctx.GetProcessPtr();
@@ -1533,7 +1533,7 @@ class CommandObjectThreadReturn : public CommandObjectRaw {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     // I am going to handle this by hand, because I don't want you to have to
     // say:
@@ -1690,7 +1690,7 @@ class CommandObjectThreadJump : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
     StackFrame *frame = m_exe_ctx.GetFramePtr();
     Thread *thread = m_exe_ctx.GetThreadPtr();
@@ -1827,7 +1827,7 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {
 
   Options *GetOptions() override { return &m_options; }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     // If we are reporting all threads, dispatch to the Process to do that:
     if (command.GetArgumentCount() == 0 && m_options.m_tids.empty()) {
       Stream &strm = result.GetOutputStream();
@@ -1858,7 +1858,7 @@ class CommandObjectThreadPlanList : public CommandObjectIterateOverThreads {
           result.GetOutputStream() << tmp_strm.GetString();
         }
       }
-      return CommandObjectIterateOverThreads::DoExecute(command, result);
+      return CommandObjectIterateOverThreads::DoExecute(command, {}, result);
     }
   }
 
@@ -1910,7 +1910,7 @@ class CommandObjectThreadPlanDiscard : public CommandObjectParsed {
     m_exe_ctx.GetThreadPtr()->AutoCompleteThreadPlans(request);
   }
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Thread *thread = m_exe_ctx.GetThreadPtr();
     if (args.GetArgumentCount() != 1) {
       result.AppendErrorWithFormat("Too many arguments, expected one - the "
@@ -1962,7 +1962,7 @@ class CommandObjectThreadPlanPrune : public CommandObjectParsed {
 
   ~CommandObjectThreadPlanPrune() override = default;
 
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Process *process = m_exe_ctx.GetProcessPtr();
 
     if (args.GetArgumentCount() == 0) {
@@ -2182,7 +2182,7 @@ class CommandObjectTraceDumpFunctionCalls : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
     if (!thread_sp) {
       result.AppendError("invalid thread\n");
@@ -2364,7 +2364,7 @@ class CommandObjectTraceDumpInstructions : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override {
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     ThreadSP thread_sp = GetSingleThreadFromArgs(m_exe_ctx, args, result);
     if (!thread_sp) {
       result.AppendError("invalid thread\n");
diff --git a/lldb/source/Commands/CommandObjectThreadUtil.cpp b/lldb/source/Commands/CommandObjectThreadUtil.cpp
index cdc5946547f47d..33bfd64e04d5e8 100644
--- a/lldb/source/Commands/CommandObjectThreadUtil.cpp
+++ b/lldb/source/Commands/CommandObjectThreadUtil.cpp
@@ -32,7 +32,7 @@ CommandObjectMultipleThreads::CommandObjectMultipleThreads(
   AddSimpleArgumentList(eArgTypeThreadIndex, eArgRepeatStar);
 }
 
-void CommandObjectIterateOverThreads::DoExecute(Args &command,
+void CommandObjectIterateOverThreads::DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
                                                 CommandReturnObject &result) {
   result.SetStatus(m_success_return);
 
@@ -164,7 +164,7 @@ bool CommandObjectIterateOverThreads::BucketThread(
   return true;
 }
 
-void CommandObjectMultipleThreads::DoExecute(Args &command,
+void CommandObjectMultipleThreads::DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
                                              CommandReturnObject &result) {
   Process &process = m_exe_ctx.GetProcessRef();
 
diff --git a/lldb/source/Commands/CommandObjectThreadUtil.h b/lldb/source/Commands/CommandObjectThreadUtil.h
index 3fc28efe8cf714..e58fd4b19f51fd 100644
--- a/lldb/source/Commands/CommandObjectThreadUtil.h
+++ b/lldb/source/Commands/CommandObjectThreadUtil.h
@@ -55,7 +55,7 @@ class CommandObjectIterateOverThreads : public CommandObjectParsed {
 
   ~CommandObjectIterateOverThreads() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override;
 
 protected:
   // Override this to do whatever you need to do for one thread.
@@ -85,7 +85,7 @@ class CommandObjectMultipleThreads : public CommandObjectParsed {
                                const char *name, const char *help,
                                const char *syntax, uint32_t flags);
 
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override;
 
 protected:
   /// Method that handles the command after the main arguments have been parsed.
diff --git a/lldb/source/Commands/CommandObjectTrace.cpp b/lldb/source/Commands/CommandObjectTrace.cpp
index 5bcbc236301cc1..e6d476d6859655 100644
--- a/lldb/source/Commands/CommandObjectTrace.cpp
+++ b/lldb/source/Commands/CommandObjectTrace.cpp
@@ -102,7 +102,7 @@ class CommandObjectTraceSave : public CommandObjectParsed {
   ~CommandObjectTraceSave() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.size() != 1) {
       result.AppendError("a single path to a directory where the trace bundle "
                          "will be created is required");
@@ -190,7 +190,7 @@ class CommandObjectTraceLoad : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.size() != 1) {
       result.AppendError("a single path to a JSON file containing a the "
                          "description of the trace bundle is required");
@@ -271,7 +271,7 @@ class CommandObjectTraceDump : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Status error;
     // TODO: fill in the dumping code here!
     if (error.Success()) {
@@ -338,7 +338,7 @@ class CommandObjectTraceSchema : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Status error;
     if (command.empty()) {
       result.AppendError(
diff --git a/lldb/source/Commands/CommandObjectType.cpp b/lldb/source/Commands/CommandObjectType.cpp
index f9786529bcdb1c..f958afec6402bc 100644
--- a/lldb/source/Commands/CommandObjectType.cpp
+++ b/lldb/source/Commands/CommandObjectType.cpp
@@ -276,7 +276,7 @@ class CommandObjectTypeSummaryAdd : public CommandObjectParsed,
                        Status *error = nullptr);
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 };
 
 static const char *g_synth_addreader_instructions =
@@ -389,7 +389,7 @@ class CommandObjectTypeSynthAdd : public CommandObjectParsed,
   bool Execute_PythonClass(Args &command, CommandReturnObject &result);
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     WarnOnPotentialUnquotedUnsignedType(command, result);
 
     if (m_options.handwrite_python)
@@ -640,7 +640,7 @@ pointers to floats.  Nor will it change the default display for Afloat and Bfloa
   ~CommandObjectTypeFormatAdd() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc < 1) {
@@ -810,7 +810,7 @@ class CommandObjectTypeFormatterDelete : public CommandObjectParsed {
 protected:
   virtual bool FormatterSpecificDeletion(ConstString typeCS) { return false; }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc != 1) {
@@ -921,7 +921,7 @@ class CommandObjectTypeFormatterClear : public CommandObjectParsed {
 protected:
   virtual void FormatterSpecificDeletion() {}
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (m_options.m_delete_all) {
       DataVisualization::Categories::ForEach(
           [this](const TypeCategoryImplSP &category_sp) -> bool {
@@ -1047,7 +1047,7 @@ class CommandObjectTypeFormatterList : public CommandObjectParsed {
     return regex == nullptr || s == regex->GetText() || regex->Execute(s);
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     std::unique_ptr<RegularExpression> category_regex;
@@ -1518,7 +1518,7 @@ Alternatively, the -o option can be used when providing a simple one-line Python
 (lldb) type summary add JustADemo -o "value = valobj.GetChildMemberWithName('value'); return 'My value is ' + value.GetValue();")");
 }
 
-void CommandObjectTypeSummaryAdd::DoExecute(Args &command,
+void CommandObjectTypeSummaryAdd::DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
                                             CommandReturnObject &result) {
   WarnOnPotentialUnquotedUnsignedType(command, result);
 
@@ -1718,7 +1718,7 @@ class CommandObjectTypeCategoryDefine : public CommandObjectParsed {
   ~CommandObjectTypeCategoryDefine() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc < 1) {
@@ -1803,7 +1803,7 @@ class CommandObjectTypeCategoryEnable : public CommandObjectParsed {
   ~CommandObjectTypeCategoryEnable() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
@@ -1854,7 +1854,7 @@ class CommandObjectTypeCategoryDelete : public CommandObjectParsed {
   ~CommandObjectTypeCategoryDelete() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc < 1) {
@@ -1945,7 +1945,7 @@ class CommandObjectTypeCategoryDisable : public CommandObjectParsed {
   ~CommandObjectTypeCategoryDisable() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc < 1 && m_options.m_language == lldb::eLanguageTypeUnknown) {
@@ -2001,7 +2001,7 @@ class CommandObjectTypeCategoryList : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     std::unique_ptr<RegularExpression> regex;
@@ -2439,7 +2439,7 @@ all children of my_foo as if no filter was defined:"
   ~CommandObjectTypeFilterAdd() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
 
     if (argc < 1) {
@@ -2598,7 +2598,7 @@ class CommandObjectTypeLookup : public CommandObjectRaw {
     return m_cmd_help_long;
   }
 
-  void DoExecute(llvm::StringRef raw_command_line,
+  void DoExecute(llvm::StringRef raw_command_line, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     if (raw_command_line.empty()) {
       result.AppendError(
@@ -2725,7 +2725,7 @@ class CommandObjectFormatterInfo : public CommandObjectRaw {
   ~CommandObjectFormatterInfo() override = default;
 
 protected:
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     TargetSP target_sp = GetDebugger().GetSelectedTarget();
     Thread *thread = GetDefaultThread();
diff --git a/lldb/source/Commands/CommandObjectVersion.cpp b/lldb/source/Commands/CommandObjectVersion.cpp
index f13ec18e240c04..82ee69e47cbe10 100644
--- a/lldb/source/Commands/CommandObjectVersion.cpp
+++ b/lldb/source/Commands/CommandObjectVersion.cpp
@@ -22,7 +22,7 @@ CommandObjectVersion::CommandObjectVersion(CommandInterpreter &interpreter)
 
 CommandObjectVersion::~CommandObjectVersion() = default;
 
-void CommandObjectVersion::DoExecute(Args &args, CommandReturnObject &result) {
+void CommandObjectVersion::DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) {
   result.AppendMessageWithFormat("%s\n", lldb_private::GetVersion());
   result.SetStatus(eReturnStatusSuccessFinishResult);
 }
diff --git a/lldb/source/Commands/CommandObjectVersion.h b/lldb/source/Commands/CommandObjectVersion.h
index 4ba081bf8706d7..50f7f8957929cf 100644
--- a/lldb/source/Commands/CommandObjectVersion.h
+++ b/lldb/source/Commands/CommandObjectVersion.h
@@ -22,7 +22,7 @@ class CommandObjectVersion : public CommandObjectParsed {
   ~CommandObjectVersion() override;
 
 protected:
-  void DoExecute(Args &args, CommandReturnObject &result) override;
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 };
 
 } // namespace lldb_private
diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp
index f8f1fac620022b..73eac5bc039f7a 100644
--- a/lldb/source/Commands/CommandObjectWatchpoint.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp
@@ -200,7 +200,7 @@ class CommandObjectWatchpointList : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     if (ProcessSP process_sp = target.GetProcessSP()) {
@@ -285,7 +285,7 @@ class CommandObjectWatchpointEnable : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     if (!CheckTargetForWatchpointOperations(target, result))
       return;
@@ -354,7 +354,7 @@ class CommandObjectWatchpointDisable : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     if (!CheckTargetForWatchpointOperations(target, result))
       return;
@@ -463,7 +463,7 @@ class CommandObjectWatchpointDelete : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     if (!CheckTargetForWatchpointOperations(target, result))
       return;
@@ -583,7 +583,7 @@ class CommandObjectWatchpointIgnore : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     if (!CheckTargetForWatchpointOperations(target, result))
       return;
@@ -702,7 +702,7 @@ class CommandObjectWatchpointModify : public CommandObjectParsed {
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     if (!CheckTargetForWatchpointOperations(target, result))
       return;
@@ -803,7 +803,7 @@ corresponding to the byte size of the data type.");
     return variable_list.GetSize() - old_size;
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
     StackFrame *frame = m_exe_ctx.GetFramePtr();
 
@@ -985,7 +985,7 @@ class CommandObjectWatchpointSetExpression : public CommandObjectRaw {
   Options *GetOptions() override { return &m_option_group; }
 
 protected:
-  void DoExecute(llvm::StringRef raw_command,
+  void DoExecute(llvm::StringRef raw_command, std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     auto exe_ctx = GetCommandInterpreter().GetExecutionContext();
     m_option_group.NotifyOptionParsingStarting(
diff --git a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
index ab1a2b390936c4..0e24c9c36a2d1e 100644
--- a/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
+++ b/lldb/source/Commands/CommandObjectWatchpointCommand.cpp
@@ -353,7 +353,7 @@ are no syntax errors may indicate that a function was declared but never called.
   };
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     const WatchpointList &watchpoints = target.GetWatchpointList();
@@ -448,7 +448,7 @@ class CommandObjectWatchpointCommandDelete : public CommandObjectParsed {
   ~CommandObjectWatchpointCommandDelete() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     const WatchpointList &watchpoints = target.GetWatchpointList();
@@ -503,7 +503,7 @@ class CommandObjectWatchpointCommandList : public CommandObjectParsed {
   ~CommandObjectWatchpointCommandList() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     Target &target = GetTarget();
 
     const WatchpointList &watchpoints = target.GetWatchpointList();
diff --git a/lldb/source/Interpreter/CommandAlias.cpp b/lldb/source/Interpreter/CommandAlias.cpp
index c5971b52f837fa..81a424945f68ca 100644
--- a/lldb/source/Interpreter/CommandAlias.cpp
+++ b/lldb/source/Interpreter/CommandAlias.cpp
@@ -136,6 +136,7 @@ Options *CommandAlias::GetOptions() {
 }
 
 void CommandAlias::Execute(const char *args_string,
+                                                  std::optional<uint16_t> offset_in_command,
                            CommandReturnObject &result) {
   llvm_unreachable("CommandAlias::Execute is not to be called");
 }
diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp
index df539d5f5bcee9..9eac8bc76621bb 100644
--- a/lldb/source/Interpreter/CommandInterpreter.cpp
+++ b/lldb/source/Interpreter/CommandInterpreter.cpp
@@ -1887,7 +1887,8 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
                                        CommandReturnObject &result,
                                        bool force_repeat_command) {
   std::string command_string(command_line);
-  std::string original_command_string(command_line);
+  std::string original_command_string(command_string);
+  std::string real_original_command_string(command_string);
 
   Log *log = GetLog(LLDBLog::Commands);
   llvm::PrettyStackTraceFormat stack_trace("HandleCommand(command = \"%s\")",
@@ -2076,7 +2077,11 @@ bool CommandInterpreter::HandleCommand(const char *command_line,
     }
 
     ElapsedTime elapsed(execute_time);
-    cmd_obj->Execute(remainder.c_str(), result);
+    size_t nchar = real_original_command_string.find(remainder);
+    std::optional<uint16_t> pos_in_cmd;
+    if (nchar != std::string::npos)
+      pos_in_cmd = nchar + GetDebugger().GetPrompt().size();
+    cmd_obj->Execute(remainder.c_str(), pos_in_cmd, result);
   }
 
   LLDB_LOGF(log, "HandleCommand, command %s",
diff --git a/lldb/source/Interpreter/CommandObject.cpp b/lldb/source/Interpreter/CommandObject.cpp
index c819024ccf0183..bb4675ae83793b 100644
--- a/lldb/source/Interpreter/CommandObject.cpp
+++ b/lldb/source/Interpreter/CommandObject.cpp
@@ -799,6 +799,7 @@ Thread *CommandObject::GetDefaultThread() {
 }
 
 void CommandObjectParsed::Execute(const char *args_string,
+                                  std::optional<uint16_t> offset_in_command,
                                   CommandReturnObject &result) {
   bool handled = false;
   Args cmd_args(args_string);
@@ -832,7 +833,7 @@ void CommandObjectParsed::Execute(const char *args_string,
           return;
         }
         m_interpreter.IncreaseCommandUsage(*this);
-        DoExecute(cmd_args, result);
+        DoExecute(cmd_args, {}, result);
       }
     }
 
@@ -841,6 +842,7 @@ void CommandObjectParsed::Execute(const char *args_string,
 }
 
 void CommandObjectRaw::Execute(const char *args_string,
+                               std::optional<uint16_t> offset_in_command,
                                CommandReturnObject &result) {
   bool handled = false;
   if (HasOverrideCallback()) {
@@ -853,7 +855,7 @@ void CommandObjectRaw::Execute(const char *args_string,
   }
   if (!handled) {
     if (CheckRequirements(result))
-      DoExecute(args_string, result);
+      DoExecute(args_string,offset_in_command, result);
 
     Cleanup();
   }
diff --git a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
index 7af768aad0bc19..1fd701f0b5afef 100644
--- a/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/CPlusPlus/ItaniumABI/ItaniumABILanguageRuntime.cpp
@@ -425,7 +425,7 @@ class CommandObjectMultiwordItaniumABI_Demangle : public CommandObjectParsed {
   ~CommandObjectMultiwordItaniumABI_Demangle() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     bool demangled_any = false;
     bool error_any = false;
     for (auto &entry : command.entries()) {
diff --git a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
index 0f153878423be7..9ad640c5314267 100644
--- a/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
+++ b/lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCRuntimeV2.cpp
@@ -905,7 +905,7 @@ class CommandObjectObjC_ClassTable_Dump : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     std::unique_ptr<RegularExpression> regex_up;
     switch (command.GetArgumentCount()) {
     case 0:
@@ -1009,7 +1009,7 @@ class CommandObjectMultiwordObjC_TaggedPointer_Info
   ~CommandObjectMultiwordObjC_TaggedPointer_Info() override = default;
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (command.GetArgumentCount() == 0) {
       result.AppendError("this command requires arguments");
       result.SetStatus(lldb::eReturnStatusFailed);
diff --git a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
index 9b2907c6809965..075a2f632de32d 100644
--- a/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
+++ b/lldb/source/Plugins/Process/MacOSX-Kernel/ProcessKDP.cpp
@@ -867,7 +867,7 @@ class CommandObjectProcessKDPPacketSend : public CommandObjectParsed {
 
   ~CommandObjectProcessKDPPacketSend() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     if (!m_command_byte.GetOptionValue().OptionWasSet()) {
       result.AppendError(
           "the --command option must be set to a valid command byte");
diff --git a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
index 65b1b3a0f26863..430e011b230ab8 100644
--- a/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
@@ -5506,7 +5506,7 @@ class CommandObjectProcessGDBRemoteSpeedTest : public CommandObjectParsed {
 
   Options *GetOptions() override { return &m_option_group; }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
     if (argc == 0) {
       ProcessGDBRemote *process =
@@ -5556,7 +5556,7 @@ class CommandObjectProcessGDBRemotePacketHistory : public CommandObjectParsed {
 
   ~CommandObjectProcessGDBRemotePacketHistory() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     ProcessGDBRemote *process =
         (ProcessGDBRemote *)m_interpreter.GetExecutionContext().GetProcessPtr();
     if (process) {
@@ -5581,7 +5581,7 @@ class CommandObjectProcessGDBRemotePacketXferSize : public CommandObjectParsed {
 
   ~CommandObjectProcessGDBRemotePacketXferSize() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
     if (argc == 0) {
       result.AppendErrorWithFormat("'%s' takes an argument to specify the max "
@@ -5623,7 +5623,7 @@ class CommandObjectProcessGDBRemotePacketSend : public CommandObjectParsed {
 
   ~CommandObjectProcessGDBRemotePacketSend() override = default;
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
     if (argc == 0) {
       result.AppendErrorWithFormat(
@@ -5671,7 +5671,7 @@ class CommandObjectProcessGDBRemotePacketMonitor : public CommandObjectRaw {
 
   ~CommandObjectProcessGDBRemotePacketMonitor() override = default;
 
-  void DoExecute(llvm::StringRef command,
+  void DoExecute(llvm::StringRef command,std::optional<uint16_t> offset_in_command,
                  CommandReturnObject &result) override {
     if (command.empty()) {
       result.AppendErrorWithFormat("'%s' takes a command string argument",
diff --git a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
index 7a326a557547df..aa9074ddf0d17d 100644
--- a/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
+++ b/lldb/source/Plugins/Process/minidump/ProcessMinidump.cpp
@@ -794,8 +794,8 @@ class CommandObjectProcessMinidumpDump : public CommandObjectParsed {
   ~CommandObjectProcessMinidumpDump() override = default;
 
   Options *GetOptions() override { return &m_option_group; }
-
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     const size_t argc = command.GetArgumentCount();
     if (argc > 0) {
       result.AppendErrorWithFormat("'%s' take no arguments, only options",
diff --git a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
index 1137f24451d28b..edafefaa23dfdf 100644
--- a/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
+++ b/lldb/source/Plugins/StructuredData/DarwinLog/StructuredDataDarwinLog.cpp
@@ -769,7 +769,7 @@ class EnableCommand : public CommandObjectParsed {
     result.AppendWarning(stream.GetString());
   }
 
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command,                std::optional<uint16_t> offset_in_command,CommandReturnObject &result) override {
     // First off, set the global sticky state of enable/disable based on this
     // command execution.
     s_is_explicitly_enabled = m_enable;
@@ -863,7 +863,7 @@ class StatusCommand : public CommandObjectParsed {
                             "plugin structured-data darwin-log status") {}
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command,               std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override {
     auto &stream = result.GetOutputStream();
 
     // Figure out if we've got a process.  If so, we can tell if DarwinLog is
diff --git a/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp b/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp
index 89e99b942d5815..4cd12d5281f352 100644
--- a/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp
+++ b/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.cpp
@@ -62,7 +62,7 @@ CommandObjectThreadTraceExportCTF::CommandOptions::GetDefinitions() {
   return llvm::ArrayRef(g_thread_trace_export_ctf_options);
 }
 
-void CommandObjectThreadTraceExportCTF::DoExecute(Args &command,
+void CommandObjectThreadTraceExportCTF::DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
                                                   CommandReturnObject &result) {
   const TraceSP &trace_sp = m_exe_ctx.GetTargetSP()->GetTrace();
   Process *process = m_exe_ctx.GetProcessPtr();
diff --git a/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h b/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h
index 1a034e87cfb65b..9f5ba9f05b447e 100644
--- a/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h
+++ b/lldb/source/Plugins/TraceExporter/ctf/CommandObjectThreadTraceExportCTF.h
@@ -48,7 +48,7 @@ class CommandObjectThreadTraceExportCTF : public CommandObjectParsed {
   Options *GetOptions() override { return &m_options; }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override;
+  void DoExecute(Args &args, std::optional<uint16_t> offset_in_command, CommandReturnObject &result) override;
 
   CommandOptions m_options;
 };
diff --git a/lldb/source/Utility/Status.cpp b/lldb/source/Utility/Status.cpp
index 3b552e5540df61..8bd106a4d5b4c8 100644
--- a/lldb/source/Utility/Status.cpp
+++ b/lldb/source/Utility/Status.cpp
@@ -196,11 +196,9 @@ void Status::Clear() {
   m_string.clear();
 }
 
-// Access the error value.
 Status::ValueType Status::GetError() const { return m_code; }
-
-// Access the error type.
 ErrorType Status::GetType() const { return m_type; }
+llvm::ArrayRef<Status::Detail> Status::GetDetails() const { return m_details; }
 
 // Returns true if this object contains a value that describes an error or
 // otherwise non-success result.
diff --git a/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py b/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py
index 6a7995ff2a837e..d0d9358589a719 100644
--- a/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py
+++ b/lldb/test/API/commands/expression/persistent_variables/TestPersistentVariables.py
@@ -56,7 +56,7 @@ def test_persistent_variables(self):
         self.expect(
             "expr int $i = 123",
             error=True,
-            substrs=["error: redefinition of persistent variable '$i'"],
+            substrs=["redefinition of persistent variable '$i'"],
         )
         self.expect_expr("$i", result_type="int", result_value="5")
 
@@ -65,7 +65,7 @@ def test_persistent_variables(self):
         self.expect(
             "expr long $i = 123",
             error=True,
-            substrs=["error: redefinition of persistent variable '$i'"],
+            substrs=["redefinition of persistent variable '$i'"],
         )
         self.expect_expr("$i", result_type="int", result_value="5")
 
diff --git a/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py b/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py
index ea3aa6a4608c41..c734033bd6c028 100644
--- a/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py
+++ b/lldb/test/API/commands/expression/static-initializers/TestStaticInitializers.py
@@ -35,7 +35,7 @@ def test_failing_init(self):
         self.expect(
             "expr -p -- struct Foo2 { Foo2() { do_abort(); } }; Foo2 f;",
             error=True,
-            substrs=["error: couldn't run static initializer:"],
+            substrs=["couldn't run static initializer:"],
         )
 
     def test_without_process(self):
diff --git a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
index 71df90e6a6d161..8d4200b1076d03 100644
--- a/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
+++ b/lldb/test/API/lang/cpp/template-function/TestTemplateFunctions.py
@@ -21,7 +21,7 @@ def do_test_template_function(self, add_cast):
                 "expr b1 <=> b2",
                 error=True,
                 substrs=[
-                    "warning: <user expression 0>:1:4: '<=>' is a single token in C++20; add a space to avoid a change in behavior"
+                    "warning:", "'<=>' is a single token in C++20; add a space to avoid a change in behavior"
                 ],
             )
 
diff --git a/lldb/test/API/lang/mixed/TestMixedLanguages.py b/lldb/test/API/lang/mixed/TestMixedLanguages.py
index 8b73254cce4a93..1637d59a5edcba 100644
--- a/lldb/test/API/lang/mixed/TestMixedLanguages.py
+++ b/lldb/test/API/lang/mixed/TestMixedLanguages.py
@@ -40,7 +40,7 @@ def cleanup():
         self.runCmd("run")
         self.expect("thread backtrace", substrs=["`main", "lang=c"])
         # Make sure evaluation of C++11 fails.
-        self.expect("expr foo != nullptr", error=True, startstr="error")
+        self.expect("expr foo != nullptr", error=True, substrs=["error"])
 
         # Run to BP at foo (in foo.cpp) and test that the language is C++.
         self.runCmd("breakpoint set -n foo")
diff --git a/lldb/test/Shell/Expr/TestObjCIDCast.test b/lldb/test/Shell/Expr/TestObjCIDCast.test
index 0611171da09e2e..19ca404643c1d9 100644
--- a/lldb/test/Shell/Expr/TestObjCIDCast.test
+++ b/lldb/test/Shell/Expr/TestObjCIDCast.test
@@ -6,4 +6,4 @@
 // RUN:   2>&1 | FileCheck %s
 
 // CHECK: (lldb) expression --language objc -- *(id)0x1
-// CHECK: error: Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
+// CHECK: error:{{.*}}Couldn't apply expression side effects : Couldn't dematerialize a result variable: couldn't read its memory
diff --git a/lldb/test/Shell/Expr/TestObjCInCXXContext.test b/lldb/test/Shell/Expr/TestObjCInCXXContext.test
index 8537799bdeb674..f8cad5b58a1e53 100644
--- a/lldb/test/Shell/Expr/TestObjCInCXXContext.test
+++ b/lldb/test/Shell/Expr/TestObjCInCXXContext.test
@@ -18,4 +18,4 @@
 // CHECK-NEXT: (NSString *){{.*}}= nil
 
 // CHECK:      (lldb) expression NSString
-// CHECK-NEXT: error:{{.*}} use of undeclared identifier 'NSString'
+// CHECK:      error:{{.*}}use of undeclared identifier 'NSString'
diff --git a/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp b/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
index a249057282d890..8c168286903014 100644
--- a/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
+++ b/lldb/test/Shell/SymbolFile/NativePDB/incomplete-tag-type.cpp
@@ -13,9 +13,7 @@
 // CHECK: (lldb) expression d
 // CHECK: (D) $1 = {}
 // CHECK: (lldb) expression static_e_ref
-// CHECK: error: {{.*}}incomplete type 'E' where a complete type is required
-// CHECK: static_e_ref
-// CHECK: ^
+// CHECK: error:{{.*}}incomplete type 'E' where a complete type is required
 
 // Complete base class.
 struct A { int x; A(); };
diff --git a/lldb/unittests/Interpreter/CMakeLists.txt b/lldb/unittests/Interpreter/CMakeLists.txt
index 54cea995084d3d..14a7d6c5610388 100644
--- a/lldb/unittests/Interpreter/CMakeLists.txt
+++ b/lldb/unittests/Interpreter/CMakeLists.txt
@@ -1,5 +1,6 @@
 add_lldb_unittest(InterpreterTests
   TestCommandPaths.cpp
+  TestCommandObjectExpression.cpp
   TestCompletion.cpp
   TestOptionArgParser.cpp
   TestOptions.cpp
diff --git a/lldb/unittests/Interpreter/TestCommandObjectExpression.cpp b/lldb/unittests/Interpreter/TestCommandObjectExpression.cpp
new file mode 100644
index 00000000000000..cd84c192442ac8
--- /dev/null
+++ b/lldb/unittests/Interpreter/TestCommandObjectExpression.cpp
@@ -0,0 +1,27 @@
+#include "Commands/CommandObjectExpression.h"
+
+#include "gtest/gtest.h"
+
+using namespace lldb_private;
+using namespace lldb;
+using llvm::StringRef;
+namespace {
+class ErrorDisplayTest : public ::testing::Test {};
+} // namespace
+
+static std::string Render(llvm::SmallVector<Status::Detail> details) {
+  Status error = Status::FromExpressionErrorDetails(eExpressionCompleted,
+                                                    std::move(details));
+  return CommandObjectExpression::RenderError(0, error);
+}
+
+TEST_F(ErrorDisplayTest, RenderStatus) {
+  Status::Detail::SourceLocation inline_loc;
+  inline_loc.in_user_input = true;
+  {
+    std::string result =
+      Render({Status::Detail{inline_loc, eSeverityError, "foo", ""}});
+    ASSERT_TRUE(StringRef(result).contains("error:"));
+    ASSERT_TRUE(StringRef(result).contains("foo"));
+  }
+}
diff --git a/lldb/unittests/Interpreter/TestCommandPaths.cpp b/lldb/unittests/Interpreter/TestCommandPaths.cpp
index 0f0a2791ebb808..9c11db82358428 100644
--- a/lldb/unittests/Interpreter/TestCommandPaths.cpp
+++ b/lldb/unittests/Interpreter/TestCommandPaths.cpp
@@ -48,7 +48,8 @@ class CommandObjectLeaf : public CommandObjectParsed {
   }
 
 protected:
-  void DoExecute(Args &command, CommandReturnObject &result) override {
+  void DoExecute(Args &command, std::optional<uint16_t> offset_in_command,
+                 CommandReturnObject &result) override {
     result.SetStatus(eReturnStatusSuccessFinishResult);
     result.AppendMessage("I did nothing");
   }



More information about the lldb-commits mailing list