Add the ability to set timeout & "run all threads" options both from the "expr" command and from

the SB API's that evaluate expressions.

<rdar://problem/12457211>

llvm-svn: 166062
This commit is contained in:
Jim Ingham 2012-10-16 21:41:58 +00:00
parent 02a1141e5a
commit 35e1bda695
32 changed files with 844 additions and 194 deletions

View File

@ -41,6 +41,7 @@ class SBDeclaration;
class SBError;
class SBEvent;
class SBEventList;
class SBExpressionOptions;
class SBFileSpec;
class SBFileSpecList;
class SBFrame;

View File

@ -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 <memory>
#include <vector>
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<lldb_private::EvaluateExpressionOptions> m_opaque_ap;
};
} // namespace lldb
#endif // LLDB_SBExpressionOptions_h_

View File

@ -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

View File

@ -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,

View File

@ -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);

View File

@ -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:

View File

@ -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 *

View File

@ -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,

View File

@ -98,6 +98,7 @@ class DynamicLibrary;
class DynamicLoader;
class EmulateInstruction;
class Error;
class EvaluateExpressionOptions;
class Event;
class EventData;
class ExecutionContext;

View File

@ -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 = "<group>"; };
4CD0BD0C134BFAB600CB44D4 /* ValueObjectDynamicValue.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ValueObjectDynamicValue.h; path = include/lldb/Core/ValueObjectDynamicValue.h; sourceTree = "<group>"; };
4CD0BD0E134BFADF00CB44D4 /* ValueObjectDynamicValue.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = ValueObjectDynamicValue.cpp; path = source/Core/ValueObjectDynamicValue.cpp; sourceTree = "<group>"; };
4CE4F672162C971A00F75CB3 /* SBExpressionOptions.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBExpressionOptions.h; path = include/lldb/API/SBExpressionOptions.h; sourceTree = "<group>"; };
4CE4F674162C973F00F75CB3 /* SBExpressionOptions.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBExpressionOptions.cpp; path = source/API/SBExpressionOptions.cpp; sourceTree = "<group>"; };
4CE4F676162CE1E100F75CB3 /* SBExpressionOptions.i */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.c.preprocessed; path = SBExpressionOptions.i; sourceTree = "<group>"; };
4CEDAED311754F5E00E875A6 /* ThreadPlanStepUntil.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = ThreadPlanStepUntil.h; path = include/lldb/Target/ThreadPlanStepUntil.h; sourceTree = "<group>"; };
4CF52AF41428291E0051E832 /* SBFileSpecList.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = SBFileSpecList.h; path = include/lldb/API/SBFileSpecList.h; sourceTree = "<group>"; };
4CF52AF7142829390051E832 /* SBFileSpecList.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = SBFileSpecList.cpp; path = source/API/SBFileSpecList.cpp; sourceTree = "<group>"; };
@ -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;
};

View File

@ -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"\

View File

@ -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<lldb_private::EvaluateExpressionOptions> m_opaque_ap;
};
} // namespace lldb

View File

@ -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

View File

@ -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);

View File

@ -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"

View File

@ -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());
}

View File

@ -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);

View File

@ -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));
}

View File

@ -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(),

View File

@ -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);

View File

@ -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);

View File

@ -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,

View File

@ -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;

View File

@ -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)

View File

@ -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)
{

View File

@ -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(),

View File

@ -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)
{

View File

@ -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.");

View File

@ -1747,7 +1747,8 @@ Target::EvaluateExpression
expr_cstr,
prefix,
result_valobj_sp,
options.GetSingleThreadTimeoutUsec());
options.GetRunOthers(),
options.GetTimeoutUsec());
}
}

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
C_SOURCES := wait-a-while.c
include $(LEVEL)/Makefile.rules

View File

@ -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()

View File

@ -0,0 +1,41 @@
#include <stdio.h>
#include <unistd.h>
#include <sys/time.h>
#include <stdint.h>
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;
}