diff --git a/lldb/include/lldb/API/SBDefines.h b/lldb/include/lldb/API/SBDefines.h index 28b71b165d81..e8740a8d5e69 100644 --- a/lldb/include/lldb/API/SBDefines.h +++ b/lldb/include/lldb/API/SBDefines.h @@ -41,6 +41,7 @@ class SBDeclaration; class SBError; class SBEvent; class SBEventList; +class SBExpressionOptions; class SBFileSpec; class SBFileSpecList; class SBFrame; diff --git a/lldb/include/lldb/API/SBExpressionOptions.h b/lldb/include/lldb/API/SBExpressionOptions.h new file mode 100644 index 000000000000..509ec052c911 --- /dev/null +++ b/lldb/include/lldb/API/SBExpressionOptions.h @@ -0,0 +1,96 @@ +//===-- SBEvent.h -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_SBExpressionOptions_h_ +#define LLDB_SBExpressionOptions_h_ + +#include "lldb/API/SBDefines.h" + +#include +#include + +namespace lldb { + + +class SBExpressionOptions +{ +friend class SBFrame; +friend class SBValue; + +public: + SBExpressionOptions(); + + SBExpressionOptions (const lldb::SBExpressionOptions &rhs); + + SBExpressionOptions (bool coerce_to_id, + bool unwind_on_error, + bool keep_in_memory, + bool run_others, + DynamicValueType use_dynamic, + uint32_t timeout_usec); + + ~SBExpressionOptions(); + + const SBExpressionOptions & + operator = (const lldb::SBExpressionOptions &rhs); + + bool + DoesCoerceToId () const; + + void + SetCoerceToId (bool coerce = true); + + bool + DoesUnwindOnError () const; + + void + SetUnwindOnError (bool unwind = false); + + bool + DoesKeepInMemory () const; + + void + SetKeepInMemory (bool keep = true); + + lldb::DynamicValueType + GetUseDynamic () const; + + void + SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget); + + uint32_t + GetTimeoutUsec () const; + + void + SetTimeoutUsec (uint32_t timeout = 0); + + bool + GetRunOthers () const; + + void + SetRunOthers (bool run_others = true); + +protected: + + SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); + + lldb_private::EvaluateExpressionOptions * + get () const; + + lldb_private::EvaluateExpressionOptions & + ref () const; + +private: + // This auto_pointer is made in the constructor and is always valid. + mutable std::auto_ptr m_opaque_ap; +}; + +} // namespace lldb + +#endif // LLDB_SBExpressionOptions_h_ diff --git a/lldb/include/lldb/API/SBFrame.h b/lldb/include/lldb/API/SBFrame.h index 7d3d208a2b62..8af708b7e5e9 100644 --- a/lldb/include/lldb/API/SBFrame.h +++ b/lldb/include/lldb/API/SBFrame.h @@ -105,6 +105,9 @@ public: lldb::SBValue EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error); + + lldb::SBValue + EvaluateExpression (const char *expr, const SBExpressionOptions &options); /// Gets the lexical block that defines the stack frame. Another way to think /// of this is it will return the block that contains all of the variables diff --git a/lldb/include/lldb/API/SBValue.h b/lldb/include/lldb/API/SBValue.h index 802a6e2b44f2..0502074d42d1 100644 --- a/lldb/include/lldb/API/SBValue.h +++ b/lldb/include/lldb/API/SBValue.h @@ -136,6 +136,9 @@ public: lldb::SBValue CreateValueFromExpression (const char *name, const char* expression); + lldb::SBValue + CreateValueFromExpression (const char *name, const char* expression, SBExpressionOptions &options); + lldb::SBValue CreateValueFromAddress (const char* name, lldb::addr_t address, diff --git a/lldb/include/lldb/Expression/ClangFunction.h b/lldb/include/lldb/Expression/ClangFunction.h index 47784d3c4959..68093eb759b8 100644 --- a/lldb/include/lldb/Expression/ClangFunction.h +++ b/lldb/include/lldb/Expression/ClangFunction.h @@ -251,9 +251,10 @@ public: /// function call, and return the program state to what it was before the /// execution. If false, we leave the program in the stopped state. /// - /// @param[in] single_thread_timeout_usec - /// If stop_others is true, the length of time to wait before - /// concluding that the system is deadlocked. + /// @param[in] timeout_usec + /// Timeout value (0 for no timeout). If try_all_threads is true, then we + /// will try on one thread for the lesser of .25 sec and half the total timeout. + /// then switch to running all threads, otherwise this will be the total timeout. /// /// @param[in] errors /// The stream to write errors to. @@ -272,7 +273,7 @@ public: bool stop_others, bool try_all_threads, bool discard_on_error, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, Stream &errors, lldb::addr_t* this_arg = 0); @@ -329,7 +330,7 @@ public: //------------------------------------------------------------------ /// Run the function this ClangFunction was created with. /// - /// This simple version will run the function on one thread. If \a single_thread_timeout_usec + /// This simple version will run the function on one thread. If \a timeout_usec /// is not zero, we time out after that timeout. If \a try_all_threads is true, then we will /// resume with all threads on, otherwise we halt the process, and eExecutionInterrupted will be returned. /// @@ -339,8 +340,10 @@ public: /// @param[in] errors /// Errors will be written here if there are any. /// - /// @param[in] single_thread_timeout_usec - /// If \b true, run only this thread, if \b false let all threads run. + /// @param[in] timeout_usec + /// Timeout value (0 for no timeout). If try_all_threads is true, then we + /// will try on one thread for the lesser of .25 sec and half the total timeout. + /// then switch to running all threads, otherwise this will be the total timeout. /// /// @param[in] try_all_threads /// If \b true, run only this thread, if \b false let all threads run. @@ -379,8 +382,11 @@ public: /// @param[in] stop_others /// If \b true, run only this thread, if \b false let all threads run. /// - /// @param[in] single_thread_timeout_usec - /// If \b true, run only this thread, if \b false let all threads run. + /// @param[in] timeout_usec + /// Timeout value (0 for no timeout). If try_all_threads is true, then we + /// will try on one thread for the lesser of .25 sec and half the total timeout. + /// then switch to running all threads, otherwise this will be the total timeout. + /// /// /// @param[in] try_all_threads /// If \b true, run only this thread, if \b false let all threads run. @@ -396,7 +402,7 @@ public: lldb::addr_t *args_addr_ptr, Stream &errors, bool stop_others, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, bool try_all_threads, bool discard_on_error, Value &results); diff --git a/lldb/include/lldb/Expression/ClangUserExpression.h b/lldb/include/lldb/Expression/ClangUserExpression.h index 772f7f6b5b7b..dc46ebe34c22 100644 --- a/lldb/include/lldb/Expression/ClangUserExpression.h +++ b/lldb/include/lldb/Expression/ClangUserExpression.h @@ -132,9 +132,16 @@ public: /// A pointer to direct at the persistent variable in which the /// expression's result is stored. /// - /// @param[in] single_thread_timeout_usec - /// The amount of time (in usec) that we are willing to wait for this - /// expression to complete, before assuming that we are blocked and giving up + /// @param[in] try_all_threads + /// If true, then we will try to run all threads if the function doesn't complete on + /// one thread. See timeout_usec for the interaction of this variable and + /// the timeout. + /// + /// @param[in] timeout_usec + /// Timeout value (0 for no timeout). If try_all_threads is true, then we + /// will try on one thread for the lesser of .25 sec and half the total timeout. + /// then switch to running all threads, otherwise this will be the total timeout. + /// /// /// @return /// A Process::Execution results value. @@ -145,7 +152,8 @@ public: bool discard_on_error, ClangUserExpressionSP &shared_ptr_to_me, lldb::ClangExpressionVariableSP &result, - uint32_t single_thread_timeout_usec = 500000); + bool try_all_threads = true, + uint32_t timeout_usec = 500000); ThreadPlan * GetThreadPlanToExecuteJITExpression (Stream &error_stream, @@ -314,9 +322,15 @@ public: /// @param[in/out] result_valobj_sp /// If execution is successful, the result valobj is placed here. /// - /// @param[in] single_thread_timeout_usec - /// The amount of time (in usec) that we are willing to wait for this - /// expression to complete, before assuming that we are blocked and giving up + /// @param[in] try_all_threads + /// If true, then we will try to run all threads if the function doesn't complete on + /// one thread. See timeout_usec for the interaction of this variable and + /// the timeout. + /// + /// @param[in] timeout_usec + /// Timeout value (0 for no timeout). If try_all_threads is true, then we + /// will try on one thread for the lesser of .25 sec and half the total timeout. + /// then switch to running all threads, otherwise this will be the total timeout. /// /// @result /// A Process::ExecutionResults value. eExecutionCompleted for success. @@ -330,7 +344,8 @@ public: const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, - uint32_t single_thread_timeout_usec = 500000); + bool try_all_threads = true, + uint32_t timeout_usec = 500000); static ExecutionResults EvaluateWithError (ExecutionContext &exe_ctx, @@ -342,7 +357,8 @@ public: const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, Error &error, - uint32_t single_thread_timeout_usec = 500000); + bool try_all_threads = true, + uint32_t timeout_usec = 500000); static const Error::ValueType kNoResult = 0x1001; ///< ValueObject::GetError() returns this if there is no result from the expression. private: diff --git a/lldb/include/lldb/Target/Process.h b/lldb/include/lldb/Target/Process.h index e043190059df..1278a44dc78c 100644 --- a/lldb/include/lldb/Target/Process.h +++ b/lldb/include/lldb/Target/Process.h @@ -2363,9 +2363,9 @@ public: RunThreadPlan (ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, bool stop_others, - bool try_all_threads, + bool run_others, bool discard_on_error, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, Stream &errors); static const char * diff --git a/lldb/include/lldb/Target/Target.h b/lldb/include/lldb/Target/Target.h index 15b87d7ce6ba..8d68a490a2bc 100644 --- a/lldb/include/lldb/Target/Target.h +++ b/lldb/include/lldb/Target/Target.h @@ -137,6 +137,121 @@ public: typedef STD_SHARED_PTR(TargetProperties) TargetPropertiesSP; +class EvaluateExpressionOptions +{ +public: + static const uint32_t default_timeout = 500000; + EvaluateExpressionOptions() : + m_execution_policy(eExecutionPolicyOnlyWhenNeeded), + m_coerce_to_id(false), + m_unwind_on_error(true), + m_keep_in_memory(false), + m_run_others(true), + m_use_dynamic(lldb::eNoDynamicValues), + m_timeout_usec(default_timeout) + {} + + ExecutionPolicy + GetExecutionPolicy () const + { + return m_execution_policy; + } + + EvaluateExpressionOptions& + SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways) + { + m_execution_policy = policy; + return *this; + } + + bool + DoesCoerceToId () const + { + return m_coerce_to_id; + } + + EvaluateExpressionOptions& + SetCoerceToId (bool coerce = true) + { + m_coerce_to_id = coerce; + return *this; + } + + bool + DoesUnwindOnError () const + { + return m_unwind_on_error; + } + + EvaluateExpressionOptions& + SetUnwindOnError (bool unwind = false) + { + m_unwind_on_error = unwind; + return *this; + } + + bool + DoesKeepInMemory () const + { + return m_keep_in_memory; + } + + EvaluateExpressionOptions& + SetKeepInMemory (bool keep = true) + { + m_keep_in_memory = keep; + return *this; + } + + lldb::DynamicValueType + GetUseDynamic () const + { + return m_use_dynamic; + } + + EvaluateExpressionOptions& + SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget) + { + m_use_dynamic = dynamic; + return *this; + } + + uint32_t + GetTimeoutUsec () const + { + return m_timeout_usec; + } + + EvaluateExpressionOptions& + SetTimeoutUsec (uint32_t timeout = 0) + { + m_timeout_usec = timeout; + return *this; + } + + bool + GetRunOthers () const + { + return m_run_others; + } + + EvaluateExpressionOptions& + SetRunOthers (bool run_others = true) + { + m_run_others = run_others; + return *this; + } + +private: + ExecutionPolicy m_execution_policy; + bool m_coerce_to_id; + bool m_unwind_on_error; + bool m_keep_in_memory; + bool m_run_others; + lldb::DynamicValueType m_use_dynamic; + uint32_t m_timeout_usec; +}; + //---------------------------------------------------------------------- // Target //---------------------------------------------------------------------- @@ -760,104 +875,6 @@ public: ClangASTImporter * GetClangASTImporter(); - class EvaluateExpressionOptions - { - public: - EvaluateExpressionOptions() : - m_execution_policy(eExecutionPolicyOnlyWhenNeeded), - m_coerce_to_id(false), - m_unwind_on_error(true), - m_keep_in_memory(false), - m_use_dynamic(lldb::eNoDynamicValues), - m_single_thread_timeout_usec(500000) - {} - - ExecutionPolicy - GetExecutionPolicy () const - { - return m_execution_policy; - } - - EvaluateExpressionOptions& - SetExecutionPolicy (ExecutionPolicy policy = eExecutionPolicyAlways) - { - m_execution_policy = policy; - return *this; - } - - bool - DoesCoerceToId () const - { - return m_coerce_to_id; - } - - EvaluateExpressionOptions& - SetCoerceToId (bool coerce = true) - { - m_coerce_to_id = coerce; - return *this; - } - - bool - DoesUnwindOnError () const - { - return m_unwind_on_error; - } - - EvaluateExpressionOptions& - SetUnwindOnError (bool unwind = false) - { - m_unwind_on_error = unwind; - return *this; - } - - bool - DoesKeepInMemory () const - { - return m_keep_in_memory; - } - - EvaluateExpressionOptions& - SetKeepInMemory (bool keep = true) - { - m_keep_in_memory = keep; - return *this; - } - - lldb::DynamicValueType - GetUseDynamic () const - { - return m_use_dynamic; - } - - EvaluateExpressionOptions& - SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget) - { - m_use_dynamic = dynamic; - return *this; - } - - uint32_t - GetSingleThreadTimeoutUsec () const - { - return m_single_thread_timeout_usec; - } - - EvaluateExpressionOptions& - SetSingleThreadTimeoutUsec (uint32_t timeout = 0) - { - m_single_thread_timeout_usec = timeout; - return *this; - } - - private: - ExecutionPolicy m_execution_policy; - bool m_coerce_to_id; - bool m_unwind_on_error; - bool m_keep_in_memory; - lldb::DynamicValueType m_use_dynamic; - uint32_t m_single_thread_timeout_usec; - }; // Since expressions results can persist beyond the lifetime of a process, // and the const expression results are available after a process is gone, diff --git a/lldb/include/lldb/lldb-forward.h b/lldb/include/lldb/lldb-forward.h index 84cecd184c51..c128de1dbcae 100644 --- a/lldb/include/lldb/lldb-forward.h +++ b/lldb/include/lldb/lldb-forward.h @@ -98,6 +98,7 @@ class DynamicLibrary; class DynamicLoader; class EmulateInstruction; class Error; +class EvaluateExpressionOptions; class Event; class EventData; class ExecutionContext; diff --git a/lldb/lldb.xcodeproj/project.pbxproj b/lldb/lldb.xcodeproj/project.pbxproj index 9139e5cfd050..80469723c3e8 100644 --- a/lldb/lldb.xcodeproj/project.pbxproj +++ b/lldb/lldb.xcodeproj/project.pbxproj @@ -505,6 +505,8 @@ 4CCA645613B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644813B40B82003BDF98 /* AppleObjCTrampolineHandler.cpp */; }; 4CCA645813B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CCA644A13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.cpp */; }; 4CD0BD0F134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */; }; + 4CE4F673162C971A00F75CB3 /* SBExpressionOptions.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 4CE4F675162C973F00F75CB3 /* SBExpressionOptions.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */; }; 4CF3D80C15AF4DC800845BF3 /* Security.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = EDB919B414F6F10D008FF64B /* Security.framework */; }; 4CF52AF51428291E0051E832 /* SBFileSpecList.h in Headers */ = {isa = PBXBuildFile; fileRef = 4CF52AF41428291E0051E832 /* SBFileSpecList.h */; settings = {ATTRIBUTES = (Public, ); }; }; 4CF52AF8142829390051E832 /* SBFileSpecList.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */; }; @@ -1492,6 +1494,9 @@ 4CCA644B13B40B82003BDF98 /* AppleThreadPlanStepThroughObjCTrampoline.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = AppleThreadPlanStepThroughObjCTrampoline.h; sourceTree = ""; }; 4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectDynamicValue.h; path = include/lldb/Core/ValueObjectDynamicValue.h; sourceTree = ""; }; 4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectDynamicValue.cpp; path = source/Core/ValueObjectDynamicValue.cpp; sourceTree = ""; }; + 4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBExpressionOptions.h; path = include/lldb/API/SBExpressionOptions.h; sourceTree = ""; }; + 4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBExpressionOptions.cpp; path = source/API/SBExpressionOptions.cpp; sourceTree = ""; }; + 4CE4F676162CE1E100F75CB3 /* SBExpressionOptions.i */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBExpressionOptions.i; sourceTree = ""; }; 4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = ""; }; 4CF52AF41428291E0051E832 /* SBFileSpecList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFileSpecList.h; path = include/lldb/API/SBFileSpecList.h; sourceTree = ""; }; 4CF52AF7142829390051E832 /* SBFileSpecList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFileSpecList.cpp; path = source/API/SBFileSpecList.cpp; sourceTree = ""; }; @@ -2028,6 +2033,7 @@ 2611FEFC142D83060017FEA3 /* SBFileSpec.i */, 2611FEFD142D83060017FEA3 /* SBFileSpecList.i */, 2611FEFE142D83060017FEA3 /* SBFrame.i */, + 4CE4F676162CE1E100F75CB3 /* SBExpressionOptions.i */, 2611FEFF142D83060017FEA3 /* SBFunction.i */, 2611FF00142D83060017FEA3 /* SBHostOS.i */, 2611FF01142D83060017FEA3 /* SBInputReader.i */, @@ -2118,6 +2124,8 @@ 2682F284115EF3A700CCFF99 /* SBError.cpp */, 9A9830FE1125FC5800A56CB0 /* SBEvent.h */, 9A9830FD1125FC5800A56CB0 /* SBEvent.cpp */, + 4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */, + 4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */, 26022531115F27FA00A601A2 /* SBFileSpec.h */, 26022532115F281400A601A2 /* SBFileSpec.cpp */, 4CF52AF41428291E0051E832 /* SBFileSpecList.h */, @@ -3381,6 +3389,7 @@ B2A58722143119810092BFBA /* SBWatchpoint.h in Headers */, 26D265A2136B40EE002EEE45 /* SharingPtr.h in Headers */, 26D265BC136B4269002EEE45 /* lldb-public.h in Headers */, + 4CE4F673162C971A00F75CB3 /* SBExpressionOptions.h in Headers */, ); runOnlyForDeploymentPostprocessing = 0; }; @@ -3773,6 +3782,7 @@ 9475C18814E5E9FA001BFC6D /* SBTypeCategory.cpp in Sources */, 9475C18E14E5F834001BFC6D /* SBTypeNameSpecifier.cpp in Sources */, 9452573A16262D0200325455 /* SBDeclaration.cpp in Sources */, + 4CE4F675162C973F00F75CB3 /* SBExpressionOptions.cpp in Sources */, ); runOnlyForDeploymentPostprocessing = 0; }; diff --git a/lldb/scripts/Python/build-swig-Python.sh b/lldb/scripts/Python/build-swig-Python.sh index a38d2ff91f4a..59394f9cc0ea 100755 --- a/lldb/scripts/Python/build-swig-Python.sh +++ b/lldb/scripts/Python/build-swig-Python.sh @@ -76,6 +76,7 @@ HEADER_FILES="${SRC_ROOT}/include/lldb/lldb.h"\ " ${SRC_ROOT}/include/lldb/API/SBDebugger.h"\ " ${SRC_ROOT}/include/lldb/API/SBError.h"\ " ${SRC_ROOT}/include/lldb/API/SBEvent.h"\ +" ${SRC_ROOT}/include/lldb/API/SBExpressionOptions.h"\ " ${SRC_ROOT}/include/lldb/API/SBFileSpec.h"\ " ${SRC_ROOT}/include/lldb/API/SBFrame.h"\ " ${SRC_ROOT}/include/lldb/API/SBFunction.h"\ @@ -120,6 +121,7 @@ INTERFACE_FILES="${SRC_ROOT}/scripts/Python/interface/SBAddress.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBDeclaration.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBError.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBEvent.i"\ +" ${SRC_ROOT}/scripts/Python/interface/SBExpressionOptions.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBFileSpec.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBFrame.i"\ " ${SRC_ROOT}/scripts/Python/interface/SBFunction.i"\ diff --git a/lldb/scripts/Python/interface/SBExpressionOptions.i b/lldb/scripts/Python/interface/SBExpressionOptions.i new file mode 100644 index 000000000000..fa58fe36896a --- /dev/null +++ b/lldb/scripts/Python/interface/SBExpressionOptions.i @@ -0,0 +1,104 @@ +//===-- SWIG interface for SBExpressionOptions -----------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +namespace lldb { + +%feature("docstring", +"A container for options to use when evaluating expressions." +) SBExpressionOptions; + +class SBExpressionOptions +{ +friend class SBFrame; +friend class SBValue; + +public: + SBExpressionOptions(); + + SBExpressionOptions (const lldb::SBExpressionOptions &rhs); + + SBExpressionOptions (bool coerce_to_id, + bool unwind_on_error, + bool keep_in_memory, + bool run_others, + DynamicValueType use_dynamic, + uint32_t timeout_usec); + + ~SBExpressionOptions(); + + bool + DoesCoerceToId () const; + + %feature("docstring", + "Sets whether to coerce the expression result to ObjC id type after evaluation." + ) SetCoerceToId; + void + SetCoerceToId (bool coerce = true); + + bool + DoesUnwindOnError () const; + + %feature("docstring", + "Sets whether to unwind the expression stack on error." + ) SetUnwindOnError; + void + SetUnwindOnError (bool unwind = false); + + bool + DoesKeepInMemory () const; + + %feature("docstring", + "Sets whether to keep the expression result in the target program's memory - forced to true when creating SBValues." + ) SetKeepInMemory; + void + SetKeepInMemory (bool keep = true); + + lldb::DynamicValueType + GetUseDynamic () const; + + %feature("docstring", + "Sets whether to cast the expression result to its dynamic type." + ) SetUseDynamic; + void + SetUseDynamic (lldb::DynamicValueType dynamic = lldb::eDynamicCanRunTarget); + + uint32_t + GetTimeoutUsec () const; + + %feature("docstring", + "Sets the duration we will wait before cancelling expression evaluation. 0 means wait forever." + ) SetTimeoutUsec; + void + SetTimeoutUsec (uint32_t timeout = 0); + + bool + GetRunOthers () const; + + %feature("docstring", + "Sets whether to run all threads if the expression does not complete on one thread." + ) SetRunOthers; + void + SetRunOthers (bool run_others = true); + +protected: + + SBExpressionOptions (lldb_private::EvaluateExpressionOptions &expression_options); + + lldb_private::EvaluateExpressionOptions * + get () const; + + lldb_private::EvaluateExpressionOptions & + ref () const; + +private: + // This auto_pointer is made in the constructor and is always valid. + mutable std::auto_ptr m_opaque_ap; +}; + +} // namespace lldb diff --git a/lldb/scripts/Python/interface/SBFrame.i b/lldb/scripts/Python/interface/SBFrame.i index 7d0256442887..1735dd994721 100644 --- a/lldb/scripts/Python/interface/SBFrame.i +++ b/lldb/scripts/Python/interface/SBFrame.i @@ -139,6 +139,9 @@ public: lldb::SBValue EvaluateExpression (const char *expr, lldb::DynamicValueType use_dynamic, bool unwind_on_error); + + lldb::SBValue + EvaluateExpression (const char *expr, SBExpressionOptions &options); %feature("docstring", " /// Gets the lexical block that defines the stack frame. Another way to think diff --git a/lldb/scripts/Python/interface/SBValue.i b/lldb/scripts/Python/interface/SBValue.i index e316637f9e6e..70c3d8074533 100644 --- a/lldb/scripts/Python/interface/SBValue.i +++ b/lldb/scripts/Python/interface/SBValue.i @@ -222,6 +222,9 @@ public: lldb::SBValue CreateValueFromExpression (const char *name, const char* expression); + + lldb::SBValue + CreateValueFromExpression (const char *name, const char* expression, SBExpressionOptions &options); lldb::SBValue CreateValueFromAddress(const char* name, lldb::addr_t address, lldb::SBType type); diff --git a/lldb/scripts/lldb.swig b/lldb/scripts/lldb.swig index 12dc859e1056..a89b6758e002 100644 --- a/lldb/scripts/lldb.swig +++ b/lldb/scripts/lldb.swig @@ -66,6 +66,7 @@ import os #include "lldb/API/SBDeclaration.h" #include "lldb/API/SBError.h" #include "lldb/API/SBEvent.h" +#include "lldb/API/SBExpressionOptions.h" #include "lldb/API/SBFileSpec.h" #include "lldb/API/SBFileSpecList.h" #include "lldb/API/SBFrame.h" @@ -125,6 +126,7 @@ import os %include "./Python/interface/SBDeclaration.i" %include "./Python/interface/SBError.i" %include "./Python/interface/SBEvent.i" +%include "./Python/interface/SBExpressionOptions.i" %include "./Python/interface/SBFileSpec.i" %include "./Python/interface/SBFileSpecList.i" %include "./Python/interface/SBFrame.i" diff --git a/lldb/source/API/SBExpressionOptions.cpp b/lldb/source/API/SBExpressionOptions.cpp new file mode 100644 index 000000000000..2a4b9f564b2d --- /dev/null +++ b/lldb/source/API/SBExpressionOptions.cpp @@ -0,0 +1,142 @@ +//===-- SBExpressionOptions.cpp ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/API/SBExpressionOptions.h" +#include "lldb/API/SBStream.h" + +#include "lldb/Target/Target.h" + +using namespace lldb; +using namespace lldb_private; + + +SBExpressionOptions::SBExpressionOptions () +{ + m_opaque_ap.reset(new EvaluateExpressionOptions()); +} + +SBExpressionOptions::SBExpressionOptions (bool coerce_to_id, + bool unwind_on_error, + bool keep_in_memory, + bool run_others, + DynamicValueType use_dynamic, + uint32_t timeout_usec) +{ + m_opaque_ap.reset(new EvaluateExpressionOptions()); + m_opaque_ap->SetCoerceToId(coerce_to_id); + m_opaque_ap->SetUnwindOnError(unwind_on_error); + m_opaque_ap->SetKeepInMemory(keep_in_memory); + m_opaque_ap->SetRunOthers(run_others); + m_opaque_ap->SetUseDynamic (use_dynamic); + m_opaque_ap->SetTimeoutUsec (timeout_usec); +} + +SBExpressionOptions::SBExpressionOptions (const SBExpressionOptions &rhs) +{ + m_opaque_ap.reset(new EvaluateExpressionOptions()); + *(m_opaque_ap.get()) = rhs.ref(); +} + +const SBExpressionOptions & +SBExpressionOptions::operator = (const SBExpressionOptions &rhs) +{ + if (this != &rhs) + { + this->ref() = rhs.ref(); + } + return *this; +} + +SBExpressionOptions::~SBExpressionOptions() +{ +} + +bool +SBExpressionOptions::DoesCoerceToId () const +{ + return m_opaque_ap->DoesCoerceToId (); +} + +void +SBExpressionOptions::SetCoerceToId (bool coerce) +{ + m_opaque_ap->SetCoerceToId (coerce); +} + +bool +SBExpressionOptions::DoesUnwindOnError () const +{ + return m_opaque_ap->DoesUnwindOnError (); +} + +void +SBExpressionOptions::SetUnwindOnError (bool unwind) +{ + m_opaque_ap->SetUnwindOnError (unwind); +} + +bool +SBExpressionOptions::DoesKeepInMemory () const +{ + return m_opaque_ap->DoesKeepInMemory (); +} + +void +SBExpressionOptions::SetKeepInMemory (bool keep) +{ + m_opaque_ap->SetKeepInMemory (keep); +} + +lldb::DynamicValueType +SBExpressionOptions::GetUseDynamic () const +{ + return m_opaque_ap->GetUseDynamic (); +} + +void +SBExpressionOptions::SetUseDynamic (lldb::DynamicValueType dynamic) +{ + m_opaque_ap->SetUseDynamic (dynamic); +} + +uint32_t +SBExpressionOptions::GetTimeoutUsec () const +{ + return m_opaque_ap->GetTimeoutUsec (); +} + +void +SBExpressionOptions::SetTimeoutUsec (uint32_t timeout) +{ + m_opaque_ap->SetTimeoutUsec (timeout); +} + +bool +SBExpressionOptions::GetRunOthers () const +{ + return m_opaque_ap->GetRunOthers (); +} + +void +SBExpressionOptions::SetRunOthers (bool run_others) +{ + m_opaque_ap->SetRunOthers (run_others); +} + +EvaluateExpressionOptions * +SBExpressionOptions::get() const +{ + return m_opaque_ap.get(); +} + +EvaluateExpressionOptions & +SBExpressionOptions::ref () const +{ + return *(m_opaque_ap.get()); +} diff --git a/lldb/source/API/SBFrame.cpp b/lldb/source/API/SBFrame.cpp index b94a0ce9267e..f89c25b27e1c 100644 --- a/lldb/source/API/SBFrame.cpp +++ b/lldb/source/API/SBFrame.cpp @@ -40,6 +40,7 @@ #include "lldb/API/SBDebugger.h" #include "lldb/API/SBValue.h" #include "lldb/API/SBAddress.h" +#include "lldb/API/SBExpressionOptions.h" #include "lldb/API/SBStream.h" #include "lldb/API/SBSymbolContext.h" #include "lldb/API/SBThread.h" @@ -1040,8 +1041,11 @@ SBFrame::EvaluateExpression (const char *expr) Target *target = exe_ctx.GetTargetPtr(); if (frame && target) { - lldb::DynamicValueType use_dynamic = frame->CalculateTarget()->GetPreferDynamicValue(); - result = EvaluateExpression (expr, use_dynamic); + SBExpressionOptions options; + lldb::DynamicValueType fetch_dynamic_value = frame->CalculateTarget()->GetPreferDynamicValue(); + options.SetUseDynamic (fetch_dynamic_value); + options.SetUnwindOnError (true); + return EvaluateExpression (expr, options); } return result; } @@ -1049,11 +1053,23 @@ SBFrame::EvaluateExpression (const char *expr) SBValue SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value) { - return EvaluateExpression (expr, fetch_dynamic_value, true); + SBExpressionOptions options; + options.SetUseDynamic (fetch_dynamic_value); + options.SetUnwindOnError (true); + return EvaluateExpression (expr, options); } SBValue SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dynamic_value, bool unwind_on_error) +{ + SBExpressionOptions options; + options.SetUseDynamic (fetch_dynamic_value); + options.SetUnwindOnError (unwind_on_error); + return EvaluateExpression (expr, options); +} + +lldb::SBValue +SBFrame::EvaluateExpression (const char *expr, const SBExpressionOptions &options) { LogSP log(GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); @@ -1080,16 +1096,12 @@ SBFrame::EvaluateExpression (const char *expr, lldb::DynamicValueType fetch_dyna StreamString frame_description; frame->DumpUsingSettingsFormat (&frame_description); Host::SetCrashDescriptionWithFormat ("SBFrame::EvaluateExpression (expr = \"%s\", fetch_dynamic_value = %u) %s", - expr, fetch_dynamic_value, frame_description.GetString().c_str()); + expr, options.GetUseDynamic(), frame_description.GetString().c_str()); #endif - Target::EvaluateExpressionOptions options; - options.SetUnwindOnError(unwind_on_error) - .SetUseDynamic(fetch_dynamic_value); - exe_results = target->EvaluateExpression (expr, frame, expr_value_sp, - options); + options.ref()); expr_result.SetSP(expr_value_sp); #ifdef LLDB_CONFIGURATION_DEBUG Host::SetCrashDescription (NULL); diff --git a/lldb/source/API/SBValue.cpp b/lldb/source/API/SBValue.cpp index 913a447aba54..0aa01a6c9cc0 100644 --- a/lldb/source/API/SBValue.cpp +++ b/lldb/source/API/SBValue.cpp @@ -40,11 +40,12 @@ #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" +#include "lldb/API/SBDebugger.h" +#include "lldb/API/SBExpressionOptions.h" +#include "lldb/API/SBFrame.h" #include "lldb/API/SBProcess.h" #include "lldb/API/SBTarget.h" #include "lldb/API/SBThread.h" -#include "lldb/API/SBFrame.h" -#include "lldb/API/SBDebugger.h" using namespace lldb; using namespace lldb_private; @@ -694,9 +695,12 @@ SBValue::CreateChildAtOffset (const char *name, uint32_t offset, SBType type) if (log) { if (new_value_sp) - log->Printf ("SBValue(%p)::CreateChildAtOffset => \"%s\"", value_sp.get(), new_value_sp->GetName().AsCString()); + log->Printf ("SBValue(%p)::CreateChildAtOffset => \"%s\"", + value_sp.get(), + new_value_sp->GetName().AsCString()); else - log->Printf ("SBValue(%p)::CreateChildAtOffset => NULL", value_sp.get()); + log->Printf ("SBValue(%p)::CreateChildAtOffset => NULL", + value_sp.get()); } return sb_value; } @@ -714,6 +718,14 @@ SBValue::Cast (SBType type) lldb::SBValue SBValue::CreateValueFromExpression (const char *name, const char* expression) +{ + SBExpressionOptions options; + options.SetKeepInMemory(true); + return CreateValueFromExpression (name, expression, options); +} + +lldb::SBValue +SBValue::CreateValueFromExpression (const char *name, const char *expression, SBExpressionOptions &options) { LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); lldb::SBValue sb_value; @@ -734,12 +746,11 @@ SBValue::CreateValueFromExpression (const char *name, const char* expression) Target* target = exe_ctx.GetTargetPtr(); if (target) { - Target::EvaluateExpressionOptions options; options.SetKeepInMemory(true); target->EvaluateExpression (expression, exe_ctx.GetFramePtr(), new_value_sp, - options); + options.ref()); if (new_value_sp) { new_value_sp->SetName(ConstString(name)); @@ -1617,7 +1628,9 @@ SBValue::GetAddress() } LogSP log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_API)); if (log) - log->Printf ("SBValue(%p)::GetAddress () => (%s,%llu)", value_sp.get(), (addr.GetSection() ? addr.GetSection()->GetName().GetCString() : "NULL"), addr.GetOffset()); + log->Printf ("SBValue(%p)::GetAddress () => (%s,%llu)", value_sp.get(), + (addr.GetSection() ? addr.GetSection()->GetName().GetCString() : "NULL"), + addr.GetOffset()); return SBAddress(new Address(addr)); } diff --git a/lldb/source/Commands/CommandObjectExpression.cpp b/lldb/source/Commands/CommandObjectExpression.cpp index 23c9dc103735..ee053608e7c5 100644 --- a/lldb/source/Commands/CommandObjectExpression.cpp +++ b/lldb/source/Commands/CommandObjectExpression.cpp @@ -50,7 +50,9 @@ CommandObjectExpression::CommandOptions::~CommandOptions () OptionDefinition CommandObjectExpression::CommandOptions::g_option_table[] = { + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "all-threads", 'a', required_argument, NULL, 0, eArgTypeBoolean, "Should we run all threads if the execution doesn't complete on one thread."}, { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "dynamic-value", 'd', required_argument, NULL, 0, eArgTypeBoolean, "Upcast the value resulting from the expression to its dynamic type if available."}, + { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "timeout", 't', required_argument, NULL, 0, eArgTypeUnsignedInteger, "Timeout value for running the expression."}, { LLDB_OPT_SET_1 | LLDB_OPT_SET_2, false, "unwind-on-error", 'u', required_argument, NULL, 0, eArgTypeBoolean, "Clean up program state if the expression causes a crash, breakpoint hit or signal."}, { LLDB_OPT_SET_2 , false, "object-description", 'o', no_argument, NULL, 0, eArgTypeNone, "Print the object description of the value resulting from the expression."}, }; @@ -80,8 +82,16 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int //} //break; - case 'o': - print_object = true; + case 'a': + { + bool success; + bool result; + result = Args::StringToBoolean(option_arg, true, &success); + if (!success) + error.SetErrorStringWithFormat("invalid all-threads value setting: \"%s\"", option_arg); + else + try_all_threads = result; + } break; case 'd': @@ -101,6 +111,22 @@ CommandObjectExpression::CommandOptions::SetOptionValue (CommandInterpreter &int } break; + case 'o': + print_object = true; + break; + + case 't': + { + bool success; + uint32_t result; + result = Args::StringToUInt32(option_arg, 0, 0, &success); + if (success) + timeout = result; + else + error.SetErrorStringWithFormat ("invalid timeout setting \"%s\"", option_arg); + } + break; + case 'u': { bool success; @@ -125,6 +151,8 @@ CommandObjectExpression::CommandOptions::OptionParsingStarting (CommandInterpret unwind_on_error = true; show_types = true; show_summary = true; + try_all_threads = true; + timeout = 0; } const OptionDefinition* @@ -146,7 +174,13 @@ CommandObjectExpression::CommandObjectExpression (CommandInterpreter &interprete m_expr_lines () { SetHelpLong( -"Examples: \n\ +"Timeouts:\n\ + If the expression can be evaluated statically (without runnning code) then it will be.\n\ + Otherwise, by default the expression will run on the current thread with a short timeout:\n\ + currently .25 seconds. If it doesn't return in that time, the evaluation will be interrupted\n\ + and resumed with all threads running. You can use the -a option to disable retrying on all\n\ + threads. You can use the -t option to set a shorter timeout.\n\ +Examples: \n\ \n\ expr my_struct->a = my_array[3] \n\ expr -f bin -- (index * 8) + 5 \n\ @@ -298,12 +332,13 @@ CommandObjectExpression::EvaluateExpression break; } - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(m_command_options.print_object) .SetUnwindOnError(m_command_options.unwind_on_error) .SetKeepInMemory(keep_in_memory) .SetUseDynamic(use_dynamic) - .SetSingleThreadTimeoutUsec(0); + .SetRunOthers(m_command_options.try_all_threads) + .SetTimeoutUsec(m_command_options.timeout); exe_results = target->EvaluateExpression (expr, m_interpreter.GetExecutionContext().GetFramePtr(), diff --git a/lldb/source/Commands/CommandObjectExpression.h b/lldb/source/Commands/CommandObjectExpression.h index 7c15aa1da830..4ccadfcd8c1a 100644 --- a/lldb/source/Commands/CommandObjectExpression.h +++ b/lldb/source/Commands/CommandObjectExpression.h @@ -55,6 +55,8 @@ public: bool unwind_on_error; bool show_types; bool show_summary; + uint32_t timeout; + bool try_all_threads; }; CommandObjectExpression (CommandInterpreter &interpreter); diff --git a/lldb/source/Commands/CommandObjectThread.cpp b/lldb/source/Commands/CommandObjectThread.cpp index 8c2be3792e72..0547d38fe4d3 100644 --- a/lldb/source/Commands/CommandObjectThread.cpp +++ b/lldb/source/Commands/CommandObjectThread.cpp @@ -1314,7 +1314,7 @@ protected: if (command && command[0] != '\0') { Target *target = exe_ctx.GetTargetPtr(); - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetUnwindOnError(true); options.SetUseDynamic(eNoDynamicValues); diff --git a/lldb/source/Commands/CommandObjectWatchpoint.cpp b/lldb/source/Commands/CommandObjectWatchpoint.cpp index 8a74471914f1..63275f9d303c 100644 --- a/lldb/source/Commands/CommandObjectWatchpoint.cpp +++ b/lldb/source/Commands/CommandObjectWatchpoint.cpp @@ -1234,11 +1234,12 @@ protected: } // Use expression evaluation to arrive at the address to watch. - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(false) - .SetSingleThreadTimeoutUsec(0); + .SetRunOthers(true) + .SetTimeoutUsec(0); ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), frame, diff --git a/lldb/source/Core/CXXFormatterFunctions.cpp b/lldb/source/Core/CXXFormatterFunctions.cpp index d8b929e2fe9c..67f769805eab 100644 --- a/lldb/source/Core/CXXFormatterFunctions.cpp +++ b/lldb/source/Core/CXXFormatterFunctions.cpp @@ -47,7 +47,7 @@ lldb_private::formatters::ExtractValueFromObjCExpression (ValueObject &valobj, if (!target || !stack_frame) return false; - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(true) @@ -85,7 +85,7 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, if (!target || !stack_frame) return valobj_sp; - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(true) @@ -122,7 +122,7 @@ lldb_private::formatters::CallSelectorOnObject (ValueObject &valobj, if (!target || !stack_frame) return valobj_sp; - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(true) @@ -459,7 +459,7 @@ lldb_private::formatters::NSNumberSummaryProvider (ValueObject& valobj, Stream& if (!target || !stack_frame) return false; - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(true) @@ -1055,7 +1055,7 @@ lldb_private::formatters::NSDictionaryCodeRunningSyntheticFrontEnd::GetChildAtIn object_fetcher_expr.Printf("struct __lldb_autogen_nspair { id key; id value; } _lldb_valgen_item; _lldb_valgen_item.key = %s; _lldb_valgen_item.value = %s; _lldb_valgen_item;",key_fetcher_expr.GetData(),value_fetcher_expr.GetData()); lldb::ValueObjectSP child_sp; m_backend.GetTargetSP()->EvaluateExpression(object_fetcher_expr.GetData(), m_backend.GetFrameSP().get(), child_sp, - Target::EvaluateExpressionOptions().SetKeepInMemory(true)); + EvaluateExpressionOptions().SetKeepInMemory(true)); if (child_sp) child_sp->SetName(ConstString(idx_name.GetData())); return child_sp; diff --git a/lldb/source/Expression/ClangFunction.cpp b/lldb/source/Expression/ClangFunction.cpp index 62e4e8a89035..1909dc2c8485 100644 --- a/lldb/source/Expression/ClangFunction.cpp +++ b/lldb/source/Expression/ClangFunction.cpp @@ -485,13 +485,13 @@ ExecutionResults ClangFunction::ExecuteFunction( ExecutionContext &exe_ctx, Stream &errors, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, bool try_all_threads, Value &results) { const bool stop_others = true; const bool discard_on_error = true; - return ExecuteFunction (exe_ctx, NULL, errors, stop_others, single_thread_timeout_usec, + return ExecuteFunction (exe_ctx, NULL, errors, stop_others, timeout_usec, try_all_threads, discard_on_error, results); } @@ -504,7 +504,7 @@ ClangFunction::ExecuteFunction ( bool stop_others, bool try_all_threads, bool discard_on_error, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, Stream &errors, lldb::addr_t *this_arg) { @@ -529,7 +529,7 @@ ClangFunction::ExecuteFunction ( stop_others, try_all_threads, discard_on_error, - single_thread_timeout_usec, + timeout_usec, errors); if (exe_ctx.GetProcessPtr()) @@ -544,7 +544,7 @@ ClangFunction::ExecuteFunction( lldb::addr_t *args_addr_ptr, Stream &errors, bool stop_others, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, bool try_all_threads, bool discard_on_error, Value &results) @@ -574,7 +574,7 @@ ClangFunction::ExecuteFunction( stop_others, try_all_threads, discard_on_error, - single_thread_timeout_usec, + timeout_usec, errors); if (args_addr_ptr != NULL) diff --git a/lldb/source/Expression/ClangUserExpression.cpp b/lldb/source/Expression/ClangUserExpression.cpp index c037d0238f92..450728272e64 100644 --- a/lldb/source/Expression/ClangUserExpression.cpp +++ b/lldb/source/Expression/ClangUserExpression.cpp @@ -544,7 +544,8 @@ ClangUserExpression::Execute (Stream &error_stream, bool discard_on_error, ClangUserExpression::ClangUserExpressionSP &shared_ptr_to_me, lldb::ClangExpressionVariableSP &result, - uint32_t single_thread_timeout_usec) + bool run_others, + uint32_t timeout_usec) { // The expression log is quite verbose, and if you're just tracking the execution of the // expression, it's quite convenient to have these logs come out with the STEP log as well. @@ -594,7 +595,7 @@ ClangUserExpression::Execute (Stream &error_stream, stop_others, try_all_threads, discard_on_error, - single_thread_timeout_usec, + timeout_usec, error_stream); if (exe_ctx.GetProcessPtr()) @@ -655,10 +656,21 @@ ClangUserExpression::Evaluate (ExecutionContext &exe_ctx, const char *expr_cstr, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, - uint32_t single_thread_timeout_usec) + bool run_others, + uint32_t timeout_usec) { Error error; - return EvaluateWithError (exe_ctx, execution_policy, language, desired_type, discard_on_error, expr_cstr, expr_prefix, result_valobj_sp, error, single_thread_timeout_usec); + return EvaluateWithError (exe_ctx, + execution_policy, + language, + desired_type, + discard_on_error, + expr_cstr, + expr_prefix, + result_valobj_sp, + error, + run_others, + timeout_usec); } ExecutionResults @@ -671,7 +683,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx, const char *expr_prefix, lldb::ValueObjectSP &result_valobj_sp, Error &error, - uint32_t single_thread_timeout_usec) + bool run_others, + uint32_t timeout_usec) { lldb::LogSP log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_EXPRESSIONS | LIBLLDB_LOG_STEP)); @@ -747,7 +760,8 @@ ClangUserExpression::EvaluateWithError (ExecutionContext &exe_ctx, discard_on_error, user_expression_sp, expr_result, - single_thread_timeout_usec); + run_others, + timeout_usec); if (execution_results != eExecutionCompleted) { diff --git a/lldb/source/Interpreter/CommandInterpreter.cpp b/lldb/source/Interpreter/CommandInterpreter.cpp index 453004d860e0..461f82167fe2 100644 --- a/lldb/source/Interpreter/CommandInterpreter.cpp +++ b/lldb/source/Interpreter/CommandInterpreter.cpp @@ -1308,11 +1308,12 @@ CommandInterpreter::PreprocessCommand (std::string &command) { ValueObjectSP expr_result_valobj_sp; - Target::EvaluateExpressionOptions options; + EvaluateExpressionOptions options; options.SetCoerceToId(false) .SetUnwindOnError(true) .SetKeepInMemory(false) - .SetSingleThreadTimeoutUsec(0); + .SetRunOthers(true) + .SetTimeoutUsec(0); ExecutionResults expr_result = target->EvaluateExpression (expr_str.c_str(), exe_ctx.GetFramePtr(), diff --git a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp index 4d634f421e76..040058b952ff 100644 --- a/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp +++ b/lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp @@ -50,7 +50,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, const bool stop_other_threads = true; const bool discard_on_error = true; const bool try_all_threads = true; - const uint32_t single_thread_timeout_usec = 500000; + const uint32_t timeout_usec = 500000; addr_t prot_arg, flags_arg = 0; if (prot == eMmapProtNone) @@ -105,7 +105,7 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr, stop_other_threads, try_all_threads, discard_on_error, - single_thread_timeout_usec, + timeout_usec, error_strm); if (result == eExecutionCompleted) { @@ -154,7 +154,7 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, const bool stop_other_threads = true; const bool discard_on_error = true; const bool try_all_threads = true; - const uint32_t single_thread_timeout_usec = 500000; + const uint32_t timeout_usec = 500000; AddressRange munmap_range; if (sc.GetAddressRange(range_scope, 0, use_inline_block_range, munmap_range)) @@ -183,7 +183,7 @@ bool lldb_private::InferiorCallMunmap(Process *process, addr_t addr, stop_other_threads, try_all_threads, discard_on_error, - single_thread_timeout_usec, + timeout_usec, error_strm); if (result == eExecutionCompleted) { diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 3b37796f8d1a..e77a898e6144 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -4133,9 +4133,9 @@ ExecutionResults Process::RunThreadPlan (ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, bool stop_others, - bool try_all_threads, + bool run_others, bool discard_on_error, - uint32_t single_thread_timeout_usec, + uint32_t timeout_usec, Stream &errors) { ExecutionResults return_value = eExecutionSetupError; @@ -4260,6 +4260,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, bool first_timeout = true; bool do_resume = true; + const uint64_t default_one_thread_timeout_usec = 250000; + uint64_t computed_timeout = 0; while (1) { @@ -4298,9 +4300,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, if (stop_state != eStateRunning) { if (log) - log->Printf("Process::RunThreadPlan(): didn't get running event after initial resume, got %s instead.", StateAsCString(stop_state)); + log->Printf("Process::RunThreadPlan(): didn't get running event after " + "initial resume, got %s instead.", + StateAsCString(stop_state)); - errors.Printf("Didn't get running event after initial resume, got %s instead.", StateAsCString(stop_state)); + errors.Printf("Didn't get running event after initial resume, got %s instead.", + StateAsCString(stop_state)); return_value = eExecutionSetupError; break; } @@ -4313,28 +4318,45 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, // We set the timeout AFTER the resume, since the resume takes some time and we // don't want to charge that to the timeout. - if (single_thread_timeout_usec != 0) + if (first_timeout) + { + if (run_others) + { + // If we are running all threads then we take half the time to run all threads, bounded by + // .25 sec. + if (timeout_usec == 0) + computed_timeout = default_one_thread_timeout_usec; + else + { + computed_timeout = timeout_usec / 2; + if (computed_timeout > default_one_thread_timeout_usec) + { + computed_timeout = default_one_thread_timeout_usec; + } + timeout_usec -= computed_timeout; + } + } + else + { + computed_timeout = timeout_usec; + } + } + else + { + computed_timeout = timeout_usec; + } + + if (computed_timeout != 0) { // we have a > 0 timeout, let us set it so that we stop after the deadline real_timeout = TimeValue::Now(); - real_timeout.OffsetWithMicroSeconds(single_thread_timeout_usec); + real_timeout.OffsetWithMicroSeconds(computed_timeout); timeout_ptr = &real_timeout; } - else if (first_timeout) - { - // if we are willing to wait "forever" we still need to have an initial timeout - // this timeout is going to induce all threads to run when hit. we do this so that - // we can avoid ending locked up because of multithreaded contention issues - real_timeout = TimeValue::Now(); - real_timeout.OffsetWithNanoSeconds(500000000UL); - timeout_ptr = &real_timeout; - } else { - timeout_ptr = NULL; // if we are in a no-timeout scenario, then we only need a fake timeout the first time through - // at this point in the code, all threads will be running so we are willing to wait forever, and do not - // need a timeout + timeout_ptr = NULL; } } else @@ -4471,21 +4493,21 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, // Not really sure what to do if Halt fails here... if (log) { - if (try_all_threads) + if (run_others) { if (first_timeout) - log->Printf ("Process::RunThreadPlan(): Running function with timeout: %d timed out, " - "trying with all threads enabled.", - single_thread_timeout_usec); + log->Printf ("Process::RunThreadPlan(): Running function with timeout: %lld timed out, " + "trying for %d usec with all threads enabled.", + computed_timeout, timeout_usec); else log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled " - "and timeout: %d timed out.", - single_thread_timeout_usec); + "and timeout: %d timed out, abandoning execution.", + timeout_usec); } else log->Printf ("Process::RunThreadPlan(): Running function with timeout: %d timed out, " - "halt and abandoning execution.", - single_thread_timeout_usec); + "abandoning execution.", + timeout_usec); } Error halt_error = Halt(); @@ -4526,7 +4548,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx, break; } - if (!try_all_threads) + if (!run_others) { if (log) log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting."); diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index 8a896875498b..0dd34631da70 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -1747,7 +1747,8 @@ Target::EvaluateExpression expr_cstr, prefix, result_valobj_sp, - options.GetSingleThreadTimeoutUsec()); + options.GetRunOthers(), + options.GetTimeoutUsec()); } } diff --git a/lldb/test/expression_command/timeout/Makefile b/lldb/test/expression_command/timeout/Makefile new file mode 100644 index 000000000000..1cd67828bd7a --- /dev/null +++ b/lldb/test/expression_command/timeout/Makefile @@ -0,0 +1,5 @@ +LEVEL = ../../make + +C_SOURCES := wait-a-while.c + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/expression_command/timeout/TestCallWithTimeout.py b/lldb/test/expression_command/timeout/TestCallWithTimeout.py new file mode 100644 index 000000000000..fb9b7d04002e --- /dev/null +++ b/lldb/test/expression_command/timeout/TestCallWithTimeout.py @@ -0,0 +1,94 @@ +""" +Test calling a function that waits a while, and make sure the timeout option to expr works. +""" + +import unittest2 +import lldb +import lldbutil +from lldbtest import * + +class ExprCommandWithTimeoutsTestCase(TestBase): + + mydir = os.path.join("expression_command", "timeout") + + def setUp(self): + # Call super's setUp(). + TestBase.setUp(self) + + self.main_source = "wait-a-while.c" + self.main_source_spec = lldb.SBFileSpec (self.main_source) + + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym(self): + """Test calling std::String member function.""" + self.buildDsym() + self.call_function() + + @dwarf_test + def test_with_dwarf(self): + """Test calling std::String member function.""" + self.buildDsym() + self.call_function() + + def call_function(self): + """Test calling function with timeout.""" + exe_name = "a.out" + exe = os.path.join(os.getcwd(), exe_name) + + target = self.dbg.CreateTarget(exe) + self.assertTrue(target, VALID_TARGET) + + breakpoint = target.BreakpointCreateBySourceRegex('stop here in main.',self.main_source_spec) + self.assertTrue(breakpoint, VALID_BREAKPOINT) + self.runCmd("breakpoint list") + + # Launch the process, and do not stop at the entry point. + process = target.LaunchSimple(None, None, os.getcwd()) + + self.assertTrue(process, PROCESS_IS_VALID) + + # Frame #0 should be on self.step_out_of_malloc. + threads = lldbutil.get_threads_stopped_at_breakpoint (process, breakpoint) + + self.assertTrue(len(threads) == 1) + thread = threads[0] + + # First set the timeout too short, and make sure we fail. + options = lldb.SBExpressionOptions() + options.SetTimeoutUsec(100) + options.SetUnwindOnError(True) + + frame = thread.GetFrameAtIndex(0) + + value = frame.EvaluateExpression ("wait_a_while (10000)", options) + self.assertTrue (value.IsValid()) + self.assertTrue (value.GetError().Success() == False) + + # Now do the same thing with the command line command, and make sure it works too. + interp = self.dbg.GetCommandInterpreter() + + result = lldb.SBCommandReturnObject() + return_value = interp.HandleCommand ("expr -t 100 -u true -- wait_a_while(10000)", result) + self.assertTrue (return_value == lldb.eReturnStatusFailed) + + # Okay, now do it again with long enough time outs: + + options.SetTimeoutUsec(1000000) + value = frame.EvaluateExpression ("wait_a_while (1000)", options) + self.assertTrue(value.IsValid()) + self.assertTrue (value.GetError().Success() == True) + + # Now do the same thingwith the command line command, and make sure it works too. + interp = self.dbg.GetCommandInterpreter() + + result = lldb.SBCommandReturnObject() + return_value = interp.HandleCommand ("expr -t 1000000 -u true -- wait_a_while(1000)", result) + self.assertTrue(return_value == lldb.eReturnStatusSuccessFinishResult) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/expression_command/timeout/wait-a-while.c b/lldb/test/expression_command/timeout/wait-a-while.c new file mode 100644 index 000000000000..f3475fc3ff2d --- /dev/null +++ b/lldb/test/expression_command/timeout/wait-a-while.c @@ -0,0 +1,41 @@ +#include +#include +#include +#include + +int +wait_a_while (useconds_t interval) +{ + int num_times = 0; + int return_value = 1; + + struct timeval start_time; + gettimeofday(&start_time, NULL); + uint64_t target = start_time.tv_sec * 1000000 + start_time.tv_usec + interval; + + while (1) + { + num_times++; + return_value = usleep (interval); + if (return_value != 0) + { + struct timeval now; + gettimeofday(&now, NULL); + interval = target - now.tv_sec * 1000000 + now.tv_usec; + } + else + break; + } + return num_times; +} + +int +main (int argc, char **argv) +{ + printf ("stop here in main.\n"); + int num_times = wait_a_while (argc * 1000); + printf ("Done, took %d times.\n", num_times); + + return 0; + +}