aleksandr.urakov created this revision.
aleksandr.urakov added reviewers: teemperor, clayborg, jingham, zturner, 
labath, davide, spyffe.
aleksandr.urakov added a project: LLDB.
Herald added subscribers: lldb-commits, abidh.

This patch adds support of expression evaluation in a context of some object. 
Consider the following example:

  struct S {
    int a = 11;
    int b = 12;
  };
  
  int main() {
    S s;
    int a = 1;
    int b = 2;
    // We have stopped here
    return 0;
  }

This patch allows to do something like that:

  lldb.frame.FindVariable("s").EvaluateExpression("a + b")

and the result will be `33` (not `3`) because fields `a` and `b` of `s` will be 
used (not locals `a` and `b`).

This is achieved by replacing of `this` type and object for the expression. 
This has some limitations: an expression can be evaluated only for values 
located in the debuggee process memory (they must have an address of 
`eAddressTypeLoad` type).

Our company needs this functionality to implement some UI visualization of 
variables in our IDEs. I understand that the community may be not interested in 
this functionality, and I'll just abandon it if so. But if the community is 
interested in this, we can save some time on merging in the future :)


Repository:
  rLLDB LLDB

https://reviews.llvm.org/D55318

Files:
  include/lldb/API/SBValue.h
  include/lldb/Expression/ExpressionSourceCode.h
  include/lldb/Expression/UserExpression.h
  include/lldb/Symbol/ClangASTContext.h
  include/lldb/Symbol/TypeSystem.h
  include/lldb/Target/Target.h
  packages/Python/lldbsuite/test/expression_command/context-object/Makefile
  
packages/Python/lldbsuite/test/expression_command/context-object/TestContextObject.py
  packages/Python/lldbsuite/test/expression_command/context-object/main.cpp
  scripts/interface/SBValue.i
  source/API/SBValue.cpp
  source/Breakpoint/BreakpointLocation.cpp
  source/Breakpoint/Watchpoint.cpp
  source/Commands/CommandObjectExpression.cpp
  source/Expression/ExpressionSourceCode.cpp
  source/Expression/UserExpression.cpp
  source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
  source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
  source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
  source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
  source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
  source/Symbol/ClangASTContext.cpp
  source/Target/Target.cpp

Index: source/Target/Target.cpp
===================================================================
--- source/Target/Target.cpp
+++ source/Target/Target.cpp
@@ -2198,7 +2198,8 @@
 UserExpression *Target::GetUserExpressionForLanguage(
     llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
     Expression::ResultType desired_type,
-    const EvaluateExpressionOptions &options, Status &error) {
+    const EvaluateExpressionOptions &options,
+    const lldb::ValueObjectSP &ctx_obj, Status &error) {
   Status type_system_error;
 
   TypeSystem *type_system =
@@ -2214,7 +2215,7 @@
   }
 
   user_expr = type_system->GetUserExpression(expr, prefix, language,
-                                             desired_type, options);
+                                             desired_type, options, ctx_obj);
   if (!user_expr)
     error.SetErrorStringWithFormat(
         "Could not create an expression for language %s",
@@ -2355,7 +2356,8 @@
 ExpressionResults Target::EvaluateExpression(
     llvm::StringRef expr, ExecutionContextScope *exe_scope,
     lldb::ValueObjectSP &result_valobj_sp,
-    const EvaluateExpressionOptions &options, std::string *fixed_expression) {
+    const EvaluateExpressionOptions &options, std::string *fixed_expression,
+    const lldb::ValueObjectSP &ctx_obj) {
   result_valobj_sp.reset();
 
   ExpressionResults execution_results = eExpressionSetupError;
@@ -2396,7 +2398,9 @@
     execution_results = UserExpression::Evaluate(exe_ctx, options, expr, prefix,
                                                  result_valobj_sp, error,
                                                  0, // Line Number
-                                                 fixed_expression);
+                                                 fixed_expression,
+                                                 nullptr, // Module
+                                                 ctx_obj);
   }
 
   m_suppress_stop_hooks = old_suppress_value;
Index: source/Symbol/ClangASTContext.cpp
===================================================================
--- source/Symbol/ClangASTContext.cpp
+++ source/Symbol/ClangASTContext.cpp
@@ -10294,13 +10294,14 @@
 UserExpression *ClangASTContextForExpressions::GetUserExpression(
     llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
     Expression::ResultType desired_type,
-    const EvaluateExpressionOptions &options) {
+    const EvaluateExpressionOptions &options,
+    const lldb::ValueObjectSP &ctx_obj) {
   TargetSP target_sp = m_target_wp.lock();
   if (!target_sp)
     return nullptr;
 
   return new ClangUserExpression(*target_sp.get(), expr, prefix, language,
-                                 desired_type, options);
+                                 desired_type, options, ctx_obj);
 }
 
 FunctionCaller *ClangASTContextForExpressions::GetFunctionCaller(
Index: source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangUtilityFunction.cpp
@@ -157,5 +157,6 @@
 void ClangUtilityFunction::ClangUtilityFunctionHelper::ResetDeclMap(
     ExecutionContext &exe_ctx, bool keep_result_in_memory) {
   m_expr_decl_map_up.reset(
-      new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx));
+      new ClangExpressionDeclMap(keep_result_in_memory, nullptr, exe_ctx,
+                                 nullptr));
 }
Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
+++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.h
@@ -62,7 +62,8 @@
 
     void ResetDeclMap(ExecutionContext &exe_ctx,
                       Materializer::PersistentVariableDelegate &result_delegate,
-                      bool keep_result_in_memory);
+                      bool keep_result_in_memory,
+                      const lldb::ValueObjectSP &ctx_obj);
 
     //------------------------------------------------------------------
     /// Return the object that the parser should allow to access ASTs. May be
@@ -106,11 +107,16 @@
   /// @param[in] desired_type
   ///     If not eResultTypeAny, the type to use for the expression
   ///     result.
+  ///
+  /// @param[in] ctx_obj
+  ///     The object (if any) in which context the expression
+  ///     must be evaluated
   //------------------------------------------------------------------
   ClangUserExpression(ExecutionContextScope &exe_scope, llvm::StringRef expr,
                       llvm::StringRef prefix, lldb::LanguageType language,
                       ResultType desired_type,
-                      const EvaluateExpressionOptions &options);
+                      const EvaluateExpressionOptions &options,
+                      const lldb::ValueObjectSP &ctx_obj);
 
   ~ClangUserExpression() override;
 
@@ -154,7 +160,8 @@
                     Materializer::PersistentVariableDelegate &result_delegate,
                     bool keep_result_in_memory) {
     m_type_system_helper.ResetDeclMap(exe_ctx, result_delegate,
-                                      keep_result_in_memory);
+                                      keep_result_in_memory,
+                                      m_ctx_obj);
   }
 
   lldb::ExpressionVariableSP
@@ -205,6 +212,9 @@
   /// were not able to calculate this position.
   llvm::Optional<size_t> m_user_expression_start_pos;
   ResultDelegate m_result_delegate;
+
+  /// The object (if any) in which context the expression is evaluated
+  lldb::ValueObjectSP m_ctx_obj;
 };
 
 } // namespace lldb_private
Index: source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangUserExpression.cpp
@@ -60,13 +60,15 @@
 ClangUserExpression::ClangUserExpression(
     ExecutionContextScope &exe_scope, llvm::StringRef expr,
     llvm::StringRef prefix, lldb::LanguageType language,
-    ResultType desired_type, const EvaluateExpressionOptions &options)
+    ResultType desired_type, const EvaluateExpressionOptions &options,
+    const lldb::ValueObjectSP &ctx_obj)
     : LLVMUserExpression(exe_scope, expr, prefix, language, desired_type,
                          options),
       m_type_system_helper(*m_target_wp.lock().get(),
                            options.GetExecutionPolicy() ==
                                eExecutionPolicyTopLevel),
-      m_result_delegate(exe_scope.CalculateTarget()) {
+      m_result_delegate(exe_scope.CalculateTarget()),
+      m_ctx_obj(ctx_obj) {
   switch (m_language) {
   case lldb::eLanguageTypeC_plus_plus:
     m_allow_cxx = true;
@@ -131,7 +133,37 @@
     return;
   }
 
-  if (clang::CXXMethodDecl *method_decl =
+  if (m_ctx_obj) {
+    const char *ctxObjErrorString = "Expression context object specified, "
+                                    "but it isn't located in debugee memory";
+
+    AddressType address_type;
+    lldb::addr_t address = m_ctx_obj->GetAddressOf(false, &address_type);
+    if (address == LLDB_INVALID_ADDRESS || address_type != eAddressTypeLoad) {
+      err.SetErrorString(ctxObjErrorString);
+      return;
+    }
+
+    switch (m_ctx_obj->GetObjectRuntimeLanguage()) {
+    case lldb::eLanguageTypeC:
+    case lldb::eLanguageTypeC89:
+    case lldb::eLanguageTypeC99:
+    case lldb::eLanguageTypeC11:
+    case lldb::eLanguageTypeC_plus_plus:
+    case lldb::eLanguageTypeC_plus_plus_03:
+    case lldb::eLanguageTypeC_plus_plus_11:
+    case lldb::eLanguageTypeC_plus_plus_14:
+      m_in_cplusplus_method = true;
+      break;
+    case lldb::eLanguageTypeObjC:
+    case lldb::eLanguageTypeObjC_plus_plus:
+      m_in_objectivec_method = true;
+      break;
+    default:
+      break;
+    }
+    m_needs_object_ptr = true;
+  } else if (clang::CXXMethodDecl *method_decl =
           ClangASTContext::DeclContextGetAsCXXMethodDecl(decl_context)) {
     if (m_allow_cxx && method_decl->isInstance()) {
       if (m_enforce_valid_object) {
@@ -397,7 +429,8 @@
       m_expr_lang = lldb::eLanguageTypeC;
 
     if (!source_code->GetText(m_transformed_text, m_expr_lang,
-                              m_in_static_method, exe_ctx)) {
+                              m_in_static_method, exe_ctx,
+                              m_ctx_obj.empty())) {
       diagnostic_manager.PutString(eDiagnosticSeverityError,
                                    "couldn't construct expression body");
       return;
@@ -734,7 +767,15 @@
 
     Status object_ptr_error;
 
-    object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
+    if (m_ctx_obj) {
+      AddressType address_type;
+      object_ptr = m_ctx_obj->GetAddressOf(false, &address_type);
+      if (object_ptr == LLDB_INVALID_ADDRESS ||
+          address_type != eAddressTypeLoad)
+        object_ptr_error.SetErrorString("Can't get context object's "
+                                        "debuggee address");
+    } else
+      object_ptr = GetObjectPointer(frame_sp, object_name, object_ptr_error);
 
     if (!object_ptr_error.Success()) {
       exe_ctx.GetTargetRef().GetDebugger().GetAsyncOutputStream()->Printf(
@@ -777,9 +818,11 @@
 void ClangUserExpression::ClangUserExpressionHelper::ResetDeclMap(
     ExecutionContext &exe_ctx,
     Materializer::PersistentVariableDelegate &delegate,
-    bool keep_result_in_memory) {
+    bool keep_result_in_memory,
+    const lldb::ValueObjectSP &ctx_obj) {
   m_expr_decl_map_up.reset(
-      new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx));
+      new ClangExpressionDeclMap(keep_result_in_memory, &delegate, exe_ctx,
+                                 ctx_obj));
 }
 
 clang::ASTConsumer *
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.h
@@ -73,11 +73,15 @@
   ///
   /// @param[in] exe_ctx
   ///     The execution context to use when parsing.
+  ///
+  /// @param[in] ctx_obj
+  ///     If not empty, then expression is evaluated in context of this object
   //------------------------------------------------------------------
   ClangExpressionDeclMap(
       bool keep_result_in_memory,
       Materializer::PersistentVariableDelegate *result_delegate,
-      ExecutionContext &exe_ctx);
+      ExecutionContext &exe_ctx,
+      const lldb::ValueObjectSP &ctx_obj);
 
   //------------------------------------------------------------------
   /// Destructor
@@ -344,6 +348,8 @@
   Materializer::PersistentVariableDelegate
       *m_result_delegate; ///< If non-NULL, used to report expression results to
                           ///ClangUserExpression.
+  lldb::ValueObjectSP m_ctx_obj; ///< If not empty, then expression is
+                                 ///evaluated in context of this object
 
   //----------------------------------------------------------------------
   /// The following values should not live beyond parsing
@@ -582,7 +588,7 @@
   /// @param[in] type
   ///     The type that needs to be created.
   //------------------------------------------------------------------
-  void AddOneType(NameSearchContext &context, TypeFromUser &type,
+  void AddOneType(NameSearchContext &context, const TypeFromUser &type,
                   unsigned int current_id);
 
   //------------------------------------------------------------------
@@ -595,7 +601,7 @@
   /// @param[in] type
   ///     The type for *this.
   //------------------------------------------------------------------
-  void AddThisType(NameSearchContext &context, TypeFromUser &type,
+  void AddThisType(NameSearchContext &context, const TypeFromUser &type,
                    unsigned int current_id);
 
   //------------------------------------------------------------------
Index: source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -66,10 +66,12 @@
 ClangExpressionDeclMap::ClangExpressionDeclMap(
     bool keep_result_in_memory,
     Materializer::PersistentVariableDelegate *result_delegate,
-    ExecutionContext &exe_ctx)
+    ExecutionContext &exe_ctx,
+    const lldb::ValueObjectSP &ctx_obj)
     : ClangASTSource(exe_ctx.GetTargetSP()), m_found_entities(),
       m_struct_members(), m_keep_result_in_memory(keep_result_in_memory),
-      m_result_delegate(result_delegate), m_parser_vars(), m_struct_vars() {
+      m_result_delegate(result_delegate), m_parser_vars(), m_struct_vars(),
+      m_ctx_obj(ctx_obj) {
   EnableStructVars();
 }
 
@@ -928,6 +930,21 @@
     static ConstString g_lldb_class_name("$__lldb_class");
 
     if (name == g_lldb_class_name) {
+      if (m_ctx_obj) {
+        Status status;
+        lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status);
+        if (!ctx_obj_ptr || status.Fail())
+          return;
+
+        AddThisType(context, TypeFromUser(m_ctx_obj->GetCompilerType()),
+                    current_id);
+
+        m_struct_vars->m_object_pointer_type =
+            TypeFromUser(ctx_obj_ptr->GetCompilerType());
+
+        return;
+      }
+
       // Clang is looking for the type of "this"
 
       if (frame == NULL)
@@ -1020,6 +1037,21 @@
 
     static ConstString g_lldb_objc_class_name("$__lldb_objc_class");
     if (name == g_lldb_objc_class_name) {
+      if (m_ctx_obj) {
+        Status status;
+        lldb::ValueObjectSP ctx_obj_ptr = m_ctx_obj->AddressOf(status);
+        if (!ctx_obj_ptr || status.Fail())
+          return;
+
+        AddOneType(context, TypeFromUser(m_ctx_obj->GetCompilerType()),
+                    current_id);
+
+        m_struct_vars->m_object_pointer_type =
+            TypeFromUser(ctx_obj_ptr->GetCompilerType());
+
+        return;
+      }
+
       // Clang is looking for the type of "*self"
 
       if (!frame)
@@ -2125,7 +2157,7 @@
 }
 
 void ClangExpressionDeclMap::AddThisType(NameSearchContext &context,
-                                         TypeFromUser &ut,
+                                         const TypeFromUser &ut,
                                          unsigned int current_id) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
@@ -2199,7 +2231,7 @@
 }
 
 void ClangExpressionDeclMap::AddOneType(NameSearchContext &context,
-                                        TypeFromUser &ut,
+                                        const TypeFromUser &ut,
                                         unsigned int current_id) {
   CompilerType copied_clang_type = GuardedCopyType(ut);
 
Index: source/Expression/UserExpression.cpp
===================================================================
--- source/Expression/UserExpression.cpp
+++ source/Expression/UserExpression.cpp
@@ -141,7 +141,8 @@
     ExecutionContext &exe_ctx, const EvaluateExpressionOptions &options,
     llvm::StringRef expr, llvm::StringRef prefix,
     lldb::ValueObjectSP &result_valobj_sp, Status &error, uint32_t line_offset,
-    std::string *fixed_expression, lldb::ModuleSP *jit_module_sp_ptr) {
+    std::string *fixed_expression, lldb::ModuleSP *jit_module_sp_ptr,
+    const lldb::ValueObjectSP &ctx_obj) {
   Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EXPRESSIONS |
                                                   LIBLLDB_LOG_STEP));
 
@@ -209,7 +210,8 @@
 
   lldb::UserExpressionSP user_expression_sp(
       target->GetUserExpressionForLanguage(expr, full_prefix, language,
-                                           desired_type, options, error));
+                                           desired_type, options, ctx_obj,
+                                           error));
   if (error.Fail()) {
     if (log)
       log->Printf("== [UserExpression::Evaluate] Getting expression: %s ==",
@@ -254,7 +256,8 @@
       lldb::UserExpressionSP fixed_expression_sp(
           target->GetUserExpressionForLanguage(fixed_expression->c_str(),
                                                full_prefix, language,
-                                               desired_type, options, error));
+                                               desired_type, options, ctx_obj,
+                                               error));
       DiagnosticManager fixed_diagnostic_manager;
       parse_success = fixed_expression_sp->Parse(
           fixed_diagnostic_manager, exe_ctx, execution_policy,
Index: source/Expression/ExpressionSourceCode.cpp
===================================================================
--- source/Expression/ExpressionSourceCode.cpp
+++ source/Expression/ExpressionSourceCode.cpp
@@ -182,7 +182,8 @@
 bool ExpressionSourceCode::GetText(std::string &text,
                                    lldb::LanguageType wrapping_language,
                                    bool static_method,
-                                   ExecutionContext &exe_ctx) const {
+                                   ExecutionContext &exe_ctx,
+                                   bool add_locals) const {
   const char *target_specific_defines = "typedef signed char BOOL;\n";
   std::string module_macros;
 
@@ -255,12 +256,13 @@
       }
     }
 
-    ConstString object_name;
-    if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) {
-      if (target->GetInjectLocalVariables(&exe_ctx)) {
-        lldb::VariableListSP var_list_sp =
-            frame->GetInScopeVariableList(false, true);
-        AddLocalVariableDecls(var_list_sp, lldb_local_var_decls);
+    if (add_locals) {
+      if (Language::LanguageIsCPlusPlus(frame->GetLanguage())) {
+        if (target->GetInjectLocalVariables(&exe_ctx)) {
+          lldb::VariableListSP var_list_sp =
+              frame->GetInScopeVariableList(false, true);
+          AddLocalVariableDecls(var_list_sp, lldb_local_var_decls);
+        }
       }
     }
   }
Index: source/Commands/CommandObjectExpression.cpp
===================================================================
--- source/Commands/CommandObjectExpression.cpp
+++ source/Commands/CommandObjectExpression.cpp
@@ -364,7 +364,7 @@
   Status error;
   lldb::UserExpressionSP expr(target->GetUserExpressionForLanguage(
       code, llvm::StringRef(), language, UserExpression::eResultTypeAny,
-      options, error));
+      options, nullptr, error));
   if (error.Fail())
     return 0;
 
Index: source/Breakpoint/Watchpoint.cpp
===================================================================
--- source/Breakpoint/Watchpoint.cpp
+++ source/Breakpoint/Watchpoint.cpp
@@ -283,7 +283,8 @@
     Status error;
     m_condition_ap.reset(m_target.GetUserExpressionForLanguage(
         condition, llvm::StringRef(), lldb::eLanguageTypeUnknown,
-        UserExpression::eResultTypeAny, EvaluateExpressionOptions(), error));
+        UserExpression::eResultTypeAny, EvaluateExpressionOptions(),
+        nullptr, error));
     if (error.Fail()) {
       // FIXME: Log something...
       m_condition_ap.reset();
Index: source/Breakpoint/BreakpointLocation.cpp
===================================================================
--- source/Breakpoint/BreakpointLocation.cpp
+++ source/Breakpoint/BreakpointLocation.cpp
@@ -256,7 +256,7 @@
 
     m_user_expression_sp.reset(GetTarget().GetUserExpressionForLanguage(
         condition_text, llvm::StringRef(), language, Expression::eResultTypeAny,
-        EvaluateExpressionOptions(), error));
+        EvaluateExpressionOptions(), nullptr, error));
     if (error.Fail()) {
       if (log)
         log->Printf("Error getting condition expression: %s.",
Index: source/API/SBValue.cpp
===================================================================
--- source/API/SBValue.cpp
+++ source/API/SBValue.cpp
@@ -1298,6 +1298,83 @@
   return false;
 }
 
+lldb::SBValue SBValue::EvaluateExpression(const char* expr) const {
+  ValueLocker locker;
+  lldb::ValueObjectSP value_sp(GetSP(locker));
+  if (!value_sp)
+    return SBValue();
+
+  lldb::TargetSP target_sp = value_sp->GetTargetSP();
+  if (!target_sp)
+    return SBValue();
+
+  lldb::SBExpressionOptions options;
+  options.SetFetchDynamicValue(target_sp->GetPreferDynamicValue());
+  options.SetUnwindOnError(true);
+  options.SetIgnoreBreakpoints(true);
+
+  return EvaluateExpression(expr, options);
+}
+
+lldb::SBValue
+SBValue::EvaluateExpression(const char* expr,
+                            const SBExpressionOptions& options) const {
+  Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_API));
+
+  if (!expr || expr[0] == '\0') {
+    if (log)
+      log->Printf(
+          "SBValue::EvaluateExpression called with an empty expression");
+    return SBValue();
+  }
+
+  if (log)
+    log->Printf("SBValue()::EvaluateExpression (expr=\"%s\")...", expr);
+
+  ValueLocker locker;
+  lldb::ValueObjectSP value_sp(GetSP(locker));
+  if (!value_sp) {
+    if (log)
+      log->Printf("SBValue::EvaluateExpression () => error: could not "
+                  "reconstruct value object for this SBValue");
+    return SBValue();
+  }
+
+  lldb::TargetSP target_sp = value_sp->GetTargetSP();
+  if (!target_sp) {
+    if (log)
+      log->Printf("SBValue::EvaluateExpression () => error: could not "
+                  "retrieve target");
+    return SBValue();
+  }
+
+  std::lock_guard<std::recursive_mutex> guard(target_sp->GetAPIMutex());
+  ExecutionContext exe_ctx(target_sp.get());
+
+  StackFrame *frame = exe_ctx.GetFramePtr();
+  if (!frame) {
+    if (log)
+      log->Printf("SBValue::EvaluateExpression () => error: could not "
+                  "retrieve current stack frame");
+    return SBValue();
+  }
+
+  ValueObjectSP res_val_sp;
+  ExpressionResults expr_res =
+      target_sp->EvaluateExpression(expr, frame, res_val_sp, options.ref(),
+                                    nullptr, value_sp);
+
+  if (log)
+    log->Printf("SBValue(%p)::EvaluateExpression (expr=\"%s\") => SBValue(%p) "
+                "(execution result=%d)",
+                static_cast<void *>(value_sp.get()), expr,
+                static_cast<void *>(res_val_sp.get()), expr_res);
+
+  SBValue result;
+  result.SetSP(res_val_sp, options.GetFetchDynamicValue());
+  return result;
+}
+
 bool SBValue::GetDescription(SBStream &description) {
   Stream &strm = description.ref();
 
Index: scripts/interface/SBValue.i
===================================================================
--- scripts/interface/SBValue.i
+++ scripts/interface/SBValue.i
@@ -449,7 +449,14 @@
     ) GetExpressionPath;
     bool
     GetExpressionPath (lldb::SBStream &description, bool qualify_cxx_base_classes);
-    
+
+    lldb::SBValue
+    EvaluateExpression(const char *expr) const;
+
+    lldb::SBValue
+    EvaluateExpression(const char *expr,
+                       const SBExpressionOptions &options) const;
+
     %pythoncode %{
         def __get_dynamic__ (self):
             '''Helper function for the "SBValue.dynamic" property.'''
Index: packages/Python/lldbsuite/test/expression_command/context-object/main.cpp
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/context-object/main.cpp
@@ -0,0 +1,18 @@
+struct S {
+  int a = 12;
+  int b = 34;
+
+  int foo() {
+    a--;
+    b--;
+    return a + b;
+  }
+};
+
+int main()
+{
+  S a;
+  int b = 1234;
+  a.foo();
+  return 0; // Break here
+}
Index: packages/Python/lldbsuite/test/expression_command/context-object/TestContextObject.py
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/context-object/TestContextObject.py
@@ -0,0 +1,42 @@
+"""
+Tests expression evaluation in context of an object.
+"""
+
+import lldb
+import lldbsuite.test.lldbutil as lldbutil
+from lldbsuite.test.lldbtest import *
+
+class ContextObjectTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    def test_context_object(self):
+        """Tests expression evaluation in context of an object."""
+        self.build()
+
+        (target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(self, '// Break here', self.main_source_spec)
+        frame = thread.GetFrameAtIndex(0)
+
+        obj_val = frame.FindVariable("a")
+        self.assertTrue(obj_val.IsValid())
+
+        value = obj_val.EvaluateExpression("a")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 11)
+
+        value = obj_val.EvaluateExpression("b")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 33)
+
+        value = obj_val.EvaluateExpression("foo()")
+        self.assertTrue(value.IsValid())
+        self.assertTrue(value.GetError().Success())
+        self.assertEqual(value.GetValueAsSigned(), 42)
+
+    def setUp(self):
+        TestBase.setUp(self)
+
+        self.main_source = "main.cpp"
+        self.main_source_spec = lldb.SBFileSpec(self.main_source)
Index: packages/Python/lldbsuite/test/expression_command/context-object/Makefile
===================================================================
--- /dev/null
+++ packages/Python/lldbsuite/test/expression_command/context-object/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
Index: include/lldb/Target/Target.h
===================================================================
--- include/lldb/Target/Target.h
+++ include/lldb/Target/Target.h
@@ -1038,7 +1038,8 @@
   UserExpression *GetUserExpressionForLanguage(
       llvm::StringRef expr, llvm::StringRef prefix, lldb::LanguageType language,
       Expression::ResultType desired_type,
-      const EvaluateExpressionOptions &options, Status &error);
+      const EvaluateExpressionOptions &options,
+      const lldb::ValueObjectSP &ctx_obj, Status &error);
 
   // Creates a FunctionCaller for the given language, the rest of the
   // parameters have the same meaning as for the FunctionCaller constructor.
@@ -1102,7 +1103,8 @@
       llvm::StringRef expression, ExecutionContextScope *exe_scope,
       lldb::ValueObjectSP &result_valobj_sp,
       const EvaluateExpressionOptions &options = EvaluateExpressionOptions(),
-      std::string *fixed_expression = nullptr);
+      std::string *fixed_expression = nullptr,
+      const lldb::ValueObjectSP &ctx_obj = lldb::ValueObjectSP());
 
   lldb::ExpressionVariableSP GetPersistentVariable(const ConstString &name);
 
Index: include/lldb/Symbol/TypeSystem.h
===================================================================
--- include/lldb/Symbol/TypeSystem.h
+++ include/lldb/Symbol/TypeSystem.h
@@ -449,7 +449,8 @@
   GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
                     lldb::LanguageType language,
                     Expression::ResultType desired_type,
-                    const EvaluateExpressionOptions &options) {
+                    const EvaluateExpressionOptions &options,
+                    const lldb::ValueObjectSP &ctx_obj) {
     return nullptr;
   }
 
Index: include/lldb/Symbol/ClangASTContext.h
===================================================================
--- include/lldb/Symbol/ClangASTContext.h
+++ include/lldb/Symbol/ClangASTContext.h
@@ -1053,7 +1053,8 @@
   GetUserExpression(llvm::StringRef expr, llvm::StringRef prefix,
                     lldb::LanguageType language,
                     Expression::ResultType desired_type,
-                    const EvaluateExpressionOptions &options) override;
+                    const EvaluateExpressionOptions &options,
+                    const lldb::ValueObjectSP &ctx_obj) override;
 
   FunctionCaller *GetFunctionCaller(const CompilerType &return_type,
                                     const Address &function_address,
Index: include/lldb/Expression/UserExpression.h
===================================================================
--- include/lldb/Expression/UserExpression.h
+++ include/lldb/Expression/UserExpression.h
@@ -273,6 +273,10 @@
   /// @param[out] jit_module_sp_ptr
   ///     If non-nullptr, used to persist the generated IR module.
   ///
+  /// @param[in] ctx_obj
+  ///     If specified, then the expression will be evaluated
+  ///     in the context of this object
+  ///
   /// @result
   ///      A Process::ExpressionResults value.  eExpressionCompleted for
   ///      success.
@@ -282,7 +286,8 @@
            llvm::StringRef expr_cstr, llvm::StringRef expr_prefix,
            lldb::ValueObjectSP &result_valobj_sp, Status &error,
            uint32_t line_offset = 0, std::string *fixed_expression = nullptr,
-           lldb::ModuleSP *jit_module_sp_ptr = nullptr);
+           lldb::ModuleSP *jit_module_sp_ptr = nullptr,
+           const lldb::ValueObjectSP &ctx_obj = lldb::ValueObjectSP());
 
   static const Status::ValueType kNoResult =
       0x1001; ///< ValueObject::GetError() returns this if there is no result
Index: include/lldb/Expression/ExpressionSourceCode.h
===================================================================
--- include/lldb/Expression/ExpressionSourceCode.h
+++ include/lldb/Expression/ExpressionSourceCode.h
@@ -37,7 +37,8 @@
   const char *GetName() const { return m_name.c_str(); }
 
   bool GetText(std::string &text, lldb::LanguageType wrapping_language,
-               bool static_method, ExecutionContext &exe_ctx) const;
+               bool static_method, ExecutionContext &exe_ctx,
+               bool add_locals) const;
 
   // Given a string returned by GetText, find the beginning and end of the body
   // passed to CreateWrapped. Return true if the bounds could be found.  This
Index: include/lldb/API/SBValue.h
===================================================================
--- include/lldb/API/SBValue.h
+++ include/lldb/API/SBValue.h
@@ -307,6 +307,10 @@
   bool GetExpressionPath(lldb::SBStream &description,
                          bool qualify_cxx_base_classes);
 
+  lldb::SBValue EvaluateExpression(const char *expr) const;
+  lldb::SBValue EvaluateExpression(const char *expr,
+                                   const SBExpressionOptions &options) const;
+
   SBValue(const lldb::ValueObjectSP &value_sp);
 
   //------------------------------------------------------------------
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to