diff options
author | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
---|---|---|
committer | Kate Stone <katherine.stone@apple.com> | 2016-09-06 20:57:50 +0000 |
commit | b9c1b51e45b845debb76d8658edabca70ca56079 (patch) | |
tree | dfcb5a13ef2b014202340f47036da383eaee74aa /lldb/source/Target | |
parent | d5aa73376966339caad04013510626ec2e42c760 (diff) | |
download | bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.tar.gz bcm5719-llvm-b9c1b51e45b845debb76d8658edabca70ca56079.zip |
*** This commit represents a complete reformatting of the LLDB source code
*** to conform to clang-format’s LLVM style. This kind of mass change has
*** two obvious implications:
Firstly, merging this particular commit into a downstream fork may be a huge
effort. Alternatively, it may be worth merging all changes up to this commit,
performing the same reformatting operation locally, and then discarding the
merge for this particular commit. The commands used to accomplish this
reformatting were as follows (with current working directory as the root of
the repository):
find . \( -iname "*.c" -or -iname "*.cpp" -or -iname "*.h" -or -iname "*.mm" \) -exec clang-format -i {} +
find . -iname "*.py" -exec autopep8 --in-place --aggressive --aggressive {} + ;
The version of clang-format used was 3.9.0, and autopep8 was 1.2.4.
Secondly, “blame” style tools will generally point to this commit instead of
a meaningful prior commit. There are alternatives available that will attempt
to look through this change and find the appropriate prior commit. YMMV.
llvm-svn: 280751
Diffstat (limited to 'lldb/source/Target')
57 files changed, 24764 insertions, 28779 deletions
diff --git a/lldb/source/Target/ABI.cpp b/lldb/source/Target/ABI.cpp index f5fd594877f..de4f685eb1c 100644 --- a/lldb/source/Target/ABI.cpp +++ b/lldb/source/Target/ABI.cpp @@ -12,10 +12,10 @@ // Other libraries and framework includes // Project includes #include "lldb/Target/ABI.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/Value.h" #include "lldb/Core/ValueObjectConstResult.h" -#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Symbol/CompilerType.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/Target.h" @@ -25,207 +25,193 @@ using namespace lldb; using namespace lldb_private; ABISP -ABI::FindPlugin (const ArchSpec &arch) -{ - ABISP abi_sp; - ABICreateInstance create_callback; - - for (uint32_t idx = 0; - (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) != nullptr; - ++idx) - { - abi_sp = create_callback(arch); - - if (abi_sp) - return abi_sp; - } - abi_sp.reset(); - return abi_sp; +ABI::FindPlugin(const ArchSpec &arch) { + ABISP abi_sp; + ABICreateInstance create_callback; + + for (uint32_t idx = 0; + (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) != + nullptr; + ++idx) { + abi_sp = create_callback(arch); + + if (abi_sp) + return abi_sp; + } + abi_sp.reset(); + return abi_sp; } ABI::ABI() = default; ABI::~ABI() = default; -bool -ABI::GetRegisterInfoByName (const ConstString &name, RegisterInfo &info) -{ - uint32_t count = 0; - const RegisterInfo *register_info_array = GetRegisterInfoArray (count); - if (register_info_array) - { - const char *unique_name_cstr = name.GetCString(); - uint32_t i; - for (i = 0; i < count; ++i) - { - if (register_info_array[i].name == unique_name_cstr) - { - info = register_info_array[i]; - return true; - } - } - for (i = 0; i < count; ++i) - { - if (register_info_array[i].alt_name == unique_name_cstr) - { - info = register_info_array[i]; - return true; - } - } +bool ABI::GetRegisterInfoByName(const ConstString &name, RegisterInfo &info) { + uint32_t count = 0; + const RegisterInfo *register_info_array = GetRegisterInfoArray(count); + if (register_info_array) { + const char *unique_name_cstr = name.GetCString(); + uint32_t i; + for (i = 0; i < count; ++i) { + if (register_info_array[i].name == unique_name_cstr) { + info = register_info_array[i]; + return true; + } } - return false; + for (i = 0; i < count; ++i) { + if (register_info_array[i].alt_name == unique_name_cstr) { + info = register_info_array[i]; + return true; + } + } + } + return false; } -bool -ABI::GetRegisterInfoByKind (RegisterKind reg_kind, uint32_t reg_num, RegisterInfo &info) -{ - if (reg_kind < eRegisterKindEHFrame || reg_kind >= kNumRegisterKinds) - return false; - - uint32_t count = 0; - const RegisterInfo *register_info_array = GetRegisterInfoArray (count); - if (register_info_array) - { - for (uint32_t i = 0; i < count; ++i) - { - if (register_info_array[i].kinds[reg_kind] == reg_num) - { - info = register_info_array[i]; - return true; - } - } - } +bool ABI::GetRegisterInfoByKind(RegisterKind reg_kind, uint32_t reg_num, + RegisterInfo &info) { + if (reg_kind < eRegisterKindEHFrame || reg_kind >= kNumRegisterKinds) return false; -} -ValueObjectSP -ABI::GetReturnValueObject (Thread &thread, - CompilerType &ast_type, - bool persistent) const -{ - if (!ast_type.IsValid()) - return ValueObjectSP(); - - ValueObjectSP return_valobj_sp; - - return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type); - if (!return_valobj_sp) - return return_valobj_sp; - - // Now turn this into a persistent variable. - // FIXME: This code is duplicated from Target::EvaluateExpression, and it is used in similar form in a couple - // of other places. Figure out the correct Create function to do all this work. - - if (persistent) - { - PersistentExpressionState *persistent_expression_state = thread.CalculateTarget()->GetPersistentExpressionStateForLanguage(ast_type.GetMinimumLanguage()); - - if (!persistent_expression_state) - return ValueObjectSP(); - - ConstString persistent_variable_name (persistent_expression_state->GetNextPersistentVariableName()); - - lldb::ValueObjectSP const_valobj_sp; - - // Check in case our value is already a constant value - if (return_valobj_sp->GetIsConstant()) - { - const_valobj_sp = return_valobj_sp; - const_valobj_sp->SetName (persistent_variable_name); - } - else - const_valobj_sp = return_valobj_sp->CreateConstantValue (persistent_variable_name); - - lldb::ValueObjectSP live_valobj_sp = return_valobj_sp; - - return_valobj_sp = const_valobj_sp; - - ExpressionVariableSP clang_expr_variable_sp(persistent_expression_state->CreatePersistentVariable(return_valobj_sp)); - - assert (clang_expr_variable_sp); - - // Set flags and live data as appropriate - - const Value &result_value = live_valobj_sp->GetValue(); - - switch (result_value.GetValueType()) - { - case Value::eValueTypeHostAddress: - case Value::eValueTypeFileAddress: - // we don't do anything with these for now - break; - case Value::eValueTypeScalar: - case Value::eValueTypeVector: - clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsFreezeDried; - clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsLLDBAllocated; - clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVNeedsAllocation; - break; - case Value::eValueTypeLoadAddress: - clang_expr_variable_sp->m_live_sp = live_valobj_sp; - clang_expr_variable_sp->m_flags |= ClangExpressionVariable::EVIsProgramReference; - break; - } - - return_valobj_sp = clang_expr_variable_sp->GetValueObject(); + uint32_t count = 0; + const RegisterInfo *register_info_array = GetRegisterInfoArray(count); + if (register_info_array) { + for (uint32_t i = 0; i < count; ++i) { + if (register_info_array[i].kinds[reg_kind] == reg_num) { + info = register_info_array[i]; + return true; + } } - return return_valobj_sp; + } + return false; } -ValueObjectSP -ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type, bool persistent) const -{ - ValueObjectSP return_valobj_sp; - return_valobj_sp = GetReturnValueObjectImpl( thread, ast_type ); +ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type, + bool persistent) const { + if (!ast_type.IsValid()) + return ValueObjectSP(); + + ValueObjectSP return_valobj_sp; + + return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type); + if (!return_valobj_sp) return return_valobj_sp; + + // Now turn this into a persistent variable. + // FIXME: This code is duplicated from Target::EvaluateExpression, and it is + // used in similar form in a couple + // of other places. Figure out the correct Create function to do all this + // work. + + if (persistent) { + PersistentExpressionState *persistent_expression_state = + thread.CalculateTarget()->GetPersistentExpressionStateForLanguage( + ast_type.GetMinimumLanguage()); + + if (!persistent_expression_state) + return ValueObjectSP(); + + ConstString persistent_variable_name( + persistent_expression_state->GetNextPersistentVariableName()); + + lldb::ValueObjectSP const_valobj_sp; + + // Check in case our value is already a constant value + if (return_valobj_sp->GetIsConstant()) { + const_valobj_sp = return_valobj_sp; + const_valobj_sp->SetName(persistent_variable_name); + } else + const_valobj_sp = + return_valobj_sp->CreateConstantValue(persistent_variable_name); + + lldb::ValueObjectSP live_valobj_sp = return_valobj_sp; + + return_valobj_sp = const_valobj_sp; + + ExpressionVariableSP clang_expr_variable_sp( + persistent_expression_state->CreatePersistentVariable( + return_valobj_sp)); + + assert(clang_expr_variable_sp); + + // Set flags and live data as appropriate + + const Value &result_value = live_valobj_sp->GetValue(); + + switch (result_value.GetValueType()) { + case Value::eValueTypeHostAddress: + case Value::eValueTypeFileAddress: + // we don't do anything with these for now + break; + case Value::eValueTypeScalar: + case Value::eValueTypeVector: + clang_expr_variable_sp->m_flags |= + ClangExpressionVariable::EVIsFreezeDried; + clang_expr_variable_sp->m_flags |= + ClangExpressionVariable::EVIsLLDBAllocated; + clang_expr_variable_sp->m_flags |= + ClangExpressionVariable::EVNeedsAllocation; + break; + case Value::eValueTypeLoadAddress: + clang_expr_variable_sp->m_live_sp = live_valobj_sp; + clang_expr_variable_sp->m_flags |= + ClangExpressionVariable::EVIsProgramReference; + break; + } + + return_valobj_sp = clang_expr_variable_sp->GetValueObject(); + } + return return_valobj_sp; +} + +ValueObjectSP ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type, + bool persistent) const { + ValueObjectSP return_valobj_sp; + return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type); + return return_valobj_sp; } // specialized to work with llvm IR types // // for now we will specify a default implementation so that we don't need to // modify other ABIs -lldb::ValueObjectSP -ABI::GetReturnValueObjectImpl( Thread &thread, llvm::Type &ir_type ) const -{ - ValueObjectSP return_valobj_sp; +lldb::ValueObjectSP ABI::GetReturnValueObjectImpl(Thread &thread, + llvm::Type &ir_type) const { + ValueObjectSP return_valobj_sp; - /* this is a dummy and will only be called if an ABI does not override this */ + /* this is a dummy and will only be called if an ABI does not override this */ - return return_valobj_sp; + return return_valobj_sp; } -bool -ABI::PrepareTrivialCall (Thread &thread, - lldb::addr_t sp, - lldb::addr_t functionAddress, - lldb::addr_t returnAddress, - llvm::Type &returntype, - llvm::ArrayRef<ABI::CallArgument> args) const -{ - // dummy prepare trivial call - assert( !"Should never get here!" ); - return false; +bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp, + lldb::addr_t functionAddress, + lldb::addr_t returnAddress, llvm::Type &returntype, + llvm::ArrayRef<ABI::CallArgument> args) const { + // dummy prepare trivial call + assert(!"Should never get here!"); + return false; } -bool -ABI::GetFallbackRegisterLocation (const RegisterInfo *reg_info, - UnwindPlan::Row::RegisterLocation &unwind_regloc) -{ - // Did the UnwindPlan fail to give us the caller's stack pointer? - // The stack pointer is defined to be the same as THIS frame's CFA, so return the CFA value as - // the caller's stack pointer. This is true on x86-32/x86-64 at least. - if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) - { - unwind_regloc.SetIsCFAPlusOffset(0); - return true; - } - - // If a volatile register is being requested, we don't want to forward the next frame's register contents - // up the stack -- the register is not retrievable at this frame. - if (RegisterIsVolatile(reg_info)) - { - unwind_regloc.SetUndefined(); - return true; - } - - return false; +bool ABI::GetFallbackRegisterLocation( + const RegisterInfo *reg_info, + UnwindPlan::Row::RegisterLocation &unwind_regloc) { + // Did the UnwindPlan fail to give us the caller's stack pointer? + // The stack pointer is defined to be the same as THIS frame's CFA, so return + // the CFA value as + // the caller's stack pointer. This is true on x86-32/x86-64 at least. + if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) { + unwind_regloc.SetIsCFAPlusOffset(0); + return true; + } + + // If a volatile register is being requested, we don't want to forward the + // next frame's register contents + // up the stack -- the register is not retrievable at this frame. + if (RegisterIsVolatile(reg_info)) { + unwind_regloc.SetUndefined(); + return true; + } + + return false; } diff --git a/lldb/source/Target/CPPLanguageRuntime.cpp b/lldb/source/Target/CPPLanguageRuntime.cpp index 28cfab1cefd..c7e7b251197 100644 --- a/lldb/source/Target/CPPLanguageRuntime.cpp +++ b/lldb/source/Target/CPPLanguageRuntime.cpp @@ -1,4 +1,5 @@ -//===-- CPPLanguageRuntime.cpp -------------------------------------------------*- C++ -*-===// +//===-- CPPLanguageRuntime.cpp +//-------------------------------------------------*- C++ -*-===// // // The LLVM Compiler Infrastructure // @@ -23,26 +24,19 @@ using namespace lldb_private; //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -CPPLanguageRuntime::~CPPLanguageRuntime() -{ -} - -CPPLanguageRuntime::CPPLanguageRuntime (Process *process) : - LanguageRuntime (process) -{ +CPPLanguageRuntime::~CPPLanguageRuntime() {} -} +CPPLanguageRuntime::CPPLanguageRuntime(Process *process) + : LanguageRuntime(process) {} -bool -CPPLanguageRuntime::GetObjectDescription (Stream &str, ValueObject &object) -{ - // C++ has no generic way to do this. - return false; +bool CPPLanguageRuntime::GetObjectDescription(Stream &str, + ValueObject &object) { + // C++ has no generic way to do this. + return false; } -bool -CPPLanguageRuntime::GetObjectDescription (Stream &str, Value &value, ExecutionContextScope *exe_scope) -{ - // C++ has no generic way to do this. - return false; +bool CPPLanguageRuntime::GetObjectDescription( + Stream &str, Value &value, ExecutionContextScope *exe_scope) { + // C++ has no generic way to do this. + return false; } diff --git a/lldb/source/Target/ExecutionContext.cpp b/lldb/source/Target/ExecutionContext.cpp index 41f076a205e..3643c159042 100644 --- a/lldb/source/Target/ExecutionContext.cpp +++ b/lldb/source/Target/ExecutionContext.cpp @@ -14,826 +14,620 @@ #include "lldb/Target/ExecutionContext.h" #include "lldb/Core/State.h" #include "lldb/Target/ExecutionContextScope.h" -#include "lldb/Target/StackFrame.h" #include "lldb/Target/Process.h" +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" using namespace lldb_private; -ExecutionContext::ExecutionContext() : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ -} - -ExecutionContext::ExecutionContext (const ExecutionContext &rhs) : - m_target_sp(rhs.m_target_sp), - m_process_sp(rhs.m_process_sp), - m_thread_sp(rhs.m_thread_sp), - m_frame_sp(rhs.m_frame_sp) -{ -} - -ExecutionContext::ExecutionContext (const lldb::TargetSP &target_sp, bool get_process) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (target_sp) - SetContext (target_sp, get_process); -} - -ExecutionContext::ExecutionContext (const lldb::ProcessSP &process_sp) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (process_sp) - SetContext (process_sp); -} - -ExecutionContext::ExecutionContext (const lldb::ThreadSP &thread_sp) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (thread_sp) - SetContext (thread_sp); -} - -ExecutionContext::ExecutionContext (const lldb::StackFrameSP &frame_sp) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (frame_sp) - SetContext (frame_sp); -} - -ExecutionContext::ExecutionContext (const lldb::TargetWP &target_wp, bool get_process) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - lldb::TargetSP target_sp(target_wp.lock()); - if (target_sp) - SetContext (target_sp, get_process); -} - -ExecutionContext::ExecutionContext (const lldb::ProcessWP &process_wp) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - lldb::ProcessSP process_sp(process_wp.lock()); - if (process_sp) - SetContext (process_sp); -} - -ExecutionContext::ExecutionContext (const lldb::ThreadWP &thread_wp) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - lldb::ThreadSP thread_sp(thread_wp.lock()); - if (thread_sp) - SetContext (thread_sp); -} - -ExecutionContext::ExecutionContext (const lldb::StackFrameWP &frame_wp) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - lldb::StackFrameSP frame_sp(frame_wp.lock()); - if (frame_sp) - SetContext (frame_sp); -} - -ExecutionContext::ExecutionContext (Target* t, bool fill_current_process_thread_frame) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (t) - { - m_target_sp = t->shared_from_this(); - if (fill_current_process_thread_frame) - { - m_process_sp = t->GetProcessSP(); - if (m_process_sp) - { - m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread(); - if (m_thread_sp) - m_frame_sp = m_thread_sp->GetSelectedFrame(); - } - } - } +ExecutionContext::ExecutionContext() + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() {} + +ExecutionContext::ExecutionContext(const ExecutionContext &rhs) + : m_target_sp(rhs.m_target_sp), m_process_sp(rhs.m_process_sp), + m_thread_sp(rhs.m_thread_sp), m_frame_sp(rhs.m_frame_sp) {} + +ExecutionContext::ExecutionContext(const lldb::TargetSP &target_sp, + bool get_process) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (target_sp) + SetContext(target_sp, get_process); +} + +ExecutionContext::ExecutionContext(const lldb::ProcessSP &process_sp) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (process_sp) + SetContext(process_sp); +} + +ExecutionContext::ExecutionContext(const lldb::ThreadSP &thread_sp) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (thread_sp) + SetContext(thread_sp); +} + +ExecutionContext::ExecutionContext(const lldb::StackFrameSP &frame_sp) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (frame_sp) + SetContext(frame_sp); +} + +ExecutionContext::ExecutionContext(const lldb::TargetWP &target_wp, + bool get_process) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + lldb::TargetSP target_sp(target_wp.lock()); + if (target_sp) + SetContext(target_sp, get_process); +} + +ExecutionContext::ExecutionContext(const lldb::ProcessWP &process_wp) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + lldb::ProcessSP process_sp(process_wp.lock()); + if (process_sp) + SetContext(process_sp); +} + +ExecutionContext::ExecutionContext(const lldb::ThreadWP &thread_wp) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + lldb::ThreadSP thread_sp(thread_wp.lock()); + if (thread_sp) + SetContext(thread_sp); } -ExecutionContext::ExecutionContext(Process* process, Thread *thread, StackFrame *frame) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (process) - { - m_process_sp = process->shared_from_this(); - m_target_sp = process->GetTarget().shared_from_this(); +ExecutionContext::ExecutionContext(const lldb::StackFrameWP &frame_wp) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + lldb::StackFrameSP frame_sp(frame_wp.lock()); + if (frame_sp) + SetContext(frame_sp); +} + +ExecutionContext::ExecutionContext(Target *t, + bool fill_current_process_thread_frame) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (t) { + m_target_sp = t->shared_from_this(); + if (fill_current_process_thread_frame) { + m_process_sp = t->GetProcessSP(); + if (m_process_sp) { + m_thread_sp = m_process_sp->GetThreadList().GetSelectedThread(); + if (m_thread_sp) + m_frame_sp = m_thread_sp->GetSelectedFrame(); + } } - if (thread) - m_thread_sp = thread->shared_from_this(); - if (frame) - m_frame_sp = frame->shared_from_this(); -} - -ExecutionContext::ExecutionContext (const ExecutionContextRef &exe_ctx_ref) : - m_target_sp (exe_ctx_ref.GetTargetSP()), - m_process_sp (exe_ctx_ref.GetProcessSP()), - m_thread_sp (exe_ctx_ref.GetThreadSP()), - m_frame_sp (exe_ctx_ref.GetFrameSP()) -{ -} - -ExecutionContext::ExecutionContext (const ExecutionContextRef *exe_ctx_ref_ptr, bool thread_and_frame_only_if_stopped) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (exe_ctx_ref_ptr) - { - m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); - m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); - if (!thread_and_frame_only_if_stopped || (m_process_sp && StateIsStoppedState(m_process_sp->GetState(), true))) - { - m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); - m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); - } + } +} + +ExecutionContext::ExecutionContext(Process *process, Thread *thread, + StackFrame *frame) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (process) { + m_process_sp = process->shared_from_this(); + m_target_sp = process->GetTarget().shared_from_this(); + } + if (thread) + m_thread_sp = thread->shared_from_this(); + if (frame) + m_frame_sp = frame->shared_from_this(); +} + +ExecutionContext::ExecutionContext(const ExecutionContextRef &exe_ctx_ref) + : m_target_sp(exe_ctx_ref.GetTargetSP()), + m_process_sp(exe_ctx_ref.GetProcessSP()), + m_thread_sp(exe_ctx_ref.GetThreadSP()), + m_frame_sp(exe_ctx_ref.GetFrameSP()) {} + +ExecutionContext::ExecutionContext(const ExecutionContextRef *exe_ctx_ref_ptr, + bool thread_and_frame_only_if_stopped) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (exe_ctx_ref_ptr) { + m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); + m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); + if (!thread_and_frame_only_if_stopped || + (m_process_sp && StateIsStoppedState(m_process_sp->GetState(), true))) { + m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); + m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); } + } } ExecutionContext::ExecutionContext(const ExecutionContextRef *exe_ctx_ref_ptr, std::unique_lock<std::recursive_mutex> &lock) - : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() -{ - if (exe_ctx_ref_ptr) - { - m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); - if (m_target_sp) - { - lock = std::unique_lock<std::recursive_mutex>(m_target_sp->GetAPIMutex()); - - m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); - m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); - m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); - } + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (exe_ctx_ref_ptr) { + m_target_sp = exe_ctx_ref_ptr->GetTargetSP(); + if (m_target_sp) { + lock = std::unique_lock<std::recursive_mutex>(m_target_sp->GetAPIMutex()); + + m_process_sp = exe_ctx_ref_ptr->GetProcessSP(); + m_thread_sp = exe_ctx_ref_ptr->GetThreadSP(); + m_frame_sp = exe_ctx_ref_ptr->GetFrameSP(); } + } } -ExecutionContext::ExecutionContext(const ExecutionContextRef &exe_ctx_ref, std::unique_lock<std::recursive_mutex> &lock) - : m_target_sp(exe_ctx_ref.GetTargetSP()), m_process_sp(), m_thread_sp(), m_frame_sp() -{ - if (m_target_sp) - { - lock = std::unique_lock<std::recursive_mutex>(m_target_sp->GetAPIMutex()); +ExecutionContext::ExecutionContext(const ExecutionContextRef &exe_ctx_ref, + std::unique_lock<std::recursive_mutex> &lock) + : m_target_sp(exe_ctx_ref.GetTargetSP()), m_process_sp(), m_thread_sp(), + m_frame_sp() { + if (m_target_sp) { + lock = std::unique_lock<std::recursive_mutex>(m_target_sp->GetAPIMutex()); - m_process_sp = exe_ctx_ref.GetProcessSP(); - m_thread_sp = exe_ctx_ref.GetThreadSP(); - m_frame_sp = exe_ctx_ref.GetFrameSP(); - } + m_process_sp = exe_ctx_ref.GetProcessSP(); + m_thread_sp = exe_ctx_ref.GetThreadSP(); + m_frame_sp = exe_ctx_ref.GetFrameSP(); + } } -ExecutionContext::ExecutionContext (ExecutionContextScope *exe_scope_ptr) : - m_target_sp (), - m_process_sp (), - m_thread_sp (), - m_frame_sp () -{ - if (exe_scope_ptr) - exe_scope_ptr->CalculateExecutionContext (*this); +ExecutionContext::ExecutionContext(ExecutionContextScope *exe_scope_ptr) + : m_target_sp(), m_process_sp(), m_thread_sp(), m_frame_sp() { + if (exe_scope_ptr) + exe_scope_ptr->CalculateExecutionContext(*this); } -ExecutionContext::ExecutionContext (ExecutionContextScope &exe_scope_ref) -{ - exe_scope_ref.CalculateExecutionContext (*this); +ExecutionContext::ExecutionContext(ExecutionContextScope &exe_scope_ref) { + exe_scope_ref.CalculateExecutionContext(*this); } -void -ExecutionContext::Clear() -{ - m_target_sp.reset(); - m_process_sp.reset(); - m_thread_sp.reset(); - m_frame_sp.reset(); +void ExecutionContext::Clear() { + m_target_sp.reset(); + m_process_sp.reset(); + m_thread_sp.reset(); + m_frame_sp.reset(); } ExecutionContext::~ExecutionContext() = default; -uint32_t -ExecutionContext::GetAddressByteSize() const -{ - if (m_target_sp && m_target_sp->GetArchitecture().IsValid()) - return m_target_sp->GetArchitecture().GetAddressByteSize(); - if (m_process_sp) - return m_process_sp->GetAddressByteSize(); - return sizeof(void *); +uint32_t ExecutionContext::GetAddressByteSize() const { + if (m_target_sp && m_target_sp->GetArchitecture().IsValid()) + return m_target_sp->GetArchitecture().GetAddressByteSize(); + if (m_process_sp) + return m_process_sp->GetAddressByteSize(); + return sizeof(void *); } -lldb::ByteOrder -ExecutionContext::GetByteOrder() const -{ - if (m_target_sp && m_target_sp->GetArchitecture().IsValid()) - m_target_sp->GetArchitecture().GetByteOrder(); - if (m_process_sp) - m_process_sp->GetByteOrder(); - return endian::InlHostByteOrder(); +lldb::ByteOrder ExecutionContext::GetByteOrder() const { + if (m_target_sp && m_target_sp->GetArchitecture().IsValid()) + m_target_sp->GetArchitecture().GetByteOrder(); + if (m_process_sp) + m_process_sp->GetByteOrder(); + return endian::InlHostByteOrder(); } -RegisterContext * -ExecutionContext::GetRegisterContext () const -{ - if (m_frame_sp) - return m_frame_sp->GetRegisterContext().get(); - else if (m_thread_sp) - return m_thread_sp->GetRegisterContext().get(); - return nullptr; +RegisterContext *ExecutionContext::GetRegisterContext() const { + if (m_frame_sp) + return m_frame_sp->GetRegisterContext().get(); + else if (m_thread_sp) + return m_thread_sp->GetRegisterContext().get(); + return nullptr; } -Target * -ExecutionContext::GetTargetPtr () const -{ - if (m_target_sp) - return m_target_sp.get(); - if (m_process_sp) - return &m_process_sp->GetTarget(); - return nullptr; +Target *ExecutionContext::GetTargetPtr() const { + if (m_target_sp) + return m_target_sp.get(); + if (m_process_sp) + return &m_process_sp->GetTarget(); + return nullptr; } -Process * -ExecutionContext::GetProcessPtr () const -{ - if (m_process_sp) - return m_process_sp.get(); - if (m_target_sp) - return m_target_sp->GetProcessSP().get(); - return nullptr; -} - -ExecutionContextScope * -ExecutionContext::GetBestExecutionContextScope () const -{ - if (m_frame_sp) - return m_frame_sp.get(); - if (m_thread_sp) - return m_thread_sp.get(); - if (m_process_sp) - return m_process_sp.get(); - return m_target_sp.get(); +Process *ExecutionContext::GetProcessPtr() const { + if (m_process_sp) + return m_process_sp.get(); + if (m_target_sp) + return m_target_sp->GetProcessSP().get(); + return nullptr; } -Target & -ExecutionContext::GetTargetRef () const -{ -#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) - assert (m_target_sp); -#endif - return *m_target_sp; +ExecutionContextScope *ExecutionContext::GetBestExecutionContextScope() const { + if (m_frame_sp) + return m_frame_sp.get(); + if (m_thread_sp) + return m_thread_sp.get(); + if (m_process_sp) + return m_process_sp.get(); + return m_target_sp.get(); } -Process & -ExecutionContext::GetProcessRef () const -{ -#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) - assert (m_process_sp); +Target &ExecutionContext::GetTargetRef() const { +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) + assert(m_target_sp); #endif - return *m_process_sp; + return *m_target_sp; } -Thread & -ExecutionContext::GetThreadRef () const -{ -#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) - assert (m_thread_sp); +Process &ExecutionContext::GetProcessRef() const { +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) + assert(m_process_sp); #endif - return *m_thread_sp; + return *m_process_sp; } -StackFrame & -ExecutionContext::GetFrameRef () const -{ -#if defined (LLDB_CONFIGURATION_DEBUG) || defined (LLDB_CONFIGURATION_RELEASE) - assert (m_frame_sp); +Thread &ExecutionContext::GetThreadRef() const { +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) + assert(m_thread_sp); #endif - return *m_frame_sp; + return *m_thread_sp; } -void -ExecutionContext::SetTargetSP (const lldb::TargetSP &target_sp) -{ - m_target_sp = target_sp; +StackFrame &ExecutionContext::GetFrameRef() const { +#if defined(LLDB_CONFIGURATION_DEBUG) || defined(LLDB_CONFIGURATION_RELEASE) + assert(m_frame_sp); +#endif + return *m_frame_sp; } -void -ExecutionContext::SetProcessSP (const lldb::ProcessSP &process_sp) -{ - m_process_sp = process_sp; +void ExecutionContext::SetTargetSP(const lldb::TargetSP &target_sp) { + m_target_sp = target_sp; } -void -ExecutionContext::SetThreadSP (const lldb::ThreadSP &thread_sp) -{ - m_thread_sp = thread_sp; +void ExecutionContext::SetProcessSP(const lldb::ProcessSP &process_sp) { + m_process_sp = process_sp; } -void -ExecutionContext::SetFrameSP (const lldb::StackFrameSP &frame_sp) -{ - m_frame_sp = frame_sp; +void ExecutionContext::SetThreadSP(const lldb::ThreadSP &thread_sp) { + m_thread_sp = thread_sp; } -void -ExecutionContext::SetTargetPtr (Target* target) -{ - if (target) - m_target_sp = target->shared_from_this(); - else - m_target_sp.reset(); +void ExecutionContext::SetFrameSP(const lldb::StackFrameSP &frame_sp) { + m_frame_sp = frame_sp; } -void -ExecutionContext::SetProcessPtr (Process *process) -{ - if (process) - m_process_sp = process->shared_from_this(); - else - m_process_sp.reset(); +void ExecutionContext::SetTargetPtr(Target *target) { + if (target) + m_target_sp = target->shared_from_this(); + else + m_target_sp.reset(); } -void -ExecutionContext::SetThreadPtr (Thread *thread) -{ - if (thread) - m_thread_sp = thread->shared_from_this(); - else - m_thread_sp.reset(); +void ExecutionContext::SetProcessPtr(Process *process) { + if (process) + m_process_sp = process->shared_from_this(); + else + m_process_sp.reset(); } -void -ExecutionContext::SetFramePtr (StackFrame *frame) -{ - if (frame) - m_frame_sp = frame->shared_from_this(); - else - m_frame_sp.reset(); +void ExecutionContext::SetThreadPtr(Thread *thread) { + if (thread) + m_thread_sp = thread->shared_from_this(); + else + m_thread_sp.reset(); } -void -ExecutionContext::SetContext (const lldb::TargetSP &target_sp, bool get_process) -{ - m_target_sp = target_sp; - if (get_process && target_sp) - m_process_sp = target_sp->GetProcessSP(); - else - m_process_sp.reset(); - m_thread_sp.reset(); +void ExecutionContext::SetFramePtr(StackFrame *frame) { + if (frame) + m_frame_sp = frame->shared_from_this(); + else m_frame_sp.reset(); } -void -ExecutionContext::SetContext (const lldb::ProcessSP &process_sp) -{ - m_process_sp = process_sp; - if (process_sp) - m_target_sp = process_sp->GetTarget().shared_from_this(); - else - m_target_sp.reset(); - m_thread_sp.reset(); - m_frame_sp.reset(); +void ExecutionContext::SetContext(const lldb::TargetSP &target_sp, + bool get_process) { + m_target_sp = target_sp; + if (get_process && target_sp) + m_process_sp = target_sp->GetProcessSP(); + else + m_process_sp.reset(); + m_thread_sp.reset(); + m_frame_sp.reset(); } -void -ExecutionContext::SetContext (const lldb::ThreadSP &thread_sp) -{ - m_frame_sp.reset(); - m_thread_sp = thread_sp; - if (thread_sp) - { - m_process_sp = thread_sp->GetProcess(); - if (m_process_sp) - m_target_sp = m_process_sp->GetTarget().shared_from_this(); - else - m_target_sp.reset(); - } - else - { - m_target_sp.reset(); - m_process_sp.reset(); - } +void ExecutionContext::SetContext(const lldb::ProcessSP &process_sp) { + m_process_sp = process_sp; + if (process_sp) + m_target_sp = process_sp->GetTarget().shared_from_this(); + else + m_target_sp.reset(); + m_thread_sp.reset(); + m_frame_sp.reset(); } -void -ExecutionContext::SetContext (const lldb::StackFrameSP &frame_sp) -{ - m_frame_sp = frame_sp; - if (frame_sp) - { - m_thread_sp = frame_sp->CalculateThread(); - if (m_thread_sp) - { - m_process_sp = m_thread_sp->GetProcess(); - if (m_process_sp) - m_target_sp = m_process_sp->GetTarget().shared_from_this(); - else - m_target_sp.reset(); - } - else - { - m_target_sp.reset(); - m_process_sp.reset(); - } - } +void ExecutionContext::SetContext(const lldb::ThreadSP &thread_sp) { + m_frame_sp.reset(); + m_thread_sp = thread_sp; + if (thread_sp) { + m_process_sp = thread_sp->GetProcess(); + if (m_process_sp) + m_target_sp = m_process_sp->GetTarget().shared_from_this(); else - { + m_target_sp.reset(); + } else { + m_target_sp.reset(); + m_process_sp.reset(); + } +} + +void ExecutionContext::SetContext(const lldb::StackFrameSP &frame_sp) { + m_frame_sp = frame_sp; + if (frame_sp) { + m_thread_sp = frame_sp->CalculateThread(); + if (m_thread_sp) { + m_process_sp = m_thread_sp->GetProcess(); + if (m_process_sp) + m_target_sp = m_process_sp->GetTarget().shared_from_this(); + else m_target_sp.reset(); - m_process_sp.reset(); - m_thread_sp.reset(); + } else { + m_target_sp.reset(); + m_process_sp.reset(); } + } else { + m_target_sp.reset(); + m_process_sp.reset(); + m_thread_sp.reset(); + } +} + +ExecutionContext &ExecutionContext::operator=(const ExecutionContext &rhs) { + if (this != &rhs) { + m_target_sp = rhs.m_target_sp; + m_process_sp = rhs.m_process_sp; + m_thread_sp = rhs.m_thread_sp; + m_frame_sp = rhs.m_frame_sp; + } + return *this; +} + +bool ExecutionContext::operator==(const ExecutionContext &rhs) const { + // Check that the frame shared pointers match, or both are valid and their + // stack + // IDs match since sometimes we get new objects that represent the same + // frame within a thread. + if ((m_frame_sp == rhs.m_frame_sp) || + (m_frame_sp && rhs.m_frame_sp && + m_frame_sp->GetStackID() == rhs.m_frame_sp->GetStackID())) { + // Check that the thread shared pointers match, or both are valid and + // their thread IDs match since sometimes we get new objects that + // represent the same thread within a process. + if ((m_thread_sp == rhs.m_thread_sp) || + (m_thread_sp && rhs.m_thread_sp && + m_thread_sp->GetID() == rhs.m_thread_sp->GetID())) { + // Processes and targets don't change much + return m_process_sp == rhs.m_process_sp && m_target_sp == rhs.m_target_sp; + } + } + return false; } -ExecutionContext & -ExecutionContext::operator =(const ExecutionContext &rhs) -{ - if (this != &rhs) - { - m_target_sp = rhs.m_target_sp; - m_process_sp = rhs.m_process_sp; - m_thread_sp = rhs.m_thread_sp; - m_frame_sp = rhs.m_frame_sp; - } - return *this; -} - -bool -ExecutionContext::operator ==(const ExecutionContext &rhs) const -{ - // Check that the frame shared pointers match, or both are valid and their stack - // IDs match since sometimes we get new objects that represent the same - // frame within a thread. - if ((m_frame_sp == rhs.m_frame_sp) || (m_frame_sp && rhs.m_frame_sp && m_frame_sp->GetStackID() == rhs.m_frame_sp->GetStackID())) - { - // Check that the thread shared pointers match, or both are valid and - // their thread IDs match since sometimes we get new objects that - // represent the same thread within a process. - if ((m_thread_sp == rhs.m_thread_sp) || (m_thread_sp && rhs.m_thread_sp && m_thread_sp->GetID() == rhs.m_thread_sp->GetID())) - { - // Processes and targets don't change much - return m_process_sp == rhs.m_process_sp && m_target_sp == rhs.m_target_sp; - } - } - return false; -} - -bool -ExecutionContext::operator !=(const ExecutionContext &rhs) const -{ - return !(*this == rhs); -} - -bool -ExecutionContext::HasTargetScope () const -{ - return ((bool) m_target_sp - && m_target_sp->IsValid()); -} - -bool -ExecutionContext::HasProcessScope () const -{ - return (HasTargetScope() - && ((bool) m_process_sp && m_process_sp->IsValid())); -} - -bool -ExecutionContext::HasThreadScope () const -{ - return (HasProcessScope() - && ((bool) m_thread_sp && m_thread_sp->IsValid())); -} - -bool -ExecutionContext::HasFrameScope () const -{ - return HasThreadScope() && m_frame_sp; -} - -ExecutionContextRef::ExecutionContextRef() : - m_target_wp (), - m_process_wp (), - m_thread_wp (), - m_tid(LLDB_INVALID_THREAD_ID), - m_stack_id () -{ -} - -ExecutionContextRef::ExecutionContextRef (const ExecutionContext *exe_ctx) : - m_target_wp (), - m_process_wp (), - m_thread_wp (), - m_tid(LLDB_INVALID_THREAD_ID), - m_stack_id () -{ - if (exe_ctx) - *this = *exe_ctx; -} - -ExecutionContextRef::ExecutionContextRef (const ExecutionContext &exe_ctx) : - m_target_wp (), - m_process_wp (), - m_thread_wp (), - m_tid(LLDB_INVALID_THREAD_ID), - m_stack_id () -{ - *this = exe_ctx; -} - -ExecutionContextRef::ExecutionContextRef (Target *target, bool adopt_selected) : - m_target_wp(), - m_process_wp(), - m_thread_wp(), - m_tid(LLDB_INVALID_THREAD_ID), - m_stack_id () -{ - SetTargetPtr (target, adopt_selected); -} - -ExecutionContextRef::ExecutionContextRef (const ExecutionContextRef &rhs) : - m_target_wp (rhs.m_target_wp), - m_process_wp(rhs.m_process_wp), - m_thread_wp (rhs.m_thread_wp), - m_tid (rhs.m_tid), - m_stack_id (rhs.m_stack_id) -{ -} - -ExecutionContextRef & -ExecutionContextRef::operator =(const ExecutionContextRef &rhs) -{ - if (this != &rhs) - { - m_target_wp = rhs.m_target_wp; - m_process_wp = rhs.m_process_wp; - m_thread_wp = rhs.m_thread_wp; - m_tid = rhs.m_tid; - m_stack_id = rhs.m_stack_id; - } - return *this; +bool ExecutionContext::operator!=(const ExecutionContext &rhs) const { + return !(*this == rhs); } -ExecutionContextRef & -ExecutionContextRef::operator =(const ExecutionContext &exe_ctx) -{ - m_target_wp = exe_ctx.GetTargetSP(); - m_process_wp = exe_ctx.GetProcessSP(); - lldb::ThreadSP thread_sp (exe_ctx.GetThreadSP()); - m_thread_wp = thread_sp; - if (thread_sp) - m_tid = thread_sp->GetID(); - else - m_tid = LLDB_INVALID_THREAD_ID; - lldb::StackFrameSP frame_sp (exe_ctx.GetFrameSP()); - if (frame_sp) - m_stack_id = frame_sp->GetStackID(); - else - m_stack_id.Clear(); - return *this; +bool ExecutionContext::HasTargetScope() const { + return ((bool)m_target_sp && m_target_sp->IsValid()); } -void -ExecutionContextRef::Clear() -{ - m_target_wp.reset(); - m_process_wp.reset(); - ClearThread(); - ClearFrame(); +bool ExecutionContext::HasProcessScope() const { + return (HasTargetScope() && ((bool)m_process_sp && m_process_sp->IsValid())); } -ExecutionContextRef::~ExecutionContextRef() = default; +bool ExecutionContext::HasThreadScope() const { + return (HasProcessScope() && ((bool)m_thread_sp && m_thread_sp->IsValid())); +} -void -ExecutionContextRef::SetTargetSP (const lldb::TargetSP &target_sp) -{ - m_target_wp = target_sp; +bool ExecutionContext::HasFrameScope() const { + return HasThreadScope() && m_frame_sp; } -void -ExecutionContextRef::SetProcessSP (const lldb::ProcessSP &process_sp) -{ - if (process_sp) - { - m_process_wp = process_sp; - SetTargetSP (process_sp->GetTarget().shared_from_this()); - } - else - { - m_process_wp.reset(); - m_target_wp.reset(); - } +ExecutionContextRef::ExecutionContextRef() + : m_target_wp(), m_process_wp(), m_thread_wp(), + m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() {} + +ExecutionContextRef::ExecutionContextRef(const ExecutionContext *exe_ctx) + : m_target_wp(), m_process_wp(), m_thread_wp(), + m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() { + if (exe_ctx) + *this = *exe_ctx; } -void -ExecutionContextRef::SetThreadSP (const lldb::ThreadSP &thread_sp) -{ - if (thread_sp) - { - m_thread_wp = thread_sp; - m_tid = thread_sp->GetID(); - SetProcessSP (thread_sp->GetProcess()); - } - else - { - ClearThread(); - m_process_wp.reset(); - m_target_wp.reset(); - } +ExecutionContextRef::ExecutionContextRef(const ExecutionContext &exe_ctx) + : m_target_wp(), m_process_wp(), m_thread_wp(), + m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() { + *this = exe_ctx; } -void -ExecutionContextRef::SetFrameSP (const lldb::StackFrameSP &frame_sp) -{ - if (frame_sp) - { - m_stack_id = frame_sp->GetStackID(); - SetThreadSP (frame_sp->GetThread()); - } - else - { - ClearFrame(); - ClearThread(); - m_process_wp.reset(); - m_target_wp.reset(); - } +ExecutionContextRef::ExecutionContextRef(Target *target, bool adopt_selected) + : m_target_wp(), m_process_wp(), m_thread_wp(), + m_tid(LLDB_INVALID_THREAD_ID), m_stack_id() { + SetTargetPtr(target, adopt_selected); } -void -ExecutionContextRef::SetTargetPtr (Target* target, bool adopt_selected) -{ - Clear(); - if (target) - { - lldb::TargetSP target_sp (target->shared_from_this()); - if (target_sp) - { - m_target_wp = target_sp; - if (adopt_selected) - { - lldb::ProcessSP process_sp (target_sp->GetProcessSP()); - if (process_sp) - { - m_process_wp = process_sp; - if (process_sp) - { - // Only fill in the thread and frame if our process is stopped - // Don't just check the state, since we might be in the middle of - // resuming. - Process::StopLocker stop_locker; - - if (stop_locker.TryLock(&process_sp->GetRunLock()) && StateIsStoppedState (process_sp->GetState(), true)) - { - lldb::ThreadSP thread_sp (process_sp->GetThreadList().GetSelectedThread()); - if (!thread_sp) - thread_sp = process_sp->GetThreadList().GetThreadAtIndex(0); - - if (thread_sp) - { - SetThreadSP (thread_sp); - lldb::StackFrameSP frame_sp (thread_sp->GetSelectedFrame()); - if (!frame_sp) - frame_sp = thread_sp->GetStackFrameAtIndex(0); - if (frame_sp) - SetFrameSP (frame_sp); - } - } - } - } - } - } - } +ExecutionContextRef::ExecutionContextRef(const ExecutionContextRef &rhs) + : m_target_wp(rhs.m_target_wp), m_process_wp(rhs.m_process_wp), + m_thread_wp(rhs.m_thread_wp), m_tid(rhs.m_tid), + m_stack_id(rhs.m_stack_id) {} + +ExecutionContextRef &ExecutionContextRef:: +operator=(const ExecutionContextRef &rhs) { + if (this != &rhs) { + m_target_wp = rhs.m_target_wp; + m_process_wp = rhs.m_process_wp; + m_thread_wp = rhs.m_thread_wp; + m_tid = rhs.m_tid; + m_stack_id = rhs.m_stack_id; + } + return *this; } -void -ExecutionContextRef::SetProcessPtr (Process *process) -{ - if (process) - { - SetProcessSP(process->shared_from_this()); - } - else - { - m_process_wp.reset(); - m_target_wp.reset(); - } +ExecutionContextRef &ExecutionContextRef:: +operator=(const ExecutionContext &exe_ctx) { + m_target_wp = exe_ctx.GetTargetSP(); + m_process_wp = exe_ctx.GetProcessSP(); + lldb::ThreadSP thread_sp(exe_ctx.GetThreadSP()); + m_thread_wp = thread_sp; + if (thread_sp) + m_tid = thread_sp->GetID(); + else + m_tid = LLDB_INVALID_THREAD_ID; + lldb::StackFrameSP frame_sp(exe_ctx.GetFrameSP()); + if (frame_sp) + m_stack_id = frame_sp->GetStackID(); + else + m_stack_id.Clear(); + return *this; } -void -ExecutionContextRef::SetThreadPtr (Thread *thread) -{ - if (thread) - { - SetThreadSP (thread->shared_from_this()); - } - else - { - ClearThread(); - m_process_wp.reset(); - m_target_wp.reset(); - } +void ExecutionContextRef::Clear() { + m_target_wp.reset(); + m_process_wp.reset(); + ClearThread(); + ClearFrame(); } -void -ExecutionContextRef::SetFramePtr (StackFrame *frame) -{ - if (frame) - SetFrameSP (frame->shared_from_this()); - else - Clear(); -} - -lldb::TargetSP -ExecutionContextRef::GetTargetSP () const -{ - lldb::TargetSP target_sp(m_target_wp.lock()); - if (target_sp && !target_sp->IsValid()) - target_sp.reset(); - return target_sp; -} - -lldb::ProcessSP -ExecutionContextRef::GetProcessSP () const -{ - lldb::ProcessSP process_sp(m_process_wp.lock()); - if (process_sp && !process_sp->IsValid()) - process_sp.reset(); - return process_sp; -} - -lldb::ThreadSP -ExecutionContextRef::GetThreadSP () const -{ - lldb::ThreadSP thread_sp (m_thread_wp.lock()); - - if (m_tid != LLDB_INVALID_THREAD_ID) - { - // We check if the thread has been destroyed in cases where clients - // might still have shared pointer to a thread, but the thread is - // not valid anymore (not part of the process) - if (!thread_sp || !thread_sp->IsValid()) - { - lldb::ProcessSP process_sp(GetProcessSP()); - if (process_sp && process_sp->IsValid()) - { - thread_sp = process_sp->GetThreadList().FindThreadByID(m_tid); - m_thread_wp = thread_sp; +ExecutionContextRef::~ExecutionContextRef() = default; + +void ExecutionContextRef::SetTargetSP(const lldb::TargetSP &target_sp) { + m_target_wp = target_sp; +} + +void ExecutionContextRef::SetProcessSP(const lldb::ProcessSP &process_sp) { + if (process_sp) { + m_process_wp = process_sp; + SetTargetSP(process_sp->GetTarget().shared_from_this()); + } else { + m_process_wp.reset(); + m_target_wp.reset(); + } +} + +void ExecutionContextRef::SetThreadSP(const lldb::ThreadSP &thread_sp) { + if (thread_sp) { + m_thread_wp = thread_sp; + m_tid = thread_sp->GetID(); + SetProcessSP(thread_sp->GetProcess()); + } else { + ClearThread(); + m_process_wp.reset(); + m_target_wp.reset(); + } +} + +void ExecutionContextRef::SetFrameSP(const lldb::StackFrameSP &frame_sp) { + if (frame_sp) { + m_stack_id = frame_sp->GetStackID(); + SetThreadSP(frame_sp->GetThread()); + } else { + ClearFrame(); + ClearThread(); + m_process_wp.reset(); + m_target_wp.reset(); + } +} + +void ExecutionContextRef::SetTargetPtr(Target *target, bool adopt_selected) { + Clear(); + if (target) { + lldb::TargetSP target_sp(target->shared_from_this()); + if (target_sp) { + m_target_wp = target_sp; + if (adopt_selected) { + lldb::ProcessSP process_sp(target_sp->GetProcessSP()); + if (process_sp) { + m_process_wp = process_sp; + if (process_sp) { + // Only fill in the thread and frame if our process is stopped + // Don't just check the state, since we might be in the middle of + // resuming. + Process::StopLocker stop_locker; + + if (stop_locker.TryLock(&process_sp->GetRunLock()) && + StateIsStoppedState(process_sp->GetState(), true)) { + lldb::ThreadSP thread_sp( + process_sp->GetThreadList().GetSelectedThread()); + if (!thread_sp) + thread_sp = process_sp->GetThreadList().GetThreadAtIndex(0); + + if (thread_sp) { + SetThreadSP(thread_sp); + lldb::StackFrameSP frame_sp(thread_sp->GetSelectedFrame()); + if (!frame_sp) + frame_sp = thread_sp->GetStackFrameAtIndex(0); + if (frame_sp) + SetFrameSP(frame_sp); + } } + } } + } } - - // Check that we aren't about to return an invalid thread sp. We might return a nullptr thread_sp, - // but don't return an invalid one. - - if (thread_sp && !thread_sp->IsValid()) - thread_sp.reset(); - - return thread_sp; -} - -lldb::StackFrameSP -ExecutionContextRef::GetFrameSP () const -{ - if (m_stack_id.IsValid()) - { - lldb::ThreadSP thread_sp (GetThreadSP()); - if (thread_sp) - return thread_sp->GetFrameWithStackID (m_stack_id); + } +} + +void ExecutionContextRef::SetProcessPtr(Process *process) { + if (process) { + SetProcessSP(process->shared_from_this()); + } else { + m_process_wp.reset(); + m_target_wp.reset(); + } +} + +void ExecutionContextRef::SetThreadPtr(Thread *thread) { + if (thread) { + SetThreadSP(thread->shared_from_this()); + } else { + ClearThread(); + m_process_wp.reset(); + m_target_wp.reset(); + } +} + +void ExecutionContextRef::SetFramePtr(StackFrame *frame) { + if (frame) + SetFrameSP(frame->shared_from_this()); + else + Clear(); +} + +lldb::TargetSP ExecutionContextRef::GetTargetSP() const { + lldb::TargetSP target_sp(m_target_wp.lock()); + if (target_sp && !target_sp->IsValid()) + target_sp.reset(); + return target_sp; +} + +lldb::ProcessSP ExecutionContextRef::GetProcessSP() const { + lldb::ProcessSP process_sp(m_process_wp.lock()); + if (process_sp && !process_sp->IsValid()) + process_sp.reset(); + return process_sp; +} + +lldb::ThreadSP ExecutionContextRef::GetThreadSP() const { + lldb::ThreadSP thread_sp(m_thread_wp.lock()); + + if (m_tid != LLDB_INVALID_THREAD_ID) { + // We check if the thread has been destroyed in cases where clients + // might still have shared pointer to a thread, but the thread is + // not valid anymore (not part of the process) + if (!thread_sp || !thread_sp->IsValid()) { + lldb::ProcessSP process_sp(GetProcessSP()); + if (process_sp && process_sp->IsValid()) { + thread_sp = process_sp->GetThreadList().FindThreadByID(m_tid); + m_thread_wp = thread_sp; + } } - return lldb::StackFrameSP(); + } + + // Check that we aren't about to return an invalid thread sp. We might return + // a nullptr thread_sp, + // but don't return an invalid one. + + if (thread_sp && !thread_sp->IsValid()) + thread_sp.reset(); + + return thread_sp; +} + +lldb::StackFrameSP ExecutionContextRef::GetFrameSP() const { + if (m_stack_id.IsValid()) { + lldb::ThreadSP thread_sp(GetThreadSP()); + if (thread_sp) + return thread_sp->GetFrameWithStackID(m_stack_id); + } + return lldb::StackFrameSP(); } ExecutionContext -ExecutionContextRef::Lock (bool thread_and_frame_only_if_stopped) const -{ - return ExecutionContext(this, thread_and_frame_only_if_stopped); +ExecutionContextRef::Lock(bool thread_and_frame_only_if_stopped) const { + return ExecutionContext(this, thread_and_frame_only_if_stopped); } diff --git a/lldb/source/Target/FileAction.cpp b/lldb/source/Target/FileAction.cpp index 06d0529fe3e..46678b11f3a 100644 --- a/lldb/source/Target/FileAction.cpp +++ b/lldb/source/Target/FileAction.cpp @@ -19,101 +19,73 @@ using namespace lldb_private; // FileAction member functions //---------------------------------------------------------------------------- -FileAction::FileAction() : - m_action(eFileActionNone), - m_fd(-1), - m_arg(-1), - m_file_spec() -{ -} +FileAction::FileAction() + : m_action(eFileActionNone), m_fd(-1), m_arg(-1), m_file_spec() {} -void -FileAction::Clear() -{ - m_action = eFileActionNone; - m_fd = -1; - m_arg = -1; - m_file_spec.Clear(); +void FileAction::Clear() { + m_action = eFileActionNone; + m_fd = -1; + m_arg = -1; + m_file_spec.Clear(); } -const char * -FileAction::GetPath() const -{ - return m_file_spec.GetCString(); -} +const char *FileAction::GetPath() const { return m_file_spec.GetCString(); } -const FileSpec & -FileAction::GetFileSpec() const -{ - return m_file_spec; -} +const FileSpec &FileAction::GetFileSpec() const { return m_file_spec; } -bool -FileAction::Open(int fd, const FileSpec &file_spec, bool read, bool write) -{ - if ((read || write) && fd >= 0 && file_spec) - { - m_action = eFileActionOpen; - m_fd = fd; - if (read && write) - m_arg = O_NOCTTY | O_CREAT | O_RDWR; - else if (read) - m_arg = O_NOCTTY | O_RDONLY; - else - m_arg = O_NOCTTY | O_CREAT | O_WRONLY; - m_file_spec = file_spec; - return true; - } +bool FileAction::Open(int fd, const FileSpec &file_spec, bool read, + bool write) { + if ((read || write) && fd >= 0 && file_spec) { + m_action = eFileActionOpen; + m_fd = fd; + if (read && write) + m_arg = O_NOCTTY | O_CREAT | O_RDWR; + else if (read) + m_arg = O_NOCTTY | O_RDONLY; else - { - Clear(); - } - return false; + m_arg = O_NOCTTY | O_CREAT | O_WRONLY; + m_file_spec = file_spec; + return true; + } else { + Clear(); + } + return false; } -bool -FileAction::Close(int fd) -{ - Clear(); - if (fd >= 0) - { - m_action = eFileActionClose; - m_fd = fd; - } - return m_fd >= 0; +bool FileAction::Close(int fd) { + Clear(); + if (fd >= 0) { + m_action = eFileActionClose; + m_fd = fd; + } + return m_fd >= 0; } -bool -FileAction::Duplicate(int fd, int dup_fd) -{ - Clear(); - if (fd >= 0 && dup_fd >= 0) - { - m_action = eFileActionDuplicate; - m_fd = fd; - m_arg = dup_fd; - } - return m_fd >= 0; +bool FileAction::Duplicate(int fd, int dup_fd) { + Clear(); + if (fd >= 0 && dup_fd >= 0) { + m_action = eFileActionDuplicate; + m_fd = fd; + m_arg = dup_fd; + } + return m_fd >= 0; } -void -FileAction::Dump(Stream &stream) const -{ - stream.PutCString("file action: "); - switch (m_action) - { - case eFileActionClose: - stream.Printf("close fd %d", m_fd); - break; - case eFileActionDuplicate: - stream.Printf("duplicate fd %d to %d", m_fd, m_arg); - break; - case eFileActionNone: - stream.PutCString("no action"); - break; - case eFileActionOpen: - stream.Printf("open fd %d with '%s', OFLAGS = 0x%x", - m_fd, m_file_spec.GetCString(), m_arg); - break; - } +void FileAction::Dump(Stream &stream) const { + stream.PutCString("file action: "); + switch (m_action) { + case eFileActionClose: + stream.Printf("close fd %d", m_fd); + break; + case eFileActionDuplicate: + stream.Printf("duplicate fd %d to %d", m_fd, m_arg); + break; + case eFileActionNone: + stream.PutCString("no action"); + break; + case eFileActionOpen: + stream.Printf("open fd %d with '%s', OFLAGS = 0x%x", m_fd, + m_file_spec.GetCString(), m_arg); + break; + } } diff --git a/lldb/source/Target/InstrumentationRuntime.cpp b/lldb/source/Target/InstrumentationRuntime.cpp index 6b52416df3d..f3bc145f8b4 100644 --- a/lldb/source/Target/InstrumentationRuntime.cpp +++ b/lldb/source/Target/InstrumentationRuntime.cpp @@ -11,72 +11,70 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/Target/Process.h" +#include "lldb/Target/InstrumentationRuntime.h" #include "lldb/Core/Module.h" #include "lldb/Core/ModuleList.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/RegularExpression.h" -#include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; -void -InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list, lldb_private::Process *process, InstrumentationRuntimeCollection &runtimes) -{ - InstrumentationRuntimeCreateInstance create_callback = nullptr; - InstrumentationRuntimeGetType get_type_callback; - for (uint32_t idx = 0; ; ++idx) - { - create_callback = PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx); - if (create_callback == nullptr) - break; - get_type_callback = PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx); - InstrumentationRuntimeType type = get_type_callback(); - - InstrumentationRuntimeCollection::iterator pos; - pos = runtimes.find (type); - if (pos == runtimes.end()) { - runtimes[type] = create_callback(process->shared_from_this()); - } +void InstrumentationRuntime::ModulesDidLoad( + lldb_private::ModuleList &module_list, lldb_private::Process *process, + InstrumentationRuntimeCollection &runtimes) { + InstrumentationRuntimeCreateInstance create_callback = nullptr; + InstrumentationRuntimeGetType get_type_callback; + for (uint32_t idx = 0;; ++idx) { + create_callback = + PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx); + if (create_callback == nullptr) + break; + get_type_callback = + PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx); + InstrumentationRuntimeType type = get_type_callback(); + + InstrumentationRuntimeCollection::iterator pos; + pos = runtimes.find(type); + if (pos == runtimes.end()) { + runtimes[type] = create_callback(process->shared_from_this()); } + } } -void -InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list) -{ - if (IsActive()) - return; +void InstrumentationRuntime::ModulesDidLoad( + lldb_private::ModuleList &module_list) { + if (IsActive()) + return; - if (GetRuntimeModuleSP()) - { - Activate(); - return; - } + if (GetRuntimeModuleSP()) { + Activate(); + return; + } - module_list.ForEach([this](const lldb::ModuleSP module_sp) -> bool { - const FileSpec &file_spec = module_sp->GetFileSpec(); - if (!file_spec) - return true; // Keep iterating. + module_list.ForEach([this](const lldb::ModuleSP module_sp) -> bool { + const FileSpec &file_spec = module_sp->GetFileSpec(); + if (!file_spec) + return true; // Keep iterating. - const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary(); - if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) || module_sp->IsExecutable()) - { - if (CheckIfRuntimeIsValid(module_sp)) - { - SetRuntimeModuleSP(module_sp); - Activate(); - return false; // Stop iterating, we're done. - } - } + const RegularExpression &runtime_regex = GetPatternForRuntimeLibrary(); + if (runtime_regex.Execute(file_spec.GetFilename().GetCString()) || + module_sp->IsExecutable()) { + if (CheckIfRuntimeIsValid(module_sp)) { + SetRuntimeModuleSP(module_sp); + Activate(); + return false; // Stop iterating, we're done. + } + } - return true; - }); + return true; + }); } lldb::ThreadCollectionSP -InstrumentationRuntime::GetBacktracesFromExtendedStopInfo(StructuredData::ObjectSP info) -{ - return ThreadCollectionSP(new ThreadCollection()); +InstrumentationRuntime::GetBacktracesFromExtendedStopInfo( + StructuredData::ObjectSP info) { + return ThreadCollectionSP(new ThreadCollection()); } diff --git a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp index cdbf93b5f72..dbbd4f4fc1d 100644 --- a/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp +++ b/lldb/source/Target/InstrumentationRuntimeStopInfo.cpp @@ -9,28 +9,29 @@ #include "lldb/Target/InstrumentationRuntimeStopInfo.h" -#include "lldb/lldb-private.h" -#include "lldb/Target/Process.h" #include "lldb/Target/InstrumentationRuntime.h" +#include "lldb/Target/Process.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; -InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(Thread &thread, std::string description, StructuredData::ObjectSP additional_data) : - StopInfo(thread, 0) -{ - m_extended_info = additional_data; - m_description = description; +InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo( + Thread &thread, std::string description, + StructuredData::ObjectSP additional_data) + : StopInfo(thread, 0) { + m_extended_info = additional_data; + m_description = description; } -const char * -InstrumentationRuntimeStopInfo::GetDescription () -{ - return m_description.c_str(); +const char *InstrumentationRuntimeStopInfo::GetDescription() { + return m_description.c_str(); } StopInfoSP -InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData (Thread &thread, std::string description, StructuredData::ObjectSP additionalData) -{ - return StopInfoSP(new InstrumentationRuntimeStopInfo(thread, description, additionalData)); +InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData( + Thread &thread, std::string description, + StructuredData::ObjectSP additionalData) { + return StopInfoSP( + new InstrumentationRuntimeStopInfo(thread, description, additionalData)); } diff --git a/lldb/source/Target/JITLoader.cpp b/lldb/source/Target/JITLoader.cpp index 2e37fb0ff4e..77ce4add486 100644 --- a/lldb/source/Target/JITLoader.cpp +++ b/lldb/source/Target/JITLoader.cpp @@ -11,30 +11,27 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Target/JITLoader.h" +#include "lldb/Core/PluginManager.h" #include "lldb/Target/JITLoaderList.h" #include "lldb/Target/Process.h" -#include "lldb/Core/PluginManager.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; -void -JITLoader::LoadPlugins (Process *process, JITLoaderList &list) -{ - JITLoaderCreateInstance create_callback = nullptr; - for (uint32_t idx = 0; (create_callback = PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != nullptr; ++idx) - { - JITLoaderSP instance_sp(create_callback(process, false)); - if (instance_sp) - list.Append(std::move(instance_sp)); - } +void JITLoader::LoadPlugins(Process *process, JITLoaderList &list) { + JITLoaderCreateInstance create_callback = nullptr; + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != nullptr; + ++idx) { + JITLoaderSP instance_sp(create_callback(process, false)); + if (instance_sp) + list.Append(std::move(instance_sp)); + } } -JITLoader::JITLoader(Process *process) : - m_process (process) -{ -} +JITLoader::JITLoader(Process *process) : m_process(process) {} JITLoader::~JITLoader() = default; diff --git a/lldb/source/Target/JITLoaderList.cpp b/lldb/source/Target/JITLoaderList.cpp index 76c9dd67535..aa748a54c82 100644 --- a/lldb/source/Target/JITLoaderList.cpp +++ b/lldb/source/Target/JITLoaderList.cpp @@ -7,70 +7,50 @@ // //===----------------------------------------------------------------------===// -#include "lldb/lldb-private.h" #include "lldb/Target/JITLoader.h" #include "lldb/Target/JITLoaderList.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; -JITLoaderList::JITLoaderList() : m_jit_loaders_vec(), m_jit_loaders_mutex() -{ -} +JITLoaderList::JITLoaderList() : m_jit_loaders_vec(), m_jit_loaders_mutex() {} -JITLoaderList::~JITLoaderList() -{ -} +JITLoaderList::~JITLoaderList() {} -void -JITLoaderList::Append (const JITLoaderSP &jit_loader_sp) -{ - std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - m_jit_loaders_vec.push_back(jit_loader_sp); +void JITLoaderList::Append(const JITLoaderSP &jit_loader_sp) { + std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); + m_jit_loaders_vec.push_back(jit_loader_sp); } -void -JITLoaderList::Remove (const JITLoaderSP &jit_loader_sp) -{ - std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(), - m_jit_loaders_vec.end(), jit_loader_sp), - m_jit_loaders_vec.end()); +void JITLoaderList::Remove(const JITLoaderSP &jit_loader_sp) { + std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); + m_jit_loaders_vec.erase(std::remove(m_jit_loaders_vec.begin(), + m_jit_loaders_vec.end(), jit_loader_sp), + m_jit_loaders_vec.end()); } -size_t -JITLoaderList::GetSize() const -{ - return m_jit_loaders_vec.size(); -} +size_t JITLoaderList::GetSize() const { return m_jit_loaders_vec.size(); } -JITLoaderSP -JITLoaderList::GetLoaderAtIndex (size_t idx) -{ - std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - return m_jit_loaders_vec[idx]; +JITLoaderSP JITLoaderList::GetLoaderAtIndex(size_t idx) { + std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); + return m_jit_loaders_vec[idx]; } -void -JITLoaderList::DidLaunch() -{ - std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - for (auto const &jit_loader : m_jit_loaders_vec) - jit_loader->DidLaunch(); +void JITLoaderList::DidLaunch() { + std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); + for (auto const &jit_loader : m_jit_loaders_vec) + jit_loader->DidLaunch(); } -void -JITLoaderList::DidAttach() -{ - std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - for (auto const &jit_loader : m_jit_loaders_vec) - jit_loader->DidAttach(); +void JITLoaderList::DidAttach() { + std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); + for (auto const &jit_loader : m_jit_loaders_vec) + jit_loader->DidAttach(); } -void -JITLoaderList::ModulesDidLoad(ModuleList &module_list) -{ - std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); - for (auto const &jit_loader : m_jit_loaders_vec) - jit_loader->ModulesDidLoad(module_list); +void JITLoaderList::ModulesDidLoad(ModuleList &module_list) { + std::lock_guard<std::recursive_mutex> guard(m_jit_loaders_mutex); + for (auto const &jit_loader : m_jit_loaders_vec) + jit_loader->ModulesDidLoad(module_list); } diff --git a/lldb/source/Target/Language.cpp b/lldb/source/Target/Language.cpp index 20439b4dc55..f62073b3d17 100644 --- a/lldb/source/Target/Language.cpp +++ b/lldb/source/Target/Language.cpp @@ -1,4 +1,5 @@ -//===-- Language.cpp -------------------------------------------------*- C++ -*-===// +//===-- Language.cpp -------------------------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -23,442 +24,365 @@ using namespace lldb_private::formatters; typedef std::unique_ptr<Language> LanguageUP; typedef std::map<lldb::LanguageType, LanguageUP> LanguagesMap; -static LanguagesMap& -GetLanguagesMap () -{ - static LanguagesMap *g_map = nullptr; - static std::once_flag g_initialize; - - std::call_once(g_initialize, [] { - g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global destructor chain - }); - - return *g_map; -} -static std::mutex & -GetLanguagesMutex() -{ - static std::mutex *g_mutex = nullptr; - static std::once_flag g_initialize; +static LanguagesMap &GetLanguagesMap() { + static LanguagesMap *g_map = nullptr; + static std::once_flag g_initialize; - std::call_once(g_initialize, [] { - g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global destructor chain - }); + std::call_once(g_initialize, [] { + g_map = new LanguagesMap(); // NOTE: INTENTIONAL LEAK due to global + // destructor chain + }); - return *g_mutex; + return *g_map; } +static std::mutex &GetLanguagesMutex() { + static std::mutex *g_mutex = nullptr; + static std::once_flag g_initialize; -Language* -Language::FindPlugin (lldb::LanguageType language) -{ - std::lock_guard<std::mutex> guard(GetLanguagesMutex()); - LanguagesMap& map(GetLanguagesMap()); - auto iter = map.find(language), end = map.end(); - if (iter != end) - return iter->second.get(); - - Language *language_ptr = nullptr; - LanguageCreateInstance create_callback; - - for (uint32_t idx = 0; - (create_callback = PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr; - ++idx) - { - language_ptr = create_callback(language); - - if (language_ptr) - { - map[language] = std::unique_ptr<Language>(language_ptr); - return language_ptr; - } - } - - return nullptr; + std::call_once(g_initialize, [] { + g_mutex = new std::mutex(); // NOTE: INTENTIONAL LEAK due to global + // destructor chain + }); + + return *g_mutex; } -void -Language::ForEach (std::function<bool(Language*)> callback) -{ - std::lock_guard<std::mutex> guard(GetLanguagesMutex()); - LanguagesMap& map(GetLanguagesMap()); - for (const auto& entry : map) - { - if (!callback(entry.second.get())) - break; +Language *Language::FindPlugin(lldb::LanguageType language) { + std::lock_guard<std::mutex> guard(GetLanguagesMutex()); + LanguagesMap &map(GetLanguagesMap()); + auto iter = map.find(language), end = map.end(); + if (iter != end) + return iter->second.get(); + + Language *language_ptr = nullptr; + LanguageCreateInstance create_callback; + + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetLanguageCreateCallbackAtIndex(idx)) != nullptr; + ++idx) { + language_ptr = create_callback(language); + + if (language_ptr) { + map[language] = std::unique_ptr<Language>(language_ptr); + return language_ptr; } -} + } -bool -Language::IsTopLevelFunction (Function& function) -{ - return false; + return nullptr; } -lldb::TypeCategoryImplSP -Language::GetFormatters () -{ - return nullptr; +void Language::ForEach(std::function<bool(Language *)> callback) { + std::lock_guard<std::mutex> guard(GetLanguagesMutex()); + LanguagesMap &map(GetLanguagesMap()); + for (const auto &entry : map) { + if (!callback(entry.second.get())) + break; + } } -HardcodedFormatters::HardcodedFormatFinder -Language::GetHardcodedFormats () -{ - return {}; +bool Language::IsTopLevelFunction(Function &function) { return false; } + +lldb::TypeCategoryImplSP Language::GetFormatters() { return nullptr; } + +HardcodedFormatters::HardcodedFormatFinder Language::GetHardcodedFormats() { + return {}; } -HardcodedFormatters::HardcodedSummaryFinder -Language::GetHardcodedSummaries () -{ - return {}; +HardcodedFormatters::HardcodedSummaryFinder Language::GetHardcodedSummaries() { + return {}; } HardcodedFormatters::HardcodedSyntheticFinder -Language::GetHardcodedSynthetics () -{ - return {}; +Language::GetHardcodedSynthetics() { + return {}; } HardcodedFormatters::HardcodedValidatorFinder -Language::GetHardcodedValidators () -{ - return {}; +Language::GetHardcodedValidators() { + return {}; } std::vector<ConstString> -Language::GetPossibleFormattersMatches (ValueObject& valobj, lldb::DynamicValueType use_dynamic) -{ - return {}; +Language::GetPossibleFormattersMatches(ValueObject &valobj, + lldb::DynamicValueType use_dynamic) { + return {}; } lldb_private::formatters::StringPrinter::EscapingHelper -Language::GetStringPrinterEscapingHelper (lldb_private::formatters::StringPrinter::GetPrintableElementType elem_type) -{ - return StringPrinter::GetDefaultEscapingHelper(elem_type); +Language::GetStringPrinterEscapingHelper( + lldb_private::formatters::StringPrinter::GetPrintableElementType + elem_type) { + return StringPrinter::GetDefaultEscapingHelper(elem_type); } struct language_name_pair { - const char *name; - LanguageType type; + const char *name; + LanguageType type; }; -struct language_name_pair language_names[] = -{ +struct language_name_pair language_names[] = { // To allow GetNameForLanguageType to be a simple array lookup, the first // part of this array must follow enum LanguageType exactly. - { "unknown", eLanguageTypeUnknown }, - { "c89", eLanguageTypeC89 }, - { "c", eLanguageTypeC }, - { "ada83", eLanguageTypeAda83 }, - { "c++", eLanguageTypeC_plus_plus }, - { "cobol74", eLanguageTypeCobol74 }, - { "cobol85", eLanguageTypeCobol85 }, - { "fortran77", eLanguageTypeFortran77 }, - { "fortran90", eLanguageTypeFortran90 }, - { "pascal83", eLanguageTypePascal83 }, - { "modula2", eLanguageTypeModula2 }, - { "java", eLanguageTypeJava }, - { "c99", eLanguageTypeC99 }, - { "ada95", eLanguageTypeAda95 }, - { "fortran95", eLanguageTypeFortran95 }, - { "pli", eLanguageTypePLI }, - { "objective-c", eLanguageTypeObjC }, - { "objective-c++", eLanguageTypeObjC_plus_plus }, - { "upc", eLanguageTypeUPC }, - { "d", eLanguageTypeD }, - { "python", eLanguageTypePython }, - { "opencl", eLanguageTypeOpenCL }, - { "go", eLanguageTypeGo }, - { "modula3", eLanguageTypeModula3 }, - { "haskell", eLanguageTypeHaskell }, - { "c++03", eLanguageTypeC_plus_plus_03 }, - { "c++11", eLanguageTypeC_plus_plus_11 }, - { "ocaml", eLanguageTypeOCaml }, - { "rust", eLanguageTypeRust }, - { "c11", eLanguageTypeC11 }, - { "swift", eLanguageTypeSwift }, - { "julia", eLanguageTypeJulia }, - { "dylan", eLanguageTypeDylan }, - { "c++14", eLanguageTypeC_plus_plus_14 }, - { "fortran03", eLanguageTypeFortran03 }, - { "fortran08", eLanguageTypeFortran08 }, + {"unknown", eLanguageTypeUnknown}, + {"c89", eLanguageTypeC89}, + {"c", eLanguageTypeC}, + {"ada83", eLanguageTypeAda83}, + {"c++", eLanguageTypeC_plus_plus}, + {"cobol74", eLanguageTypeCobol74}, + {"cobol85", eLanguageTypeCobol85}, + {"fortran77", eLanguageTypeFortran77}, + {"fortran90", eLanguageTypeFortran90}, + {"pascal83", eLanguageTypePascal83}, + {"modula2", eLanguageTypeModula2}, + {"java", eLanguageTypeJava}, + {"c99", eLanguageTypeC99}, + {"ada95", eLanguageTypeAda95}, + {"fortran95", eLanguageTypeFortran95}, + {"pli", eLanguageTypePLI}, + {"objective-c", eLanguageTypeObjC}, + {"objective-c++", eLanguageTypeObjC_plus_plus}, + {"upc", eLanguageTypeUPC}, + {"d", eLanguageTypeD}, + {"python", eLanguageTypePython}, + {"opencl", eLanguageTypeOpenCL}, + {"go", eLanguageTypeGo}, + {"modula3", eLanguageTypeModula3}, + {"haskell", eLanguageTypeHaskell}, + {"c++03", eLanguageTypeC_plus_plus_03}, + {"c++11", eLanguageTypeC_plus_plus_11}, + {"ocaml", eLanguageTypeOCaml}, + {"rust", eLanguageTypeRust}, + {"c11", eLanguageTypeC11}, + {"swift", eLanguageTypeSwift}, + {"julia", eLanguageTypeJulia}, + {"dylan", eLanguageTypeDylan}, + {"c++14", eLanguageTypeC_plus_plus_14}, + {"fortran03", eLanguageTypeFortran03}, + {"fortran08", eLanguageTypeFortran08}, // Vendor Extensions - { "mipsassem", eLanguageTypeMipsAssembler }, - { "renderscript", eLanguageTypeExtRenderScript}, + {"mipsassem", eLanguageTypeMipsAssembler}, + {"renderscript", eLanguageTypeExtRenderScript}, // Now synonyms, in arbitrary order - { "objc", eLanguageTypeObjC }, - { "objc++", eLanguageTypeObjC_plus_plus }, - { "pascal", eLanguageTypePascal83 } -}; - -static uint32_t num_languages = sizeof(language_names) / sizeof (struct language_name_pair); - -LanguageType -Language::GetLanguageTypeFromString (const char *string) -{ - for (uint32_t i = 0; i < num_languages; i++) - { - if (strcasecmp (language_names[i].name, string) == 0) - return (LanguageType) language_names[i].type; - } - return eLanguageTypeUnknown; -} - -const char * -Language::GetNameForLanguageType (LanguageType language) -{ - if (language < num_languages) - return language_names[language].name; - else - return language_names[eLanguageTypeUnknown].name; -} - -void -Language::PrintAllLanguages (Stream &s, const char *prefix, const char *suffix) -{ - for (uint32_t i = 1; i < num_languages; i++) - { - s.Printf("%s%s%s", prefix, language_names[i].name, suffix); - } -} - -void -Language::ForAllLanguages (std::function<bool(lldb::LanguageType)> callback) -{ - for (uint32_t i = 1; i < num_languages; i++) - { - if (!callback(language_names[i].type)) - break; - } -} - -bool -Language::LanguageIsCPlusPlus (LanguageType language) -{ - switch (language) - { - case eLanguageTypeC_plus_plus: - case eLanguageTypeC_plus_plus_03: - case eLanguageTypeC_plus_plus_11: - case eLanguageTypeC_plus_plus_14: - case eLanguageTypeObjC_plus_plus: - return true; - default: - return false; - } -} - -bool -Language::LanguageIsObjC (LanguageType language) -{ - switch (language) - { - case eLanguageTypeObjC: - case eLanguageTypeObjC_plus_plus: - return true; - default: - return false; - } -} - -bool -Language::LanguageIsC (LanguageType language) -{ - switch (language) - { - case eLanguageTypeC: - case eLanguageTypeC89: - case eLanguageTypeC99: - case eLanguageTypeC11: - return true; - default: - return false; - } + {"objc", eLanguageTypeObjC}, + {"objc++", eLanguageTypeObjC_plus_plus}, + {"pascal", eLanguageTypePascal83}}; + +static uint32_t num_languages = + sizeof(language_names) / sizeof(struct language_name_pair); + +LanguageType Language::GetLanguageTypeFromString(const char *string) { + for (uint32_t i = 0; i < num_languages; i++) { + if (strcasecmp(language_names[i].name, string) == 0) + return (LanguageType)language_names[i].type; + } + return eLanguageTypeUnknown; +} + +const char *Language::GetNameForLanguageType(LanguageType language) { + if (language < num_languages) + return language_names[language].name; + else + return language_names[eLanguageTypeUnknown].name; +} + +void Language::PrintAllLanguages(Stream &s, const char *prefix, + const char *suffix) { + for (uint32_t i = 1; i < num_languages; i++) { + s.Printf("%s%s%s", prefix, language_names[i].name, suffix); + } +} + +void Language::ForAllLanguages( + std::function<bool(lldb::LanguageType)> callback) { + for (uint32_t i = 1; i < num_languages; i++) { + if (!callback(language_names[i].type)) + break; + } +} + +bool Language::LanguageIsCPlusPlus(LanguageType language) { + switch (language) { + case eLanguageTypeC_plus_plus: + case eLanguageTypeC_plus_plus_03: + case eLanguageTypeC_plus_plus_11: + case eLanguageTypeC_plus_plus_14: + case eLanguageTypeObjC_plus_plus: + return true; + default: + return false; + } } -bool -Language::LanguageIsPascal (LanguageType language) -{ - switch (language) - { - case eLanguageTypePascal83: - return true; - default: - return false; - } +bool Language::LanguageIsObjC(LanguageType language) { + switch (language) { + case eLanguageTypeObjC: + case eLanguageTypeObjC_plus_plus: + return true; + default: + return false; + } } -LanguageType -Language::GetPrimaryLanguage (LanguageType language) -{ - switch (language) - { - case eLanguageTypeC_plus_plus: - case eLanguageTypeC_plus_plus_03: - case eLanguageTypeC_plus_plus_11: - case eLanguageTypeC_plus_plus_14: - return eLanguageTypeC_plus_plus; - case eLanguageTypeC: - case eLanguageTypeC89: - case eLanguageTypeC99: - case eLanguageTypeC11: - return eLanguageTypeC; - case eLanguageTypeObjC: - case eLanguageTypeObjC_plus_plus: - return eLanguageTypeObjC; - case eLanguageTypePascal83: - case eLanguageTypeCobol74: - case eLanguageTypeCobol85: - case eLanguageTypeFortran77: - case eLanguageTypeFortran90: - case eLanguageTypeFortran95: - case eLanguageTypeFortran03: - case eLanguageTypeFortran08: - case eLanguageTypeAda83: - case eLanguageTypeAda95: - case eLanguageTypeModula2: - case eLanguageTypeJava: - case eLanguageTypePLI: - case eLanguageTypeUPC: - case eLanguageTypeD: - case eLanguageTypePython: - case eLanguageTypeOpenCL: - case eLanguageTypeGo: - case eLanguageTypeModula3: - case eLanguageTypeHaskell: - case eLanguageTypeOCaml: - case eLanguageTypeRust: - case eLanguageTypeSwift: - case eLanguageTypeJulia: - case eLanguageTypeDylan: - case eLanguageTypeMipsAssembler: - case eLanguageTypeExtRenderScript: - case eLanguageTypeUnknown: - default: - return language; - } +bool Language::LanguageIsC(LanguageType language) { + switch (language) { + case eLanguageTypeC: + case eLanguageTypeC89: + case eLanguageTypeC99: + case eLanguageTypeC11: + return true; + default: + return false; + } } -void -Language::GetLanguagesSupportingTypeSystems (std::set<lldb::LanguageType> &languages, - std::set<lldb::LanguageType> &languages_for_expressions) -{ - uint32_t idx = 0; - - while (TypeSystemEnumerateSupportedLanguages enumerate = PluginManager::GetTypeSystemEnumerateSupportedLanguagesCallbackAtIndex(idx++)) - { - (*enumerate)(languages, languages_for_expressions); - } -} +bool Language::LanguageIsPascal(LanguageType language) { + switch (language) { + case eLanguageTypePascal83: + return true; + default: + return false; + } +} + +LanguageType Language::GetPrimaryLanguage(LanguageType language) { + switch (language) { + case eLanguageTypeC_plus_plus: + case eLanguageTypeC_plus_plus_03: + case eLanguageTypeC_plus_plus_11: + case eLanguageTypeC_plus_plus_14: + return eLanguageTypeC_plus_plus; + case eLanguageTypeC: + case eLanguageTypeC89: + case eLanguageTypeC99: + case eLanguageTypeC11: + return eLanguageTypeC; + case eLanguageTypeObjC: + case eLanguageTypeObjC_plus_plus: + return eLanguageTypeObjC; + case eLanguageTypePascal83: + case eLanguageTypeCobol74: + case eLanguageTypeCobol85: + case eLanguageTypeFortran77: + case eLanguageTypeFortran90: + case eLanguageTypeFortran95: + case eLanguageTypeFortran03: + case eLanguageTypeFortran08: + case eLanguageTypeAda83: + case eLanguageTypeAda95: + case eLanguageTypeModula2: + case eLanguageTypeJava: + case eLanguageTypePLI: + case eLanguageTypeUPC: + case eLanguageTypeD: + case eLanguageTypePython: + case eLanguageTypeOpenCL: + case eLanguageTypeGo: + case eLanguageTypeModula3: + case eLanguageTypeHaskell: + case eLanguageTypeOCaml: + case eLanguageTypeRust: + case eLanguageTypeSwift: + case eLanguageTypeJulia: + case eLanguageTypeDylan: + case eLanguageTypeMipsAssembler: + case eLanguageTypeExtRenderScript: + case eLanguageTypeUnknown: + default: + return language; + } +} + +void Language::GetLanguagesSupportingTypeSystems( + std::set<lldb::LanguageType> &languages, + std::set<lldb::LanguageType> &languages_for_expressions) { + uint32_t idx = 0; + + while (TypeSystemEnumerateSupportedLanguages enumerate = PluginManager:: + GetTypeSystemEnumerateSupportedLanguagesCallbackAtIndex(idx++)) { + (*enumerate)(languages, languages_for_expressions); + } +} + +void Language::GetLanguagesSupportingREPLs( + std::set<lldb::LanguageType> &languages) { + uint32_t idx = 0; + + while (REPLEnumerateSupportedLanguages enumerate = + PluginManager::GetREPLEnumerateSupportedLanguagesCallbackAtIndex( + idx++)) { + (*enumerate)(languages); + } +} + +std::unique_ptr<Language::TypeScavenger> Language::GetTypeScavenger() { + return nullptr; +} + +const char *Language::GetLanguageSpecificTypeLookupHelp() { return nullptr; } + +size_t Language::TypeScavenger::Find(ExecutionContextScope *exe_scope, + const char *key, ResultSet &results, + bool append) { + if (!exe_scope || !exe_scope->CalculateTarget().get()) + return false; -void -Language::GetLanguagesSupportingREPLs (std::set<lldb::LanguageType> &languages) -{ - uint32_t idx = 0; - - while (REPLEnumerateSupportedLanguages enumerate = PluginManager::GetREPLEnumerateSupportedLanguagesCallbackAtIndex(idx++)) - { - (*enumerate)(languages); - } -} + if (!key || !key[0]) + return false; -std::unique_ptr<Language::TypeScavenger> -Language::GetTypeScavenger () -{ - return nullptr; -} + if (!append) + results.clear(); -const char* -Language::GetLanguageSpecificTypeLookupHelp () -{ - return nullptr; -} + size_t old_size = results.size(); -size_t -Language::TypeScavenger::Find (ExecutionContextScope *exe_scope, - const char *key, - ResultSet &results, - bool append) -{ - if (!exe_scope || !exe_scope->CalculateTarget().get()) - return false; - - if (!key || !key[0]) - return false; - - if (!append) - results.clear(); - - size_t old_size = results.size(); - - if (this->Find_Impl(exe_scope, key, results)) - return results.size() - old_size; - return 0; + if (this->Find_Impl(exe_scope, key, results)) + return results.size() - old_size; + return 0; } -bool -Language::GetFormatterPrefixSuffix (ValueObject& valobj, ConstString type_hint, - std::string& prefix, std::string& suffix) -{ - return false; +bool Language::GetFormatterPrefixSuffix(ValueObject &valobj, + ConstString type_hint, + std::string &prefix, + std::string &suffix) { + return false; } -DumpValueObjectOptions::DeclPrintingHelper -Language::GetDeclPrintingHelper () -{ - return nullptr; +DumpValueObjectOptions::DeclPrintingHelper Language::GetDeclPrintingHelper() { + return nullptr; } -LazyBool -Language::IsLogicalTrue (ValueObject& valobj, - Error& error) -{ - return eLazyBoolCalculate; +LazyBool Language::IsLogicalTrue(ValueObject &valobj, Error &error) { + return eLazyBoolCalculate; } -bool -Language::IsNilReference (ValueObject& valobj) -{ - return false; -} +bool Language::IsNilReference(ValueObject &valobj) { return false; } -bool -Language::IsUninitializedReference (ValueObject& valobj) -{ - return false; -} +bool Language::IsUninitializedReference(ValueObject &valobj) { return false; } -bool -Language::GetFunctionDisplayName (const SymbolContext *sc, - const ExecutionContext *exe_ctx, - FunctionNameRepresentation representation, - Stream& s) -{ - return false; +bool Language::GetFunctionDisplayName(const SymbolContext *sc, + const ExecutionContext *exe_ctx, + FunctionNameRepresentation representation, + Stream &s) { + return false; } -void -Language::GetExceptionResolverDescription(bool catch_on, bool throw_on, Stream &s) -{ - GetDefaultExceptionResolverDescription(catch_on, throw_on, s); +void Language::GetExceptionResolverDescription(bool catch_on, bool throw_on, + Stream &s) { + GetDefaultExceptionResolverDescription(catch_on, throw_on, s); } -void -Language::GetDefaultExceptionResolverDescription(bool catch_on, bool throw_on, Stream &s) -{ - s.Printf ("Exception breakpoint (catch: %s throw: %s)", - catch_on ? "on" : "off", - throw_on ? "on" : "off"); +void Language::GetDefaultExceptionResolverDescription(bool catch_on, + bool throw_on, + Stream &s) { + s.Printf("Exception breakpoint (catch: %s throw: %s)", + catch_on ? "on" : "off", throw_on ? "on" : "off"); } //---------------------------------------------------------------------- // Constructor //---------------------------------------------------------------------- -Language::Language() -{ -} +Language::Language() {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -Language::~Language() -{ -} +Language::~Language() {} diff --git a/lldb/source/Target/LanguageRuntime.cpp b/lldb/source/Target/LanguageRuntime.cpp index f61af071e3e..16cd12dde7a 100644 --- a/lldb/source/Target/LanguageRuntime.cpp +++ b/lldb/source/Target/LanguageRuntime.cpp @@ -14,340 +14,287 @@ #include "lldb/Target/LanguageRuntime.h" #include "Plugins/Language/CPlusPlus/CPlusPlusLanguage.h" #include "Plugins/Language/ObjC/ObjCLanguage.h" -#include "lldb/Target/ObjCLanguageRuntime.h" -#include "lldb/Target/Target.h" #include "lldb/Core/PluginManager.h" #include "lldb/Core/SearchFilter.h" #include "lldb/Interpreter/CommandInterpreter.h" +#include "lldb/Target/ObjCLanguageRuntime.h" +#include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; -class ExceptionSearchFilter : public SearchFilter -{ +class ExceptionSearchFilter : public SearchFilter { public: - ExceptionSearchFilter (const lldb::TargetSP &target_sp, - lldb::LanguageType language, - bool update_module_list = true) : - SearchFilter(target_sp), - m_language(language), - m_language_runtime(nullptr), - m_filter_sp() - { - if (update_module_list) - UpdateModuleListIfNeeded (); - } + ExceptionSearchFilter(const lldb::TargetSP &target_sp, + lldb::LanguageType language, + bool update_module_list = true) + : SearchFilter(target_sp), m_language(language), + m_language_runtime(nullptr), m_filter_sp() { + if (update_module_list) + UpdateModuleListIfNeeded(); + } - ~ExceptionSearchFilter() override = default; + ~ExceptionSearchFilter() override = default; - bool - ModulePasses (const lldb::ModuleSP &module_sp) override - { - UpdateModuleListIfNeeded (); - if (m_filter_sp) - return m_filter_sp->ModulePasses (module_sp); - return false; - } - - bool - ModulePasses (const FileSpec &spec) override - { - UpdateModuleListIfNeeded (); - if (m_filter_sp) - return m_filter_sp->ModulePasses (spec); - return false; - } - - void - Search (Searcher &searcher) override - { - UpdateModuleListIfNeeded (); - if (m_filter_sp) - m_filter_sp->Search (searcher); - } + bool ModulePasses(const lldb::ModuleSP &module_sp) override { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + return m_filter_sp->ModulePasses(module_sp); + return false; + } + + bool ModulePasses(const FileSpec &spec) override { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + return m_filter_sp->ModulePasses(spec); + return false; + } + + void Search(Searcher &searcher) override { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + m_filter_sp->Search(searcher); + } + + void GetDescription(Stream *s) override { + UpdateModuleListIfNeeded(); + if (m_filter_sp) + m_filter_sp->GetDescription(s); + } - void - GetDescription (Stream *s) override - { - UpdateModuleListIfNeeded (); - if (m_filter_sp) - m_filter_sp->GetDescription (s); - } - protected: - LanguageType m_language; - LanguageRuntime *m_language_runtime; - SearchFilterSP m_filter_sp; - - SearchFilterSP - DoCopyForBreakpoint(Breakpoint &breakpoint) override - { - return SearchFilterSP(new ExceptionSearchFilter(TargetSP(), m_language, false)); - } + LanguageType m_language; + LanguageRuntime *m_language_runtime; + SearchFilterSP m_filter_sp; - void - UpdateModuleListIfNeeded () - { - ProcessSP process_sp (m_target_sp->GetProcessSP()); - if (process_sp) - { - bool refreash_filter = !m_filter_sp; - if (m_language_runtime == nullptr) - { - m_language_runtime = process_sp->GetLanguageRuntime(m_language); - refreash_filter = true; - } - else - { - LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language); - if (m_language_runtime != language_runtime) - { - m_language_runtime = language_runtime; - refreash_filter = true; - } - } - - if (refreash_filter && m_language_runtime) - { - m_filter_sp = m_language_runtime->CreateExceptionSearchFilter (); - } - } - else - { - m_filter_sp.reset(); - m_language_runtime = nullptr; + SearchFilterSP DoCopyForBreakpoint(Breakpoint &breakpoint) override { + return SearchFilterSP( + new ExceptionSearchFilter(TargetSP(), m_language, false)); + } + + void UpdateModuleListIfNeeded() { + ProcessSP process_sp(m_target_sp->GetProcessSP()); + if (process_sp) { + bool refreash_filter = !m_filter_sp; + if (m_language_runtime == nullptr) { + m_language_runtime = process_sp->GetLanguageRuntime(m_language); + refreash_filter = true; + } else { + LanguageRuntime *language_runtime = + process_sp->GetLanguageRuntime(m_language); + if (m_language_runtime != language_runtime) { + m_language_runtime = language_runtime; + refreash_filter = true; } + } + + if (refreash_filter && m_language_runtime) { + m_filter_sp = m_language_runtime->CreateExceptionSearchFilter(); + } + } else { + m_filter_sp.reset(); + m_language_runtime = nullptr; } + } }; // The Target is the one that knows how to create breakpoints, so this function -// is meant to be used either by the target or internally in Set/ClearExceptionBreakpoints. -class ExceptionBreakpointResolver : public BreakpointResolver -{ +// is meant to be used either by the target or internally in +// Set/ClearExceptionBreakpoints. +class ExceptionBreakpointResolver : public BreakpointResolver { public: - ExceptionBreakpointResolver (lldb::LanguageType language, - bool catch_bp, - bool throw_bp) : - BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver), - m_language(language), - m_language_runtime(nullptr), - m_catch_bp(catch_bp), - m_throw_bp(throw_bp) - { - } + ExceptionBreakpointResolver(lldb::LanguageType language, bool catch_bp, + bool throw_bp) + : BreakpointResolver(nullptr, BreakpointResolver::ExceptionResolver), + m_language(language), m_language_runtime(nullptr), m_catch_bp(catch_bp), + m_throw_bp(throw_bp) {} - ~ExceptionBreakpointResolver() override = default; - - Searcher::CallbackReturn - SearchCallback (SearchFilter &filter, - SymbolContext &context, - Address *addr, - bool containing) override - { - - if (SetActualResolver()) - return m_actual_resolver_sp->SearchCallback (filter, context, addr, containing); - else - return eCallbackReturnStop; - } - - Searcher::Depth - GetDepth () override - { - if (SetActualResolver()) - return m_actual_resolver_sp->GetDepth(); - else - return eDepthTarget; - } - - void - GetDescription (Stream *s) override - { - Language *language_plugin = Language::FindPlugin(m_language); - if (language_plugin) - language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp, *s); - else - Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp, *s); - - SetActualResolver(); - if (m_actual_resolver_sp) - { - s->Printf (" using: "); - m_actual_resolver_sp->GetDescription (s); - } - else - s->Printf (" the correct runtime exception handler will be determined when you run"); - } + ~ExceptionBreakpointResolver() override = default; - void - Dump (Stream *s) const override - { - } - - /// Methods for support type inquiry through isa, cast, and dyn_cast: - static inline bool classof(const BreakpointResolverName *) { return true; } - static inline bool classof(const BreakpointResolver *V) { - return V->getResolverID() == BreakpointResolver::ExceptionResolver; - } + Searcher::CallbackReturn SearchCallback(SearchFilter &filter, + SymbolContext &context, Address *addr, + bool containing) override { + + if (SetActualResolver()) + return m_actual_resolver_sp->SearchCallback(filter, context, addr, + containing); + else + return eCallbackReturnStop; + } + + Searcher::Depth GetDepth() override { + if (SetActualResolver()) + return m_actual_resolver_sp->GetDepth(); + else + return eDepthTarget; + } + + void GetDescription(Stream *s) override { + Language *language_plugin = Language::FindPlugin(m_language); + if (language_plugin) + language_plugin->GetExceptionResolverDescription(m_catch_bp, m_throw_bp, + *s); + else + Language::GetDefaultExceptionResolverDescription(m_catch_bp, m_throw_bp, + *s); + + SetActualResolver(); + if (m_actual_resolver_sp) { + s->Printf(" using: "); + m_actual_resolver_sp->GetDescription(s); + } else + s->Printf(" the correct runtime exception handler will be determined " + "when you run"); + } + + void Dump(Stream *s) const override {} + + /// Methods for support type inquiry through isa, cast, and dyn_cast: + static inline bool classof(const BreakpointResolverName *) { return true; } + static inline bool classof(const BreakpointResolver *V) { + return V->getResolverID() == BreakpointResolver::ExceptionResolver; + } protected: - BreakpointResolverSP - CopyForBreakpoint (Breakpoint &breakpoint) override - { - return BreakpointResolverSP(new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp)); - } + BreakpointResolverSP CopyForBreakpoint(Breakpoint &breakpoint) override { + return BreakpointResolverSP( + new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp)); + } - bool - SetActualResolver() - { - ProcessSP process_sp; - if (m_breakpoint) - { - process_sp = m_breakpoint->GetTarget().GetProcessSP(); - if (process_sp) - { - bool refreash_resolver = !m_actual_resolver_sp; - if (m_language_runtime == nullptr) - { - m_language_runtime = process_sp->GetLanguageRuntime(m_language); - refreash_resolver = true; - } - else - { - LanguageRuntime *language_runtime = process_sp->GetLanguageRuntime(m_language); - if (m_language_runtime != language_runtime) - { - m_language_runtime = language_runtime; - refreash_resolver = true; - } - } - - if (refreash_resolver && m_language_runtime) - { - m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver (m_breakpoint, m_catch_bp, m_throw_bp); - } - } - else - { - m_actual_resolver_sp.reset(); - m_language_runtime = nullptr; - } + bool SetActualResolver() { + ProcessSP process_sp; + if (m_breakpoint) { + process_sp = m_breakpoint->GetTarget().GetProcessSP(); + if (process_sp) { + bool refreash_resolver = !m_actual_resolver_sp; + if (m_language_runtime == nullptr) { + m_language_runtime = process_sp->GetLanguageRuntime(m_language); + refreash_resolver = true; + } else { + LanguageRuntime *language_runtime = + process_sp->GetLanguageRuntime(m_language); + if (m_language_runtime != language_runtime) { + m_language_runtime = language_runtime; + refreash_resolver = true; + } } - else - { - m_actual_resolver_sp.reset(); - m_language_runtime = nullptr; + + if (refreash_resolver && m_language_runtime) { + m_actual_resolver_sp = m_language_runtime->CreateExceptionResolver( + m_breakpoint, m_catch_bp, m_throw_bp); } - return (bool)m_actual_resolver_sp; + } else { + m_actual_resolver_sp.reset(); + m_language_runtime = nullptr; + } + } else { + m_actual_resolver_sp.reset(); + m_language_runtime = nullptr; } + return (bool)m_actual_resolver_sp; + } - lldb::BreakpointResolverSP m_actual_resolver_sp; - lldb::LanguageType m_language; - LanguageRuntime *m_language_runtime; - bool m_catch_bp; - bool m_throw_bp; + lldb::BreakpointResolverSP m_actual_resolver_sp; + lldb::LanguageType m_language; + LanguageRuntime *m_language_runtime; + bool m_catch_bp; + bool m_throw_bp; }; -LanguageRuntime* -LanguageRuntime::FindPlugin (Process *process, lldb::LanguageType language) -{ - std::unique_ptr<LanguageRuntime> language_runtime_ap; - LanguageRuntimeCreateInstance create_callback; +LanguageRuntime *LanguageRuntime::FindPlugin(Process *process, + lldb::LanguageType language) { + std::unique_ptr<LanguageRuntime> language_runtime_ap; + LanguageRuntimeCreateInstance create_callback; - for (uint32_t idx = 0; - (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr; - ++idx) - { - language_runtime_ap.reset (create_callback(process, language)); + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != + nullptr; + ++idx) { + language_runtime_ap.reset(create_callback(process, language)); - if (language_runtime_ap) - return language_runtime_ap.release(); - } + if (language_runtime_ap) + return language_runtime_ap.release(); + } - return nullptr; + return nullptr; } -LanguageRuntime::LanguageRuntime(Process *process) : - m_process (process) -{ -} +LanguageRuntime::LanguageRuntime(Process *process) : m_process(process) {} LanguageRuntime::~LanguageRuntime() = default; Breakpoint::BreakpointPreconditionSP -LanguageRuntime::CreateExceptionPrecondition (lldb::LanguageType language, - bool catch_bp, - bool throw_bp) -{ - switch (language) - { - case eLanguageTypeObjC: - if (throw_bp) - return Breakpoint::BreakpointPreconditionSP(new ObjCLanguageRuntime::ObjCExceptionPrecondition ()); - break; - default: - break; - } - return Breakpoint::BreakpointPreconditionSP(); +LanguageRuntime::CreateExceptionPrecondition(lldb::LanguageType language, + bool catch_bp, bool throw_bp) { + switch (language) { + case eLanguageTypeObjC: + if (throw_bp) + return Breakpoint::BreakpointPreconditionSP( + new ObjCLanguageRuntime::ObjCExceptionPrecondition()); + break; + default: + break; + } + return Breakpoint::BreakpointPreconditionSP(); } -BreakpointSP -LanguageRuntime::CreateExceptionBreakpoint (Target &target, - lldb::LanguageType language, - bool catch_bp, - bool throw_bp, - bool is_internal) -{ - BreakpointResolverSP resolver_sp(new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); - SearchFilterSP filter_sp(new ExceptionSearchFilter(target.shared_from_this(), language)); - bool hardware = false; - bool resolve_indirect_functions = false; - BreakpointSP exc_breakpt_sp (target.CreateBreakpoint (filter_sp, resolver_sp, is_internal, hardware, resolve_indirect_functions)); - if (exc_breakpt_sp) - { - Breakpoint::BreakpointPreconditionSP precondition_sp = CreateExceptionPrecondition(language, catch_bp, throw_bp); - if (precondition_sp) - exc_breakpt_sp->SetPrecondition(precondition_sp); - - if (is_internal) - exc_breakpt_sp->SetBreakpointKind("exception"); - } - - return exc_breakpt_sp; +BreakpointSP LanguageRuntime::CreateExceptionBreakpoint( + Target &target, lldb::LanguageType language, bool catch_bp, bool throw_bp, + bool is_internal) { + BreakpointResolverSP resolver_sp( + new ExceptionBreakpointResolver(language, catch_bp, throw_bp)); + SearchFilterSP filter_sp( + new ExceptionSearchFilter(target.shared_from_this(), language)); + bool hardware = false; + bool resolve_indirect_functions = false; + BreakpointSP exc_breakpt_sp( + target.CreateBreakpoint(filter_sp, resolver_sp, is_internal, hardware, + resolve_indirect_functions)); + if (exc_breakpt_sp) { + Breakpoint::BreakpointPreconditionSP precondition_sp = + CreateExceptionPrecondition(language, catch_bp, throw_bp); + if (precondition_sp) + exc_breakpt_sp->SetPrecondition(precondition_sp); + + if (is_internal) + exc_breakpt_sp->SetBreakpointKind("exception"); + } + + return exc_breakpt_sp; } -void -LanguageRuntime::InitializeCommands (CommandObject* parent) -{ - if (!parent) - return; - - if (!parent->IsMultiwordObject()) - return; - - LanguageRuntimeCreateInstance create_callback; - - for (uint32_t idx = 0; - (create_callback = PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != nullptr; - ++idx) - { - if (LanguageRuntimeGetCommandObject command_callback = - PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) - { - CommandObjectSP command = command_callback(parent->GetCommandInterpreter()); - if (command) - { - // the CommandObject vended by a Language plugin cannot be created once and cached because - // we may create multiple debuggers and need one instance of the command each - the implementing function - // is meant to create a new instance of the command each time it is invoked - parent->LoadSubCommand(command->GetCommandName(), command); - } - } +void LanguageRuntime::InitializeCommands(CommandObject *parent) { + if (!parent) + return; + + if (!parent->IsMultiwordObject()) + return; + + LanguageRuntimeCreateInstance create_callback; + + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetLanguageRuntimeCreateCallbackAtIndex(idx)) != + nullptr; + ++idx) { + if (LanguageRuntimeGetCommandObject command_callback = + PluginManager::GetLanguageRuntimeGetCommandObjectAtIndex(idx)) { + CommandObjectSP command = + command_callback(parent->GetCommandInterpreter()); + if (command) { + // the CommandObject vended by a Language plugin cannot be created once + // and cached because + // we may create multiple debuggers and need one instance of the command + // each - the implementing function + // is meant to create a new instance of the command each time it is + // invoked + parent->LoadSubCommand(command->GetCommandName(), command); + } } + } } -lldb::SearchFilterSP -LanguageRuntime::CreateExceptionSearchFilter () -{ - return m_process->GetTarget().GetSearchFilterForModule(nullptr); +lldb::SearchFilterSP LanguageRuntime::CreateExceptionSearchFilter() { + return m_process->GetTarget().GetSearchFilterForModule(nullptr); } diff --git a/lldb/source/Target/Memory.cpp b/lldb/source/Target/Memory.cpp index 2a734e3c769..2814fcc67b1 100644 --- a/lldb/source/Target/Memory.cpp +++ b/lldb/source/Target/Memory.cpp @@ -26,518 +26,463 @@ using namespace lldb_private; // MemoryCache constructor //---------------------------------------------------------------------- MemoryCache::MemoryCache(Process &process) - : m_mutex(), - m_L1_cache(), - m_L2_cache(), - m_invalid_ranges(), + : m_mutex(), m_L1_cache(), m_L2_cache(), m_invalid_ranges(), m_process(process), - m_L2_cache_line_byte_size(process.GetMemoryCacheLineSize()) -{ -} + m_L2_cache_line_byte_size(process.GetMemoryCacheLineSize()) {} //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -MemoryCache::~MemoryCache() -{ -} - -void -MemoryCache::Clear(bool clear_invalid_ranges) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_L1_cache.clear(); - m_L2_cache.clear(); - if (clear_invalid_ranges) - m_invalid_ranges.Clear(); - m_L2_cache_line_byte_size = m_process.GetMemoryCacheLineSize(); +MemoryCache::~MemoryCache() {} + +void MemoryCache::Clear(bool clear_invalid_ranges) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_L1_cache.clear(); + m_L2_cache.clear(); + if (clear_invalid_ranges) + m_invalid_ranges.Clear(); + m_L2_cache_line_byte_size = m_process.GetMemoryCacheLineSize(); } -void -MemoryCache::AddL1CacheData(lldb::addr_t addr, const void *src, size_t src_len) -{ - AddL1CacheData(addr,DataBufferSP (new DataBufferHeap(DataBufferHeap(src, src_len)))); +void MemoryCache::AddL1CacheData(lldb::addr_t addr, const void *src, + size_t src_len) { + AddL1CacheData( + addr, DataBufferSP(new DataBufferHeap(DataBufferHeap(src, src_len)))); } -void -MemoryCache::AddL1CacheData(lldb::addr_t addr, const DataBufferSP &data_buffer_sp) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_L1_cache[addr] = data_buffer_sp; +void MemoryCache::AddL1CacheData(lldb::addr_t addr, + const DataBufferSP &data_buffer_sp) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_L1_cache[addr] = data_buffer_sp; } -void -MemoryCache::Flush (addr_t addr, size_t size) -{ - if (size == 0) - return; +void MemoryCache::Flush(addr_t addr, size_t size) { + if (size == 0) + return; - std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); - // Erase any blocks from the L1 cache that intersect with the flush range - if (!m_L1_cache.empty()) - { - AddrRange flush_range(addr, size); - BlockMap::iterator pos = m_L1_cache.upper_bound(addr); - if (pos != m_L1_cache.begin()) - { - --pos; - } - while (pos != m_L1_cache.end()) - { - AddrRange chunk_range(pos->first, pos->second->GetByteSize()); - if (!chunk_range.DoesIntersect(flush_range)) - break; - pos = m_L1_cache.erase(pos); - } + // Erase any blocks from the L1 cache that intersect with the flush range + if (!m_L1_cache.empty()) { + AddrRange flush_range(addr, size); + BlockMap::iterator pos = m_L1_cache.upper_bound(addr); + if (pos != m_L1_cache.begin()) { + --pos; } - - if (!m_L2_cache.empty()) - { - const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size; - const addr_t end_addr = (addr + size - 1); - const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size); - const addr_t last_cache_line_addr = end_addr - (end_addr % cache_line_byte_size); - // Watch for overflow where size will cause us to go off the end of the - // 64 bit address space - uint32_t num_cache_lines; - if (last_cache_line_addr >= first_cache_line_addr) - num_cache_lines = ((last_cache_line_addr - first_cache_line_addr)/cache_line_byte_size) + 1; - else - num_cache_lines = (UINT64_MAX - first_cache_line_addr + 1)/cache_line_byte_size; - - uint32_t cache_idx = 0; - for (addr_t curr_addr = first_cache_line_addr; - cache_idx < num_cache_lines; - curr_addr += cache_line_byte_size, ++cache_idx) - { - BlockMap::iterator pos = m_L2_cache.find (curr_addr); - if (pos != m_L2_cache.end()) - m_L2_cache.erase(pos); - } + while (pos != m_L1_cache.end()) { + AddrRange chunk_range(pos->first, pos->second->GetByteSize()); + if (!chunk_range.DoesIntersect(flush_range)) + break; + pos = m_L1_cache.erase(pos); } -} - -void -MemoryCache::AddInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size) -{ - if (byte_size > 0) - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - InvalidRanges::Entry range (base_addr, byte_size); - m_invalid_ranges.Append(range); - m_invalid_ranges.Sort(); + } + + if (!m_L2_cache.empty()) { + const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size; + const addr_t end_addr = (addr + size - 1); + const addr_t first_cache_line_addr = addr - (addr % cache_line_byte_size); + const addr_t last_cache_line_addr = + end_addr - (end_addr % cache_line_byte_size); + // Watch for overflow where size will cause us to go off the end of the + // 64 bit address space + uint32_t num_cache_lines; + if (last_cache_line_addr >= first_cache_line_addr) + num_cache_lines = ((last_cache_line_addr - first_cache_line_addr) / + cache_line_byte_size) + + 1; + else + num_cache_lines = + (UINT64_MAX - first_cache_line_addr + 1) / cache_line_byte_size; + + uint32_t cache_idx = 0; + for (addr_t curr_addr = first_cache_line_addr; cache_idx < num_cache_lines; + curr_addr += cache_line_byte_size, ++cache_idx) { + BlockMap::iterator pos = m_L2_cache.find(curr_addr); + if (pos != m_L2_cache.end()) + m_L2_cache.erase(pos); } + } } -bool -MemoryCache::RemoveInvalidRange (lldb::addr_t base_addr, lldb::addr_t byte_size) -{ - if (byte_size > 0) - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr); - if (idx != UINT32_MAX) - { - const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex (idx); - if (entry->GetRangeBase() == base_addr && entry->GetByteSize() == byte_size) - return m_invalid_ranges.RemoveEntrtAtIndex (idx); - } - } - return false; +void MemoryCache::AddInvalidRange(lldb::addr_t base_addr, + lldb::addr_t byte_size) { + if (byte_size > 0) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + InvalidRanges::Entry range(base_addr, byte_size); + m_invalid_ranges.Append(range); + m_invalid_ranges.Sort(); + } } - - -size_t -MemoryCache::Read (addr_t addr, - void *dst, - size_t dst_len, - Error &error) -{ - size_t bytes_left = dst_len; - - // Check the L1 cache for a range that contain the entire memory read. - // If we find a range in the L1 cache that does, we use it. Else we fall - // back to reading memory in m_L2_cache_line_byte_size byte sized chunks. - // The L1 cache contains chunks of memory that are not required to be - // m_L2_cache_line_byte_size bytes in size, so we don't try anything - // tricky when reading from them (no partial reads from the L1 cache). - +bool MemoryCache::RemoveInvalidRange(lldb::addr_t base_addr, + lldb::addr_t byte_size) { + if (byte_size > 0) { std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (!m_L1_cache.empty()) - { - AddrRange read_range(addr, dst_len); - BlockMap::iterator pos = m_L1_cache.upper_bound(addr); - if (pos != m_L1_cache.begin ()) - { - --pos; - } - AddrRange chunk_range(pos->first, pos->second->GetByteSize()); - if (chunk_range.Contains(read_range)) - { - memcpy(dst, pos->second->GetBytes() + addr - chunk_range.GetRangeBase(), dst_len); - return dst_len; - } + const uint32_t idx = m_invalid_ranges.FindEntryIndexThatContains(base_addr); + if (idx != UINT32_MAX) { + const InvalidRanges::Entry *entry = m_invalid_ranges.GetEntryAtIndex(idx); + if (entry->GetRangeBase() == base_addr && + entry->GetByteSize() == byte_size) + return m_invalid_ranges.RemoveEntrtAtIndex(idx); } + } + return false; +} - - // If this memory read request is larger than the cache line size, then - // we (1) try to read as much of it at once as possible, and (2) don't - // add the data to the memory cache. We don't want to split a big read - // up into more separate reads than necessary, and with a large memory read - // request, it is unlikely that the caller function will ask for the next - // 4 bytes after the large memory read - so there's little benefit to saving - // it in the cache. - if (dst && dst_len > m_L2_cache_line_byte_size) - { - size_t bytes_read = m_process.ReadMemoryFromInferior (addr, dst, dst_len, error); - // Add this non block sized range to the L1 cache if we actually read anything - if (bytes_read > 0) - AddL1CacheData(addr, dst, bytes_read); - return bytes_read; +size_t MemoryCache::Read(addr_t addr, void *dst, size_t dst_len, Error &error) { + size_t bytes_left = dst_len; + + // Check the L1 cache for a range that contain the entire memory read. + // If we find a range in the L1 cache that does, we use it. Else we fall + // back to reading memory in m_L2_cache_line_byte_size byte sized chunks. + // The L1 cache contains chunks of memory that are not required to be + // m_L2_cache_line_byte_size bytes in size, so we don't try anything + // tricky when reading from them (no partial reads from the L1 cache). + + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (!m_L1_cache.empty()) { + AddrRange read_range(addr, dst_len); + BlockMap::iterator pos = m_L1_cache.upper_bound(addr); + if (pos != m_L1_cache.begin()) { + --pos; } - - if (dst && bytes_left > 0) - { - const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size; - uint8_t *dst_buf = (uint8_t *)dst; - addr_t curr_addr = addr - (addr % cache_line_byte_size); - addr_t cache_offset = addr - curr_addr; - - while (bytes_left > 0) - { - if (m_invalid_ranges.FindEntryThatContains(curr_addr)) - { - error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, curr_addr); - return dst_len - bytes_left; - } - - BlockMap::const_iterator pos = m_L2_cache.find (curr_addr); - BlockMap::const_iterator end = m_L2_cache.end (); - - if (pos != end) - { - size_t curr_read_size = cache_line_byte_size - cache_offset; - if (curr_read_size > bytes_left) - curr_read_size = bytes_left; - - memcpy (dst_buf + dst_len - bytes_left, pos->second->GetBytes() + cache_offset, curr_read_size); - - bytes_left -= curr_read_size; - curr_addr += curr_read_size + cache_offset; - cache_offset = 0; - - if (bytes_left > 0) - { - // Get sequential cache page hits - for (++pos; (pos != end) && (bytes_left > 0); ++pos) - { - assert ((curr_addr % cache_line_byte_size) == 0); - - if (pos->first != curr_addr) - break; - - curr_read_size = pos->second->GetByteSize(); - if (curr_read_size > bytes_left) - curr_read_size = bytes_left; - - memcpy (dst_buf + dst_len - bytes_left, pos->second->GetBytes(), curr_read_size); - - bytes_left -= curr_read_size; - curr_addr += curr_read_size; - - // We have a cache page that succeeded to read some bytes - // but not an entire page. If this happens, we must cap - // off how much data we are able to read... - if (pos->second->GetByteSize() != cache_line_byte_size) - return dst_len - bytes_left; - } - } - } - - // We need to read from the process - - if (bytes_left > 0) - { - assert ((curr_addr % cache_line_byte_size) == 0); - std::unique_ptr<DataBufferHeap> data_buffer_heap_ap(new DataBufferHeap (cache_line_byte_size, 0)); - size_t process_bytes_read = m_process.ReadMemoryFromInferior (curr_addr, - data_buffer_heap_ap->GetBytes(), - data_buffer_heap_ap->GetByteSize(), - error); - if (process_bytes_read == 0) - return dst_len - bytes_left; - - if (process_bytes_read != cache_line_byte_size) - data_buffer_heap_ap->SetByteSize (process_bytes_read); - m_L2_cache[curr_addr] = DataBufferSP (data_buffer_heap_ap.release()); - // We have read data and put it into the cache, continue through the - // loop again to get the data out of the cache... - } + AddrRange chunk_range(pos->first, pos->second->GetByteSize()); + if (chunk_range.Contains(read_range)) { + memcpy(dst, pos->second->GetBytes() + addr - chunk_range.GetRangeBase(), + dst_len); + return dst_len; + } + } + + // If this memory read request is larger than the cache line size, then + // we (1) try to read as much of it at once as possible, and (2) don't + // add the data to the memory cache. We don't want to split a big read + // up into more separate reads than necessary, and with a large memory read + // request, it is unlikely that the caller function will ask for the next + // 4 bytes after the large memory read - so there's little benefit to saving + // it in the cache. + if (dst && dst_len > m_L2_cache_line_byte_size) { + size_t bytes_read = + m_process.ReadMemoryFromInferior(addr, dst, dst_len, error); + // Add this non block sized range to the L1 cache if we actually read + // anything + if (bytes_read > 0) + AddL1CacheData(addr, dst, bytes_read); + return bytes_read; + } + + if (dst && bytes_left > 0) { + const uint32_t cache_line_byte_size = m_L2_cache_line_byte_size; + uint8_t *dst_buf = (uint8_t *)dst; + addr_t curr_addr = addr - (addr % cache_line_byte_size); + addr_t cache_offset = addr - curr_addr; + + while (bytes_left > 0) { + if (m_invalid_ranges.FindEntryThatContains(curr_addr)) { + error.SetErrorStringWithFormat("memory read failed for 0x%" PRIx64, + curr_addr); + return dst_len - bytes_left; + } + + BlockMap::const_iterator pos = m_L2_cache.find(curr_addr); + BlockMap::const_iterator end = m_L2_cache.end(); + + if (pos != end) { + size_t curr_read_size = cache_line_byte_size - cache_offset; + if (curr_read_size > bytes_left) + curr_read_size = bytes_left; + + memcpy(dst_buf + dst_len - bytes_left, + pos->second->GetBytes() + cache_offset, curr_read_size); + + bytes_left -= curr_read_size; + curr_addr += curr_read_size + cache_offset; + cache_offset = 0; + + if (bytes_left > 0) { + // Get sequential cache page hits + for (++pos; (pos != end) && (bytes_left > 0); ++pos) { + assert((curr_addr % cache_line_byte_size) == 0); + + if (pos->first != curr_addr) + break; + + curr_read_size = pos->second->GetByteSize(); + if (curr_read_size > bytes_left) + curr_read_size = bytes_left; + + memcpy(dst_buf + dst_len - bytes_left, pos->second->GetBytes(), + curr_read_size); + + bytes_left -= curr_read_size; + curr_addr += curr_read_size; + + // We have a cache page that succeeded to read some bytes + // but not an entire page. If this happens, we must cap + // off how much data we are able to read... + if (pos->second->GetByteSize() != cache_line_byte_size) + return dst_len - bytes_left; + } } + } + + // We need to read from the process + + if (bytes_left > 0) { + assert((curr_addr % cache_line_byte_size) == 0); + std::unique_ptr<DataBufferHeap> data_buffer_heap_ap( + new DataBufferHeap(cache_line_byte_size, 0)); + size_t process_bytes_read = m_process.ReadMemoryFromInferior( + curr_addr, data_buffer_heap_ap->GetBytes(), + data_buffer_heap_ap->GetByteSize(), error); + if (process_bytes_read == 0) + return dst_len - bytes_left; + + if (process_bytes_read != cache_line_byte_size) + data_buffer_heap_ap->SetByteSize(process_bytes_read); + m_L2_cache[curr_addr] = DataBufferSP(data_buffer_heap_ap.release()); + // We have read data and put it into the cache, continue through the + // loop again to get the data out of the cache... + } } - - return dst_len - bytes_left; -} + } - - -AllocatedBlock::AllocatedBlock (lldb::addr_t addr, - uint32_t byte_size, - uint32_t permissions, - uint32_t chunk_size) : - m_addr (addr), - m_byte_size (byte_size), - m_permissions (permissions), - m_chunk_size (chunk_size), - m_offset_to_chunk_size () -// m_allocated (byte_size / chunk_size) -{ - assert (byte_size > chunk_size); + return dst_len - bytes_left; } -AllocatedBlock::~AllocatedBlock () +AllocatedBlock::AllocatedBlock(lldb::addr_t addr, uint32_t byte_size, + uint32_t permissions, uint32_t chunk_size) + : m_addr(addr), m_byte_size(byte_size), m_permissions(permissions), + m_chunk_size(chunk_size), m_offset_to_chunk_size() +// m_allocated (byte_size / chunk_size) { + assert(byte_size > chunk_size); } -lldb::addr_t -AllocatedBlock::ReserveBlock (uint32_t size) -{ - addr_t addr = LLDB_INVALID_ADDRESS; - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (size <= m_byte_size) - { - const uint32_t needed_chunks = CalculateChunksNeededForSize (size); - - if (m_offset_to_chunk_size.empty()) - { - m_offset_to_chunk_size[0] = needed_chunks; +AllocatedBlock::~AllocatedBlock() {} + +lldb::addr_t AllocatedBlock::ReserveBlock(uint32_t size) { + addr_t addr = LLDB_INVALID_ADDRESS; + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); + if (size <= m_byte_size) { + const uint32_t needed_chunks = CalculateChunksNeededForSize(size); + + if (m_offset_to_chunk_size.empty()) { + m_offset_to_chunk_size[0] = needed_chunks; + if (log) + log->Printf("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) " + "=> offset = 0x%x, %u %u bit chunks", + (void *)this, size, size, 0, needed_chunks, m_chunk_size); + addr = m_addr; + } else { + uint32_t last_offset = 0; + OffsetToChunkSize::const_iterator pos = m_offset_to_chunk_size.begin(); + OffsetToChunkSize::const_iterator end = m_offset_to_chunk_size.end(); + while (pos != end) { + if (pos->first > last_offset) { + const uint32_t bytes_available = pos->first - last_offset; + const uint32_t num_chunks = + CalculateChunksNeededForSize(bytes_available); + if (num_chunks >= needed_chunks) { + m_offset_to_chunk_size[last_offset] = needed_chunks; if (log) - log->Printf("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", (void *)this, - size, size, 0, needed_chunks, m_chunk_size); - addr = m_addr; - } - else - { - uint32_t last_offset = 0; - OffsetToChunkSize::const_iterator pos = m_offset_to_chunk_size.begin(); - OffsetToChunkSize::const_iterator end = m_offset_to_chunk_size.end(); - while (pos != end) - { - if (pos->first > last_offset) - { - const uint32_t bytes_available = pos->first - last_offset; - const uint32_t num_chunks = CalculateChunksNeededForSize (bytes_available); - if (num_chunks >= needed_chunks) - { - m_offset_to_chunk_size[last_offset] = needed_chunks; - if (log) - log->Printf("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - " - "num_chunks %lu", - (void *)this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size()); - addr = m_addr + last_offset; - break; - } - } - - last_offset = pos->first + pos->second * m_chunk_size; - - if (++pos == end) - { - // Last entry... - const uint32_t chunks_left = CalculateChunksNeededForSize (m_byte_size - last_offset); - if (chunks_left >= needed_chunks) - { - m_offset_to_chunk_size[last_offset] = needed_chunks; - if (log) - log->Printf("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - " - "num_chunks %lu", - (void *)this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size()); - addr = m_addr + last_offset; - break; - } - } - } + log->Printf("[2] AllocatedBlock::ReserveBlock(%p) (size = %u " + "(0x%x)) => offset = 0x%x, %u %u bit chunks - " + "num_chunks %lu", + (void *)this, size, size, last_offset, needed_chunks, + m_chunk_size, m_offset_to_chunk_size.size()); + addr = m_addr + last_offset; + break; + } } -// const uint32_t total_chunks = m_allocated.size (); -// uint32_t unallocated_idx = 0; -// uint32_t allocated_idx = m_allocated.find_first(); -// uint32_t first_chunk_idx = UINT32_MAX; -// uint32_t num_chunks; -// while (1) -// { -// if (allocated_idx == UINT32_MAX) -// { -// // No more bits are set starting from unallocated_idx, so we -// // either have enough chunks for the request, or we don't. -// // Either way we break out of the while loop... -// num_chunks = total_chunks - unallocated_idx; -// if (needed_chunks <= num_chunks) -// first_chunk_idx = unallocated_idx; -// break; -// } -// else if (allocated_idx > unallocated_idx) -// { -// // We have some allocated chunks, check if there are enough -// // free chunks to satisfy the request? -// num_chunks = allocated_idx - unallocated_idx; -// if (needed_chunks <= num_chunks) -// { -// // Yep, we have enough! -// first_chunk_idx = unallocated_idx; -// break; -// } -// } -// -// while (unallocated_idx < total_chunks) -// { -// if (m_allocated[unallocated_idx]) -// ++unallocated_idx; -// else -// break; -// } -// -// if (unallocated_idx >= total_chunks) -// break; -// -// allocated_idx = m_allocated.find_next(unallocated_idx); -// } -// -// if (first_chunk_idx != UINT32_MAX) -// { -// const uint32_t end_bit_idx = unallocated_idx + needed_chunks; -// for (uint32_t idx = first_chunk_idx; idx < end_bit_idx; ++idx) -// m_allocated.set(idx); -// return m_addr + m_chunk_size * first_chunk_idx; -// } - } - if (log) - log->Printf("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, (void *)this, size, size, (uint64_t)addr); - return addr; -} + last_offset = pos->first + pos->second * m_chunk_size; -bool -AllocatedBlock::FreeBlock (addr_t addr) -{ - uint32_t offset = addr - m_addr; - OffsetToChunkSize::iterator pos = m_offset_to_chunk_size.find (offset); - bool success = false; - if (pos != m_offset_to_chunk_size.end()) - { - m_offset_to_chunk_size.erase (pos); - success = true; + if (++pos == end) { + // Last entry... + const uint32_t chunks_left = + CalculateChunksNeededForSize(m_byte_size - last_offset); + if (chunks_left >= needed_chunks) { + m_offset_to_chunk_size[last_offset] = needed_chunks; + if (log) + log->Printf("[3] AllocatedBlock::ReserveBlock(%p) (size = %u " + "(0x%x)) => offset = 0x%x, %u %u bit chunks - " + "num_chunks %lu", + (void *)this, size, size, last_offset, needed_chunks, + m_chunk_size, m_offset_to_chunk_size.size()); + addr = m_addr + last_offset; + break; + } + } + } } - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); - if (log) - log->Printf("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", (void *)this, (uint64_t)addr, - success, m_offset_to_chunk_size.size()); - return success; + // const uint32_t total_chunks = m_allocated.size (); + // uint32_t unallocated_idx = 0; + // uint32_t allocated_idx = m_allocated.find_first(); + // uint32_t first_chunk_idx = UINT32_MAX; + // uint32_t num_chunks; + // while (1) + // { + // if (allocated_idx == UINT32_MAX) + // { + // // No more bits are set starting from unallocated_idx, so + // we + // // either have enough chunks for the request, or we don't. + // // Either way we break out of the while loop... + // num_chunks = total_chunks - unallocated_idx; + // if (needed_chunks <= num_chunks) + // first_chunk_idx = unallocated_idx; + // break; + // } + // else if (allocated_idx > unallocated_idx) + // { + // // We have some allocated chunks, check if there are + // enough + // // free chunks to satisfy the request? + // num_chunks = allocated_idx - unallocated_idx; + // if (needed_chunks <= num_chunks) + // { + // // Yep, we have enough! + // first_chunk_idx = unallocated_idx; + // break; + // } + // } + // + // while (unallocated_idx < total_chunks) + // { + // if (m_allocated[unallocated_idx]) + // ++unallocated_idx; + // else + // break; + // } + // + // if (unallocated_idx >= total_chunks) + // break; + // + // allocated_idx = m_allocated.find_next(unallocated_idx); + // } + // + // if (first_chunk_idx != UINT32_MAX) + // { + // const uint32_t end_bit_idx = unallocated_idx + needed_chunks; + // for (uint32_t idx = first_chunk_idx; idx < end_bit_idx; ++idx) + // m_allocated.set(idx); + // return m_addr + m_chunk_size * first_chunk_idx; + // } + } + + if (log) + log->Printf("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => " + "0x%16.16" PRIx64, + (void *)this, size, size, (uint64_t)addr); + return addr; } -AllocatedMemoryCache::AllocatedMemoryCache(Process &process) : m_process(process), m_mutex(), m_memory_map() -{ +bool AllocatedBlock::FreeBlock(addr_t addr) { + uint32_t offset = addr - m_addr; + OffsetToChunkSize::iterator pos = m_offset_to_chunk_size.find(offset); + bool success = false; + if (pos != m_offset_to_chunk_size.end()) { + m_offset_to_chunk_size.erase(pos); + success = true; + } + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE)); + if (log) + log->Printf("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 + ") => %i, num_chunks: %lu", + (void *)this, (uint64_t)addr, success, + m_offset_to_chunk_size.size()); + return success; } -AllocatedMemoryCache::~AllocatedMemoryCache () -{ -} +AllocatedMemoryCache::AllocatedMemoryCache(Process &process) + : m_process(process), m_mutex(), m_memory_map() {} +AllocatedMemoryCache::~AllocatedMemoryCache() {} -void -AllocatedMemoryCache::Clear() -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_process.IsAlive()) - { - PermissionsToBlockMap::iterator pos, end = m_memory_map.end(); - for (pos = m_memory_map.begin(); pos != end; ++pos) - m_process.DoDeallocateMemory(pos->second->GetBaseAddress()); - } - m_memory_map.clear(); +void AllocatedMemoryCache::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_process.IsAlive()) { + PermissionsToBlockMap::iterator pos, end = m_memory_map.end(); + for (pos = m_memory_map.begin(); pos != end; ++pos) + m_process.DoDeallocateMemory(pos->second->GetBaseAddress()); + } + m_memory_map.clear(); } - AllocatedMemoryCache::AllocatedBlockSP -AllocatedMemoryCache::AllocatePage (uint32_t byte_size, - uint32_t permissions, - uint32_t chunk_size, - Error &error) -{ - AllocatedBlockSP block_sp; - const size_t page_size = 4096; - const size_t num_pages = (byte_size + page_size - 1) / page_size; - const size_t page_byte_size = num_pages * page_size; - - addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error); - - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - { - log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64, - (uint32_t)page_byte_size, - GetPermissionsAsCString(permissions), - (uint64_t)addr); - } - - if (addr != LLDB_INVALID_ADDRESS) - { - block_sp.reset (new AllocatedBlock (addr, page_byte_size, permissions, chunk_size)); - m_memory_map.insert (std::make_pair (permissions, block_sp)); - } - return block_sp; +AllocatedMemoryCache::AllocatePage(uint32_t byte_size, uint32_t permissions, + uint32_t chunk_size, Error &error) { + AllocatedBlockSP block_sp; + const size_t page_size = 4096; + const size_t num_pages = (byte_size + page_size - 1) / page_size; + const size_t page_byte_size = num_pages * page_size; + + addr_t addr = m_process.DoAllocateMemory(page_byte_size, permissions, error); + + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) { + log->Printf("Process::DoAllocateMemory (byte_size = 0x%8.8" PRIx32 + ", permissions = %s) => 0x%16.16" PRIx64, + (uint32_t)page_byte_size, GetPermissionsAsCString(permissions), + (uint64_t)addr); + } + + if (addr != LLDB_INVALID_ADDRESS) { + block_sp.reset( + new AllocatedBlock(addr, page_byte_size, permissions, chunk_size)); + m_memory_map.insert(std::make_pair(permissions, block_sp)); + } + return block_sp; } -lldb::addr_t -AllocatedMemoryCache::AllocateMemory (size_t byte_size, - uint32_t permissions, - Error &error) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - addr_t addr = LLDB_INVALID_ADDRESS; - std::pair<PermissionsToBlockMap::iterator, PermissionsToBlockMap::iterator> range = m_memory_map.equal_range (permissions); +lldb::addr_t AllocatedMemoryCache::AllocateMemory(size_t byte_size, + uint32_t permissions, + Error &error) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); - for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second; ++pos) - { - addr = (*pos).second->ReserveBlock (byte_size); - if (addr != LLDB_INVALID_ADDRESS) - break; - } - - if (addr == LLDB_INVALID_ADDRESS) - { - AllocatedBlockSP block_sp (AllocatePage (byte_size, permissions, 16, error)); + addr_t addr = LLDB_INVALID_ADDRESS; + std::pair<PermissionsToBlockMap::iterator, PermissionsToBlockMap::iterator> + range = m_memory_map.equal_range(permissions); - if (block_sp) - addr = block_sp->ReserveBlock (byte_size); - } - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32 ", permissions = %s) => 0x%16.16" PRIx64, (uint32_t)byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr); - return addr; + for (PermissionsToBlockMap::iterator pos = range.first; pos != range.second; + ++pos) { + addr = (*pos).second->ReserveBlock(byte_size); + if (addr != LLDB_INVALID_ADDRESS) + break; + } + + if (addr == LLDB_INVALID_ADDRESS) { + AllocatedBlockSP block_sp(AllocatePage(byte_size, permissions, 16, error)); + + if (block_sp) + addr = block_sp->ReserveBlock(byte_size); + } + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8" PRIx32 + ", permissions = %s) => 0x%16.16" PRIx64, + (uint32_t)byte_size, GetPermissionsAsCString(permissions), + (uint64_t)addr); + return addr; } -bool -AllocatedMemoryCache::DeallocateMemory (lldb::addr_t addr) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); +bool AllocatedMemoryCache::DeallocateMemory(lldb::addr_t addr) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); - PermissionsToBlockMap::iterator pos, end = m_memory_map.end(); - bool success = false; - for (pos = m_memory_map.begin(); pos != end; ++pos) - { - if (pos->second->Contains (addr)) - { - success = pos->second->FreeBlock (addr); - break; - } + PermissionsToBlockMap::iterator pos, end = m_memory_map.end(); + bool success = false; + for (pos = m_memory_map.begin(); pos != end; ++pos) { + if (pos->second->Contains(addr)) { + success = pos->second->FreeBlock(addr); + break; } - Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16" PRIx64 ") => %i", (uint64_t)addr, success); - return success; + } + Log *log(GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("AllocatedMemoryCache::DeallocateMemory (addr = 0x%16.16" PRIx64 + ") => %i", + (uint64_t)addr, success); + return success; } - - diff --git a/lldb/source/Target/MemoryHistory.cpp b/lldb/source/Target/MemoryHistory.cpp index 33860f868ee..62794279650 100644 --- a/lldb/source/Target/MemoryHistory.cpp +++ b/lldb/source/Target/MemoryHistory.cpp @@ -17,17 +17,17 @@ using namespace lldb; using namespace lldb_private; -lldb::MemoryHistorySP -MemoryHistory::FindPlugin (const ProcessSP process) -{ - MemoryHistoryCreateInstance create_callback = nullptr; - - for (uint32_t idx = 0; (create_callback = PluginManager::GetMemoryHistoryCreateCallbackAtIndex(idx)) != nullptr; ++idx) - { - MemoryHistorySP memory_history_sp (create_callback (process)); - if (memory_history_sp) - return memory_history_sp; - } - - return MemoryHistorySP(); +lldb::MemoryHistorySP MemoryHistory::FindPlugin(const ProcessSP process) { + MemoryHistoryCreateInstance create_callback = nullptr; + + for (uint32_t idx = 0; + (create_callback = PluginManager::GetMemoryHistoryCreateCallbackAtIndex( + idx)) != nullptr; + ++idx) { + MemoryHistorySP memory_history_sp(create_callback(process)); + if (memory_history_sp) + return memory_history_sp; + } + + return MemoryHistorySP(); } diff --git a/lldb/source/Target/ObjCLanguageRuntime.cpp b/lldb/source/Target/ObjCLanguageRuntime.cpp index 8911d9dab35..3ee4dd3ad57 100644 --- a/lldb/source/Target/ObjCLanguageRuntime.cpp +++ b/lldb/source/Target/ObjCLanguageRuntime.cpp @@ -30,414 +30,358 @@ using namespace lldb_private; //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -ObjCLanguageRuntime::~ObjCLanguageRuntime() -{ +ObjCLanguageRuntime::~ObjCLanguageRuntime() {} + +ObjCLanguageRuntime::ObjCLanguageRuntime(Process *process) + : LanguageRuntime(process), m_impl_cache(), + m_has_new_literals_and_indexing(eLazyBoolCalculate), + m_isa_to_descriptor(), m_hash_to_isa_map(), m_type_size_cache(), + m_isa_to_descriptor_stop_id(UINT32_MAX), m_complete_class_cache(), + m_negative_complete_class_cache() {} + +bool ObjCLanguageRuntime::AddClass(ObjCISA isa, + const ClassDescriptorSP &descriptor_sp, + const char *class_name) { + if (isa != 0) { + m_isa_to_descriptor[isa] = descriptor_sp; + // class_name is assumed to be valid + m_hash_to_isa_map.insert( + std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa)); + return true; + } + return false; } -ObjCLanguageRuntime::ObjCLanguageRuntime (Process *process) : - LanguageRuntime (process), - m_impl_cache(), - m_has_new_literals_and_indexing (eLazyBoolCalculate), - m_isa_to_descriptor(), - m_hash_to_isa_map(), - m_type_size_cache(), - m_isa_to_descriptor_stop_id (UINT32_MAX), - m_complete_class_cache(), - m_negative_complete_class_cache() -{ +void ObjCLanguageRuntime::AddToMethodCache(lldb::addr_t class_addr, + lldb::addr_t selector, + lldb::addr_t impl_addr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + log->Printf("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 + " implementation 0x%" PRIx64 ".", + class_addr, selector, impl_addr); + } + m_impl_cache.insert(std::pair<ClassAndSel, lldb::addr_t>( + ClassAndSel(class_addr, selector), impl_addr)); } -bool -ObjCLanguageRuntime::AddClass (ObjCISA isa, const ClassDescriptorSP &descriptor_sp, const char *class_name) -{ - if (isa != 0) - { - m_isa_to_descriptor[isa] = descriptor_sp; - // class_name is assumed to be valid - m_hash_to_isa_map.insert(std::make_pair(MappedHash::HashStringUsingDJB(class_name), isa)); - return true; - } - return false; +lldb::addr_t ObjCLanguageRuntime::LookupInMethodCache(lldb::addr_t class_addr, + lldb::addr_t selector) { + MsgImplMap::iterator pos, end = m_impl_cache.end(); + pos = m_impl_cache.find(ClassAndSel(class_addr, selector)); + if (pos != end) + return (*pos).second; + return LLDB_INVALID_ADDRESS; } -void -ObjCLanguageRuntime::AddToMethodCache (lldb::addr_t class_addr, lldb::addr_t selector, lldb::addr_t impl_addr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - { - log->Printf ("Caching: class 0x%" PRIx64 " selector 0x%" PRIx64 " implementation 0x%" PRIx64 ".", class_addr, selector, impl_addr); - } - m_impl_cache.insert (std::pair<ClassAndSel,lldb::addr_t> (ClassAndSel(class_addr, selector), impl_addr)); -} +lldb::TypeSP +ObjCLanguageRuntime::LookupInCompleteClassCache(ConstString &name) { + CompleteClassMap::iterator complete_class_iter = + m_complete_class_cache.find(name); -lldb::addr_t -ObjCLanguageRuntime::LookupInMethodCache (lldb::addr_t class_addr, lldb::addr_t selector) -{ - MsgImplMap::iterator pos, end = m_impl_cache.end(); - pos = m_impl_cache.find (ClassAndSel(class_addr, selector)); - if (pos != end) - return (*pos).second; - return LLDB_INVALID_ADDRESS; -} + if (complete_class_iter != m_complete_class_cache.end()) { + // Check the weak pointer to make sure the type hasn't been unloaded + TypeSP complete_type_sp(complete_class_iter->second.lock()); + if (complete_type_sp) + return complete_type_sp; + else + m_complete_class_cache.erase(name); + } -lldb::TypeSP -ObjCLanguageRuntime::LookupInCompleteClassCache (ConstString &name) -{ - CompleteClassMap::iterator complete_class_iter = m_complete_class_cache.find(name); - - if (complete_class_iter != m_complete_class_cache.end()) - { - // Check the weak pointer to make sure the type hasn't been unloaded - TypeSP complete_type_sp (complete_class_iter->second.lock()); - - if (complete_type_sp) - return complete_type_sp; - else - m_complete_class_cache.erase(name); - } - - if (m_negative_complete_class_cache.count(name) > 0) - return TypeSP(); - - const ModuleList &modules = m_process->GetTarget().GetImages(); - - SymbolContextList sc_list; - const size_t matching_symbols = modules.FindSymbolsWithNameAndType (name, - eSymbolTypeObjCClass, - sc_list); - - if (matching_symbols) - { - SymbolContext sc; - - sc_list.GetContextAtIndex(0, sc); - - ModuleSP module_sp(sc.module_sp); - - if (!module_sp) - return TypeSP(); - - const SymbolContext null_sc; - const bool exact_match = true; - const uint32_t max_matches = UINT32_MAX; - TypeList types; - - llvm::DenseSet<SymbolFile *> searched_symbol_files; - const uint32_t num_types = module_sp->FindTypes (null_sc, - name, - exact_match, - max_matches, - searched_symbol_files, - types); - - if (num_types) - { - uint32_t i; - for (i = 0; i < num_types; ++i) - { - TypeSP type_sp (types.GetTypeAtIndex(i)); - - if (ClangASTContext::IsObjCObjectOrInterfaceType(type_sp->GetForwardCompilerType ())) - { - if (type_sp->IsCompleteObjCClass()) - { - m_complete_class_cache[name] = type_sp; - return type_sp; - } - } - } + if (m_negative_complete_class_cache.count(name) > 0) + return TypeSP(); + + const ModuleList &modules = m_process->GetTarget().GetImages(); + + SymbolContextList sc_list; + const size_t matching_symbols = + modules.FindSymbolsWithNameAndType(name, eSymbolTypeObjCClass, sc_list); + + if (matching_symbols) { + SymbolContext sc; + + sc_list.GetContextAtIndex(0, sc); + + ModuleSP module_sp(sc.module_sp); + + if (!module_sp) + return TypeSP(); + + const SymbolContext null_sc; + const bool exact_match = true; + const uint32_t max_matches = UINT32_MAX; + TypeList types; + + llvm::DenseSet<SymbolFile *> searched_symbol_files; + const uint32_t num_types = module_sp->FindTypes( + null_sc, name, exact_match, max_matches, searched_symbol_files, types); + + if (num_types) { + uint32_t i; + for (i = 0; i < num_types; ++i) { + TypeSP type_sp(types.GetTypeAtIndex(i)); + + if (ClangASTContext::IsObjCObjectOrInterfaceType( + type_sp->GetForwardCompilerType())) { + if (type_sp->IsCompleteObjCClass()) { + m_complete_class_cache[name] = type_sp; + return type_sp; + } } + } } - m_negative_complete_class_cache.insert(name); - return TypeSP(); + } + m_negative_complete_class_cache.insert(name); + return TypeSP(); } -size_t -ObjCLanguageRuntime::GetByteOffsetForIvar (CompilerType &parent_qual_type, const char *ivar_name) -{ - return LLDB_INVALID_IVAR_OFFSET; +size_t ObjCLanguageRuntime::GetByteOffsetForIvar(CompilerType &parent_qual_type, + const char *ivar_name) { + return LLDB_INVALID_IVAR_OFFSET; } -bool -ObjCLanguageRuntime::ClassDescriptor::IsPointerValid (lldb::addr_t value, - uint32_t ptr_size, - bool allow_NULLs, - bool allow_tagged, - bool check_version_specific) const -{ - if (!value) - return allow_NULLs; - if ( (value % 2) == 1 && allow_tagged) - return true; - if ((value % ptr_size) == 0) - return (check_version_specific ? CheckPointer(value,ptr_size) : true); - else - return false; +bool ObjCLanguageRuntime::ClassDescriptor::IsPointerValid( + lldb::addr_t value, uint32_t ptr_size, bool allow_NULLs, bool allow_tagged, + bool check_version_specific) const { + if (!value) + return allow_NULLs; + if ((value % 2) == 1 && allow_tagged) + return true; + if ((value % ptr_size) == 0) + return (check_version_specific ? CheckPointer(value, ptr_size) : true); + else + return false; } ObjCLanguageRuntime::ObjCISA -ObjCLanguageRuntime::GetISA(const ConstString &name) -{ - ISAToDescriptorIterator pos = GetDescriptorIterator (name); - if (pos != m_isa_to_descriptor.end()) - return pos->first; - return 0; +ObjCLanguageRuntime::GetISA(const ConstString &name) { + ISAToDescriptorIterator pos = GetDescriptorIterator(name); + if (pos != m_isa_to_descriptor.end()) + return pos->first; + return 0; } ObjCLanguageRuntime::ISAToDescriptorIterator -ObjCLanguageRuntime::GetDescriptorIterator (const ConstString &name) -{ - ISAToDescriptorIterator end = m_isa_to_descriptor.end(); - - if (name) - { - UpdateISAToDescriptorMap(); - if (m_hash_to_isa_map.empty()) - { - // No name hashes were provided, we need to just linearly power through the - // names and find a match - for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); pos != end; ++pos) - { - if (pos->second->GetClassName() == name) - return pos; - } - } - else - { - // Name hashes were provided, so use them to efficiently lookup name to isa/descriptor - const uint32_t name_hash = MappedHash::HashStringUsingDJB (name.GetCString()); - std::pair <HashToISAIterator, HashToISAIterator> range = m_hash_to_isa_map.equal_range(name_hash); - for (HashToISAIterator range_pos = range.first; range_pos != range.second; ++range_pos) - { - ISAToDescriptorIterator pos = m_isa_to_descriptor.find (range_pos->second); - if (pos != m_isa_to_descriptor.end()) - { - if (pos->second->GetClassName() == name) - return pos; - } - } +ObjCLanguageRuntime::GetDescriptorIterator(const ConstString &name) { + ISAToDescriptorIterator end = m_isa_to_descriptor.end(); + + if (name) { + UpdateISAToDescriptorMap(); + if (m_hash_to_isa_map.empty()) { + // No name hashes were provided, we need to just linearly power through + // the + // names and find a match + for (ISAToDescriptorIterator pos = m_isa_to_descriptor.begin(); + pos != end; ++pos) { + if (pos->second->GetClassName() == name) + return pos; + } + } else { + // Name hashes were provided, so use them to efficiently lookup name to + // isa/descriptor + const uint32_t name_hash = + MappedHash::HashStringUsingDJB(name.GetCString()); + std::pair<HashToISAIterator, HashToISAIterator> range = + m_hash_to_isa_map.equal_range(name_hash); + for (HashToISAIterator range_pos = range.first; range_pos != range.second; + ++range_pos) { + ISAToDescriptorIterator pos = + m_isa_to_descriptor.find(range_pos->second); + if (pos != m_isa_to_descriptor.end()) { + if (pos->second->GetClassName() == name) + return pos; } + } } - return end; + } + return end; } -std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator,ObjCLanguageRuntime::ISAToDescriptorIterator> -ObjCLanguageRuntime::GetDescriptorIteratorPair (bool update_if_needed) -{ - if (update_if_needed) - UpdateISAToDescriptorMapIfNeeded(); - - return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, - ObjCLanguageRuntime::ISAToDescriptorIterator>( - m_isa_to_descriptor.begin(), - m_isa_to_descriptor.end()); -} +std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, + ObjCLanguageRuntime::ISAToDescriptorIterator> +ObjCLanguageRuntime::GetDescriptorIteratorPair(bool update_if_needed) { + if (update_if_needed) + UpdateISAToDescriptorMapIfNeeded(); + return std::pair<ObjCLanguageRuntime::ISAToDescriptorIterator, + ObjCLanguageRuntime::ISAToDescriptorIterator>( + m_isa_to_descriptor.begin(), m_isa_to_descriptor.end()); +} ObjCLanguageRuntime::ObjCISA -ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) -{ - ClassDescriptorSP objc_class_sp (GetClassDescriptorFromISA(isa)); - if (objc_class_sp) - { - ClassDescriptorSP objc_super_class_sp (objc_class_sp->GetSuperclass()); - if (objc_super_class_sp) - return objc_super_class_sp->GetISA(); - } - return 0; +ObjCLanguageRuntime::GetParentClass(ObjCLanguageRuntime::ObjCISA isa) { + ClassDescriptorSP objc_class_sp(GetClassDescriptorFromISA(isa)); + if (objc_class_sp) { + ClassDescriptorSP objc_super_class_sp(objc_class_sp->GetSuperclass()); + if (objc_super_class_sp) + return objc_super_class_sp->GetISA(); + } + return 0; } ConstString -ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) -{ - ClassDescriptorSP objc_class_sp (GetNonKVOClassDescriptor(isa)); - if (objc_class_sp) - return objc_class_sp->GetClassName(); - return ConstString(); +ObjCLanguageRuntime::GetActualTypeName(ObjCLanguageRuntime::ObjCISA isa) { + ClassDescriptorSP objc_class_sp(GetNonKVOClassDescriptor(isa)); + if (objc_class_sp) + return objc_class_sp->GetClassName(); + return ConstString(); } ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetClassDescriptorFromClassName (const ConstString &class_name) -{ - ISAToDescriptorIterator pos = GetDescriptorIterator (class_name); - if (pos != m_isa_to_descriptor.end()) - return pos->second; - return ClassDescriptorSP(); - +ObjCLanguageRuntime::GetClassDescriptorFromClassName( + const ConstString &class_name) { + ISAToDescriptorIterator pos = GetDescriptorIterator(class_name); + if (pos != m_isa_to_descriptor.end()) + return pos->second; + return ClassDescriptorSP(); } ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetClassDescriptor (ValueObject& valobj) -{ - ClassDescriptorSP objc_class_sp; - // if we get an invalid VO (which might still happen when playing around - // with pointers returned by the expression parser, don't consider this - // a valid ObjC object) - if (valobj.GetCompilerType().IsValid()) - { - addr_t isa_pointer = valobj.GetPointerValue(); - if (isa_pointer != LLDB_INVALID_ADDRESS) - { - ExecutionContext exe_ctx (valobj.GetExecutionContextRef()); - - Process *process = exe_ctx.GetProcessPtr(); - if (process) - { - Error error; - ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); - if (isa != LLDB_INVALID_ADDRESS) - objc_class_sp = GetClassDescriptorFromISA (isa); - } - } +ObjCLanguageRuntime::GetClassDescriptor(ValueObject &valobj) { + ClassDescriptorSP objc_class_sp; + // if we get an invalid VO (which might still happen when playing around + // with pointers returned by the expression parser, don't consider this + // a valid ObjC object) + if (valobj.GetCompilerType().IsValid()) { + addr_t isa_pointer = valobj.GetPointerValue(); + if (isa_pointer != LLDB_INVALID_ADDRESS) { + ExecutionContext exe_ctx(valobj.GetExecutionContextRef()); + + Process *process = exe_ctx.GetProcessPtr(); + if (process) { + Error error; + ObjCISA isa = process->ReadPointerFromMemory(isa_pointer, error); + if (isa != LLDB_INVALID_ADDRESS) + objc_class_sp = GetClassDescriptorFromISA(isa); + } } - return objc_class_sp; + } + return objc_class_sp; } ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetNonKVOClassDescriptor (ValueObject& valobj) -{ - ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp (GetClassDescriptor (valobj)); - if (objc_class_sp) - { - if (!objc_class_sp->IsKVO()) - return objc_class_sp; - - ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); - if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) - return non_kvo_objc_class_sp; - } - return ClassDescriptorSP(); +ObjCLanguageRuntime::GetNonKVOClassDescriptor(ValueObject &valobj) { + ObjCLanguageRuntime::ClassDescriptorSP objc_class_sp( + GetClassDescriptor(valobj)); + if (objc_class_sp) { + if (!objc_class_sp->IsKVO()) + return objc_class_sp; + + ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); + if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) + return non_kvo_objc_class_sp; + } + return ClassDescriptorSP(); } - ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetClassDescriptorFromISA (ObjCISA isa) -{ - if (isa) - { - UpdateISAToDescriptorMap(); - ObjCLanguageRuntime::ISAToDescriptorIterator pos = m_isa_to_descriptor.find(isa); - if (pos != m_isa_to_descriptor.end()) - return pos->second; - } - return ClassDescriptorSP(); +ObjCLanguageRuntime::GetClassDescriptorFromISA(ObjCISA isa) { + if (isa) { + UpdateISAToDescriptorMap(); + ObjCLanguageRuntime::ISAToDescriptorIterator pos = + m_isa_to_descriptor.find(isa); + if (pos != m_isa_to_descriptor.end()) + return pos->second; + } + return ClassDescriptorSP(); } ObjCLanguageRuntime::ClassDescriptorSP -ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa) -{ - if (isa) - { - ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA (isa); - if (objc_class_sp && objc_class_sp->IsValid()) - { - if (!objc_class_sp->IsKVO()) - return objc_class_sp; - - ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); - if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) - return non_kvo_objc_class_sp; - } +ObjCLanguageRuntime::GetNonKVOClassDescriptor(ObjCISA isa) { + if (isa) { + ClassDescriptorSP objc_class_sp = GetClassDescriptorFromISA(isa); + if (objc_class_sp && objc_class_sp->IsValid()) { + if (!objc_class_sp->IsKVO()) + return objc_class_sp; + + ClassDescriptorSP non_kvo_objc_class_sp(objc_class_sp->GetSuperclass()); + if (non_kvo_objc_class_sp && non_kvo_objc_class_sp->IsValid()) + return non_kvo_objc_class_sp; } - return ClassDescriptorSP(); + } + return ClassDescriptorSP(); } - CompilerType -ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool for_expression) -{ - if (m_scratch_ast_ctx_ap) - return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression); - return CompilerType(); +ObjCLanguageRuntime::EncodingToType::RealizeType(const char *name, + bool for_expression) { + if (m_scratch_ast_ctx_ap) + return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression); + return CompilerType(); } -CompilerType -ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression) -{ - clang::ASTContext *clang_ast = ast_ctx.getASTContext(); - if (!clang_ast) - return CompilerType(); - return RealizeType(*clang_ast, name, for_expression); +CompilerType ObjCLanguageRuntime::EncodingToType::RealizeType( + ClangASTContext &ast_ctx, const char *name, bool for_expression) { + clang::ASTContext *clang_ast = ast_ctx.getASTContext(); + if (!clang_ast) + return CompilerType(); + return RealizeType(*clang_ast, name, for_expression); } ObjCLanguageRuntime::EncodingToType::~EncodingToType() {} -ObjCLanguageRuntime::EncodingToTypeSP -ObjCLanguageRuntime::GetEncodingToType () -{ - return nullptr; +ObjCLanguageRuntime::EncodingToTypeSP ObjCLanguageRuntime::GetEncodingToType() { + return nullptr; } -bool -ObjCLanguageRuntime::GetTypeBitSize (const CompilerType& compiler_type, - uint64_t &size) -{ - void *opaque_ptr = compiler_type.GetOpaqueQualType(); - size = m_type_size_cache.Lookup(opaque_ptr); - // an ObjC object will at least have an ISA, so 0 is definitely not OK - if (size > 0) - return true; - - ClassDescriptorSP class_descriptor_sp = GetClassDescriptorFromClassName(compiler_type.GetTypeName()); - if (!class_descriptor_sp) - return false; - - int32_t max_offset = INT32_MIN; - uint64_t sizeof_max = 0; - bool found = false; - - for (size_t idx = 0; - idx < class_descriptor_sp->GetNumIVars(); - idx++) - { - const auto& ivar = class_descriptor_sp->GetIVarAtIndex(idx); - int32_t cur_offset = ivar.m_offset; - if (cur_offset > max_offset) - { - max_offset = cur_offset; - sizeof_max = ivar.m_size; - found = true; - } +bool ObjCLanguageRuntime::GetTypeBitSize(const CompilerType &compiler_type, + uint64_t &size) { + void *opaque_ptr = compiler_type.GetOpaqueQualType(); + size = m_type_size_cache.Lookup(opaque_ptr); + // an ObjC object will at least have an ISA, so 0 is definitely not OK + if (size > 0) + return true; + + ClassDescriptorSP class_descriptor_sp = + GetClassDescriptorFromClassName(compiler_type.GetTypeName()); + if (!class_descriptor_sp) + return false; + + int32_t max_offset = INT32_MIN; + uint64_t sizeof_max = 0; + bool found = false; + + for (size_t idx = 0; idx < class_descriptor_sp->GetNumIVars(); idx++) { + const auto &ivar = class_descriptor_sp->GetIVarAtIndex(idx); + int32_t cur_offset = ivar.m_offset; + if (cur_offset > max_offset) { + max_offset = cur_offset; + sizeof_max = ivar.m_size; + found = true; } - - size = 8 * (max_offset + sizeof_max); - if (found) - m_type_size_cache.Insert(opaque_ptr, size); - - return found; + } + + size = 8 * (max_offset + sizeof_max); + if (found) + m_type_size_cache.Insert(opaque_ptr, size); + + return found; } //------------------------------------------------------------------ // Exception breakpoint Precondition class for ObjC: //------------------------------------------------------------------ -void -ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName(const char *class_name) -{ - m_class_names.insert(class_name); +void ObjCLanguageRuntime::ObjCExceptionPrecondition::AddClassName( + const char *class_name) { + m_class_names.insert(class_name); } -ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() -{ -} +ObjCLanguageRuntime::ObjCExceptionPrecondition::ObjCExceptionPrecondition() {} -bool -ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition(StoppointCallbackContext &context) -{ - return true; +bool ObjCLanguageRuntime::ObjCExceptionPrecondition::EvaluatePrecondition( + StoppointCallbackContext &context) { + return true; } -void -ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription(Stream &stream, lldb::DescriptionLevel level) -{ -} +void ObjCLanguageRuntime::ObjCExceptionPrecondition::GetDescription( + Stream &stream, lldb::DescriptionLevel level) {} -Error -ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition(Args &args) -{ - Error error; - if (args.GetArgumentCount() > 0) - error.SetErrorString("The ObjC Exception breakpoint doesn't support extra options."); - return error; +Error ObjCLanguageRuntime::ObjCExceptionPrecondition::ConfigurePrecondition( + Args &args) { + Error error; + if (args.GetArgumentCount() > 0) + error.SetErrorString( + "The ObjC Exception breakpoint doesn't support extra options."); + return error; } diff --git a/lldb/source/Target/OperatingSystem.cpp b/lldb/source/Target/OperatingSystem.cpp index 9b4f2120bef..7a1d9d61987 100644 --- a/lldb/source/Target/OperatingSystem.cpp +++ b/lldb/source/Target/OperatingSystem.cpp @@ -18,45 +18,42 @@ using namespace lldb; using namespace lldb_private; -OperatingSystem* -OperatingSystem::FindPlugin (Process *process, const char *plugin_name) -{ - OperatingSystemCreateInstance create_callback = nullptr; - if (plugin_name) - { - ConstString const_plugin_name(plugin_name); - create_callback = PluginManager::GetOperatingSystemCreateCallbackForPluginName (const_plugin_name); - if (create_callback) - { - std::unique_ptr<OperatingSystem> instance_ap(create_callback(process, true)); - if (instance_ap) - return instance_ap.release(); - } +OperatingSystem *OperatingSystem::FindPlugin(Process *process, + const char *plugin_name) { + OperatingSystemCreateInstance create_callback = nullptr; + if (plugin_name) { + ConstString const_plugin_name(plugin_name); + create_callback = + PluginManager::GetOperatingSystemCreateCallbackForPluginName( + const_plugin_name); + if (create_callback) { + std::unique_ptr<OperatingSystem> instance_ap( + create_callback(process, true)); + if (instance_ap) + return instance_ap.release(); } - else - { - for (uint32_t idx = 0; (create_callback = PluginManager::GetOperatingSystemCreateCallbackAtIndex(idx)) != nullptr; ++idx) - { - std::unique_ptr<OperatingSystem> instance_ap(create_callback(process, false)); - if (instance_ap) - return instance_ap.release(); - } + } else { + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetOperatingSystemCreateCallbackAtIndex(idx)) != + nullptr; + ++idx) { + std::unique_ptr<OperatingSystem> instance_ap( + create_callback(process, false)); + if (instance_ap) + return instance_ap.release(); } - return nullptr; + } + return nullptr; } - -OperatingSystem::OperatingSystem (Process *process) : - m_process (process) -{ -} +OperatingSystem::OperatingSystem(Process *process) : m_process(process) {} OperatingSystem::~OperatingSystem() = default; -bool -OperatingSystem::IsOperatingSystemPluginThread (const lldb::ThreadSP &thread_sp) -{ - if (thread_sp) - return thread_sp->IsOperatingSystemPluginThread(); - return false; +bool OperatingSystem::IsOperatingSystemPluginThread( + const lldb::ThreadSP &thread_sp) { + if (thread_sp) + return thread_sp->IsOperatingSystemPluginThread(); + return false; } diff --git a/lldb/source/Target/PathMappingList.cpp b/lldb/source/Target/PathMappingList.cpp index bc1334aca46..4df3a185471 100644 --- a/lldb/source/Target/PathMappingList.cpp +++ b/lldb/source/Target/PathMappingList.cpp @@ -26,331 +26,265 @@ using namespace lldb_private; //---------------------------------------------------------------------- // PathMappingList constructor //---------------------------------------------------------------------- -PathMappingList::PathMappingList () : - m_pairs(), - m_callback(nullptr), - m_callback_baton(nullptr), - m_mod_id(0) -{ -} +PathMappingList::PathMappingList() + : m_pairs(), m_callback(nullptr), m_callback_baton(nullptr), m_mod_id(0) {} -PathMappingList::PathMappingList (ChangedCallback callback, - void *callback_baton) : - m_pairs (), - m_callback (callback), - m_callback_baton (callback_baton), - m_mod_id (0) -{ -} +PathMappingList::PathMappingList(ChangedCallback callback, void *callback_baton) + : m_pairs(), m_callback(callback), m_callback_baton(callback_baton), + m_mod_id(0) {} -PathMappingList::PathMappingList (const PathMappingList &rhs) : - m_pairs(rhs.m_pairs), - m_callback(nullptr), - m_callback_baton(nullptr), - m_mod_id(0) -{ -} +PathMappingList::PathMappingList(const PathMappingList &rhs) + : m_pairs(rhs.m_pairs), m_callback(nullptr), m_callback_baton(nullptr), + m_mod_id(0) {} -const PathMappingList & -PathMappingList::operator =(const PathMappingList &rhs) -{ - if (this != &rhs) - { - m_pairs = rhs.m_pairs; - m_callback = nullptr; - m_callback_baton = nullptr; - m_mod_id = rhs.m_mod_id; - } - return *this; +const PathMappingList &PathMappingList::operator=(const PathMappingList &rhs) { + if (this != &rhs) { + m_pairs = rhs.m_pairs; + m_callback = nullptr; + m_callback_baton = nullptr; + m_mod_id = rhs.m_mod_id; + } + return *this; } PathMappingList::~PathMappingList() = default; -void -PathMappingList::Append (const ConstString &path, - const ConstString &replacement, - bool notify) -{ - ++m_mod_id; - m_pairs.push_back(pair(path, replacement)); - if (notify && m_callback) - m_callback (*this, m_callback_baton); +void PathMappingList::Append(const ConstString &path, + const ConstString &replacement, bool notify) { + ++m_mod_id; + m_pairs.push_back(pair(path, replacement)); + if (notify && m_callback) + m_callback(*this, m_callback_baton); } -void -PathMappingList::Append (const PathMappingList &rhs, bool notify) -{ - ++m_mod_id; - if (!rhs.m_pairs.empty()) - { - const_iterator pos, end = rhs.m_pairs.end(); - for (pos = rhs.m_pairs.begin(); pos != end; ++pos) - m_pairs.push_back(*pos); - if (notify && m_callback) - m_callback (*this, m_callback_baton); - } +void PathMappingList::Append(const PathMappingList &rhs, bool notify) { + ++m_mod_id; + if (!rhs.m_pairs.empty()) { + const_iterator pos, end = rhs.m_pairs.end(); + for (pos = rhs.m_pairs.begin(); pos != end; ++pos) + m_pairs.push_back(*pos); + if (notify && m_callback) + m_callback(*this, m_callback_baton); + } } -void -PathMappingList::Insert (const ConstString &path, - const ConstString &replacement, - uint32_t index, - bool notify) -{ - ++m_mod_id; - iterator insert_iter; - if (index >= m_pairs.size()) - insert_iter = m_pairs.end(); - else - insert_iter = m_pairs.begin() + index; - m_pairs.insert(insert_iter, pair(path, replacement)); - if (notify && m_callback) - m_callback (*this, m_callback_baton); +void PathMappingList::Insert(const ConstString &path, + const ConstString &replacement, uint32_t index, + bool notify) { + ++m_mod_id; + iterator insert_iter; + if (index >= m_pairs.size()) + insert_iter = m_pairs.end(); + else + insert_iter = m_pairs.begin() + index; + m_pairs.insert(insert_iter, pair(path, replacement)); + if (notify && m_callback) + m_callback(*this, m_callback_baton); } -bool -PathMappingList::Replace (const ConstString &path, - const ConstString &replacement, - uint32_t index, - bool notify) -{ - iterator insert_iter; - if (index >= m_pairs.size()) - return false; - ++m_mod_id; - m_pairs[index] = pair(path, replacement); - if (notify && m_callback) - m_callback (*this, m_callback_baton); - return true; +bool PathMappingList::Replace(const ConstString &path, + const ConstString &replacement, uint32_t index, + bool notify) { + iterator insert_iter; + if (index >= m_pairs.size()) + return false; + ++m_mod_id; + m_pairs[index] = pair(path, replacement); + if (notify && m_callback) + m_callback(*this, m_callback_baton); + return true; } -bool -PathMappingList::Remove (size_t index, bool notify) -{ - if (index >= m_pairs.size()) - return false; +bool PathMappingList::Remove(size_t index, bool notify) { + if (index >= m_pairs.size()) + return false; - ++m_mod_id; - iterator iter = m_pairs.begin() + index; - m_pairs.erase(iter); - if (notify && m_callback) - m_callback (*this, m_callback_baton); - return true; + ++m_mod_id; + iterator iter = m_pairs.begin() + index; + m_pairs.erase(iter); + if (notify && m_callback) + m_callback(*this, m_callback_baton); + return true; } // For clients which do not need the pair index dumped, pass a pair_index >= 0 // to only dump the indicated pair. -void -PathMappingList::Dump (Stream *s, int pair_index) -{ - unsigned int numPairs = m_pairs.size(); - - if (pair_index < 0) - { - unsigned int index; - for (index = 0; index < numPairs; ++index) - s->Printf("[%d] \"%s\" -> \"%s\"\n", - index, m_pairs[index].first.GetCString(), m_pairs[index].second.GetCString()); - } - else - { - if (static_cast<unsigned int>(pair_index) < numPairs) - s->Printf("%s -> %s", - m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString()); - } +void PathMappingList::Dump(Stream *s, int pair_index) { + unsigned int numPairs = m_pairs.size(); + + if (pair_index < 0) { + unsigned int index; + for (index = 0; index < numPairs; ++index) + s->Printf("[%d] \"%s\" -> \"%s\"\n", index, + m_pairs[index].first.GetCString(), + m_pairs[index].second.GetCString()); + } else { + if (static_cast<unsigned int>(pair_index) < numPairs) + s->Printf("%s -> %s", m_pairs[pair_index].first.GetCString(), + m_pairs[pair_index].second.GetCString()); + } } -void -PathMappingList::Clear (bool notify) -{ - if (!m_pairs.empty()) - ++m_mod_id; - m_pairs.clear(); - if (notify && m_callback) - m_callback (*this, m_callback_baton); +void PathMappingList::Clear(bool notify) { + if (!m_pairs.empty()) + ++m_mod_id; + m_pairs.clear(); + if (notify && m_callback) + m_callback(*this, m_callback_baton); } -bool -PathMappingList::RemapPath (const ConstString &path, ConstString &new_path) const -{ - const char *path_cstr = path.GetCString(); - - if (!path_cstr) - return false; - - const_iterator pos, end = m_pairs.end(); - for (pos = m_pairs.begin(); pos != end; ++pos) - { - const size_t prefixLen = pos->first.GetLength(); - - if (::strncmp (pos->first.GetCString(), path_cstr, prefixLen) == 0) - { - std::string new_path_str (pos->second.GetCString()); - new_path_str.append(path.GetCString() + prefixLen); - new_path.SetCString(new_path_str.c_str()); - return true; - } - } +bool PathMappingList::RemapPath(const ConstString &path, + ConstString &new_path) const { + const char *path_cstr = path.GetCString(); + + if (!path_cstr) return false; -} -bool -PathMappingList::RemapPath (const char *path, std::string &new_path) const -{ - if (m_pairs.empty() || path == nullptr || path[0] == '\0') - return false; + const_iterator pos, end = m_pairs.end(); + for (pos = m_pairs.begin(); pos != end; ++pos) { + const size_t prefixLen = pos->first.GetLength(); - const_iterator pos, end = m_pairs.end(); - for (pos = m_pairs.begin(); pos != end; ++pos) - { - const size_t prefix_len = pos->first.GetLength(); - - if (::strncmp (pos->first.GetCString(), path, prefix_len) == 0) - { - new_path = pos->second.GetCString(); - new_path.append(path + prefix_len); - return true; - } + if (::strncmp(pos->first.GetCString(), path_cstr, prefixLen) == 0) { + std::string new_path_str(pos->second.GetCString()); + new_path_str.append(path.GetCString() + prefixLen); + new_path.SetCString(new_path_str.c_str()); + return true; } - return false; + } + return false; } -bool -PathMappingList::ReverseRemapPath (const ConstString &path, ConstString &new_path) const -{ - const char *path_cstr = path.GetCString(); - if (!path_cstr) - return false; - - for (const auto& it : m_pairs) - { - // FIXME: This should be using FileSpec API's to do the path appending. - const size_t prefixLen = it.second.GetLength(); - if (::strncmp (it.second.GetCString(), path_cstr, prefixLen) == 0) - { - std::string new_path_str (it.first.GetCString()); - new_path_str.append(path.GetCString() + prefixLen); - new_path.SetCString(new_path_str.c_str()); - return true; - } +bool PathMappingList::RemapPath(const char *path, std::string &new_path) const { + if (m_pairs.empty() || path == nullptr || path[0] == '\0') + return false; + + const_iterator pos, end = m_pairs.end(); + for (pos = m_pairs.begin(); pos != end; ++pos) { + const size_t prefix_len = pos->first.GetLength(); + + if (::strncmp(pos->first.GetCString(), path, prefix_len) == 0) { + new_path = pos->second.GetCString(); + new_path.append(path + prefix_len); + return true; } + } + return false; +} + +bool PathMappingList::ReverseRemapPath(const ConstString &path, + ConstString &new_path) const { + const char *path_cstr = path.GetCString(); + if (!path_cstr) return false; + + for (const auto &it : m_pairs) { + // FIXME: This should be using FileSpec API's to do the path appending. + const size_t prefixLen = it.second.GetLength(); + if (::strncmp(it.second.GetCString(), path_cstr, prefixLen) == 0) { + std::string new_path_str(it.first.GetCString()); + new_path_str.append(path.GetCString() + prefixLen); + new_path.SetCString(new_path_str.c_str()); + return true; + } + } + return false; } -bool -PathMappingList::FindFile (const FileSpec &orig_spec, FileSpec &new_spec) const -{ - if (!m_pairs.empty()) - { - char orig_path[PATH_MAX]; - const size_t orig_path_len = orig_spec.GetPath (orig_path, sizeof(orig_path)); - if (orig_path_len > 0) - { - const_iterator pos, end = m_pairs.end(); - for (pos = m_pairs.begin(); pos != end; ++pos) - { - const size_t prefix_len = pos->first.GetLength(); - - if (orig_path_len >= prefix_len) - { - if (::strncmp (pos->first.GetCString(), orig_path, prefix_len) == 0) - { - new_spec.SetFile(pos->second.GetCString(), false); - new_spec.AppendPathComponent(orig_path+prefix_len); - if (new_spec.Exists()) - return true; - } - } - } +bool PathMappingList::FindFile(const FileSpec &orig_spec, + FileSpec &new_spec) const { + if (!m_pairs.empty()) { + char orig_path[PATH_MAX]; + const size_t orig_path_len = + orig_spec.GetPath(orig_path, sizeof(orig_path)); + if (orig_path_len > 0) { + const_iterator pos, end = m_pairs.end(); + for (pos = m_pairs.begin(); pos != end; ++pos) { + const size_t prefix_len = pos->first.GetLength(); + + if (orig_path_len >= prefix_len) { + if (::strncmp(pos->first.GetCString(), orig_path, prefix_len) == 0) { + new_spec.SetFile(pos->second.GetCString(), false); + new_spec.AppendPathComponent(orig_path + prefix_len); + if (new_spec.Exists()) + return true; + } } + } } - new_spec.Clear(); - return false; + } + new_spec.Clear(); + return false; } -bool -PathMappingList::Replace (const ConstString &path, const ConstString &new_path, bool notify) -{ - uint32_t idx = FindIndexForPath (path); - if (idx < m_pairs.size()) - { - ++m_mod_id; - m_pairs[idx].second = new_path; - if (notify && m_callback) - m_callback (*this, m_callback_baton); - return true; - } - return false; +bool PathMappingList::Replace(const ConstString &path, + const ConstString &new_path, bool notify) { + uint32_t idx = FindIndexForPath(path); + if (idx < m_pairs.size()) { + ++m_mod_id; + m_pairs[idx].second = new_path; + if (notify && m_callback) + m_callback(*this, m_callback_baton); + return true; + } + return false; } -bool -PathMappingList::Remove (const ConstString &path, bool notify) -{ - iterator pos = FindIteratorForPath (path); - if (pos != m_pairs.end()) - { - ++m_mod_id; - m_pairs.erase (pos); - if (notify && m_callback) - m_callback (*this, m_callback_baton); - return true; - } - return false; +bool PathMappingList::Remove(const ConstString &path, bool notify) { + iterator pos = FindIteratorForPath(path); + if (pos != m_pairs.end()) { + ++m_mod_id; + m_pairs.erase(pos); + if (notify && m_callback) + m_callback(*this, m_callback_baton); + return true; + } + return false; } PathMappingList::const_iterator -PathMappingList::FindIteratorForPath (const ConstString &path) const -{ - const_iterator pos; - const_iterator begin = m_pairs.begin(); - const_iterator end = m_pairs.end(); - - for (pos = begin; pos != end; ++pos) - { - if (pos->first == path) - break; - } - return pos; +PathMappingList::FindIteratorForPath(const ConstString &path) const { + const_iterator pos; + const_iterator begin = m_pairs.begin(); + const_iterator end = m_pairs.end(); + + for (pos = begin; pos != end; ++pos) { + if (pos->first == path) + break; + } + return pos; } PathMappingList::iterator -PathMappingList::FindIteratorForPath (const ConstString &path) -{ - iterator pos; - iterator begin = m_pairs.begin(); - iterator end = m_pairs.end(); - - for (pos = begin; pos != end; ++pos) - { - if (pos->first == path) - break; - } - return pos; +PathMappingList::FindIteratorForPath(const ConstString &path) { + iterator pos; + iterator begin = m_pairs.begin(); + iterator end = m_pairs.end(); + + for (pos = begin; pos != end; ++pos) { + if (pos->first == path) + break; + } + return pos; } -bool -PathMappingList::GetPathsAtIndex (uint32_t idx, ConstString &path, ConstString &new_path) const -{ - if (idx < m_pairs.size()) - { - path = m_pairs[idx].first; - new_path = m_pairs[idx].second; - return true; - } - return false; +bool PathMappingList::GetPathsAtIndex(uint32_t idx, ConstString &path, + ConstString &new_path) const { + if (idx < m_pairs.size()) { + path = m_pairs[idx].first; + new_path = m_pairs[idx].second; + return true; + } + return false; } -uint32_t -PathMappingList::FindIndexForPath (const ConstString &path) const -{ - const_iterator pos; - const_iterator begin = m_pairs.begin(); - const_iterator end = m_pairs.end(); - - for (pos = begin; pos != end; ++pos) - { - if (pos->first == path) - return std::distance (begin, pos); - } - return UINT32_MAX; +uint32_t PathMappingList::FindIndexForPath(const ConstString &path) const { + const_iterator pos; + const_iterator begin = m_pairs.begin(); + const_iterator end = m_pairs.end(); + + for (pos = begin; pos != end; ++pos) { + if (pos->first == path) + return std::distance(begin, pos); + } + return UINT32_MAX; } diff --git a/lldb/source/Target/Platform.cpp b/lldb/source/Target/Platform.cpp index 884c9b2cbcd..6b0e0989cc4 100644 --- a/lldb/source/Target/Platform.cpp +++ b/lldb/source/Target/Platform.cpp @@ -18,7 +18,7 @@ #include "llvm/Support/Path.h" // Project includes -#include "lldb/Target/Platform.h" +#include "Utility/ModuleCache.h" #include "lldb/Breakpoint/BreakpointIDList.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/DataBufferHeap.h" @@ -37,11 +37,11 @@ #include "lldb/Interpreter/OptionValueProperties.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ObjectFile.h" +#include "lldb/Target/Platform.h" #include "lldb/Target/Process.h" #include "lldb/Target/Target.h" #include "lldb/Target/UnixSignals.h" #include "lldb/Utility/Utils.h" -#include "Utility/ModuleCache.h" // Define these constants from POSIX mman.h rather than include the file // so that they will be correct even when compiled on Linux. @@ -55,92 +55,72 @@ static uint32_t g_initialize_count = 0; // Use a singleton function for g_local_platform_sp to avoid init // constructors since LLDB is often part of a shared library -static PlatformSP& -GetHostPlatformSP () -{ - static PlatformSP g_platform_sp; - return g_platform_sp; +static PlatformSP &GetHostPlatformSP() { + static PlatformSP g_platform_sp; + return g_platform_sp; } -const char * -Platform::GetHostPlatformName () -{ - return "host"; -} +const char *Platform::GetHostPlatformName() { return "host"; } namespace { - PropertyDefinition - g_properties[] = - { - { "use-module-cache" , OptionValue::eTypeBoolean , true, true, nullptr, nullptr, "Use module cache." }, - { "module-cache-directory", OptionValue::eTypeFileSpec, true, 0 , nullptr, nullptr, "Root directory for cached modules." }, - { nullptr , OptionValue::eTypeInvalid , false, 0, nullptr, nullptr, nullptr } - }; - - enum - { - ePropertyUseModuleCache, - ePropertyModuleCacheDirectory - }; +PropertyDefinition g_properties[] = { + {"use-module-cache", OptionValue::eTypeBoolean, true, true, nullptr, + nullptr, "Use module cache."}, + {"module-cache-directory", OptionValue::eTypeFileSpec, true, 0, nullptr, + nullptr, "Root directory for cached modules."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; -} // namespace +enum { ePropertyUseModuleCache, ePropertyModuleCacheDirectory }; +} // namespace -ConstString -PlatformProperties::GetSettingName () -{ - static ConstString g_setting_name("platform"); - return g_setting_name; +ConstString PlatformProperties::GetSettingName() { + static ConstString g_setting_name("platform"); + return g_setting_name; } -PlatformProperties::PlatformProperties () -{ - m_collection_sp.reset (new OptionValueProperties (GetSettingName ())); - m_collection_sp->Initialize (g_properties); +PlatformProperties::PlatformProperties() { + m_collection_sp.reset(new OptionValueProperties(GetSettingName())); + m_collection_sp->Initialize(g_properties); - auto module_cache_dir = GetModuleCacheDirectory (); - if (module_cache_dir) - return; + auto module_cache_dir = GetModuleCacheDirectory(); + if (module_cache_dir) + return; - llvm::SmallString<64> user_home_dir; - if (!llvm::sys::path::home_directory (user_home_dir)) - return; + llvm::SmallString<64> user_home_dir; + if (!llvm::sys::path::home_directory(user_home_dir)) + return; - module_cache_dir = FileSpec (user_home_dir.c_str(), false); - module_cache_dir.AppendPathComponent (".lldb"); - module_cache_dir.AppendPathComponent ("module_cache"); - SetModuleCacheDirectory (module_cache_dir); + module_cache_dir = FileSpec(user_home_dir.c_str(), false); + module_cache_dir.AppendPathComponent(".lldb"); + module_cache_dir.AppendPathComponent("module_cache"); + SetModuleCacheDirectory(module_cache_dir); } -bool -PlatformProperties::GetUseModuleCache () const -{ - const auto idx = ePropertyUseModuleCache; - return m_collection_sp->GetPropertyAtIndexAsBoolean ( - nullptr, idx, g_properties[idx].default_uint_value != 0); +bool PlatformProperties::GetUseModuleCache() const { + const auto idx = ePropertyUseModuleCache; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -PlatformProperties::SetUseModuleCache (bool use_module_cache) -{ - return m_collection_sp->SetPropertyAtIndexAsBoolean (nullptr, ePropertyUseModuleCache, use_module_cache); +bool PlatformProperties::SetUseModuleCache(bool use_module_cache) { + return m_collection_sp->SetPropertyAtIndexAsBoolean( + nullptr, ePropertyUseModuleCache, use_module_cache); } -FileSpec -PlatformProperties::GetModuleCacheDirectory () const -{ - return m_collection_sp->GetPropertyAtIndexAsFileSpec (nullptr, ePropertyModuleCacheDirectory); +FileSpec PlatformProperties::GetModuleCacheDirectory() const { + return m_collection_sp->GetPropertyAtIndexAsFileSpec( + nullptr, ePropertyModuleCacheDirectory); } -bool -PlatformProperties::SetModuleCacheDirectory (const FileSpec& dir_spec) -{ - return m_collection_sp->SetPropertyAtIndexAsFileSpec (nullptr, ePropertyModuleCacheDirectory, dir_spec); +bool PlatformProperties::SetModuleCacheDirectory(const FileSpec &dir_spec) { + return m_collection_sp->SetPropertyAtIndexAsFileSpec( + nullptr, ePropertyModuleCacheDirectory, dir_spec); } //------------------------------------------------------------------ -/// Get the native host platform plug-in. +/// Get the native host platform plug-in. /// /// There should only be one of these for each host that LLDB runs /// upon that should be statically compiled in and registered using @@ -149,89 +129,66 @@ PlatformProperties::SetModuleCacheDirectory (const FileSpec& dir_spec) /// This platform will be used as the default platform when launching /// or attaching to processes unless another platform is specified. //------------------------------------------------------------------ -PlatformSP -Platform::GetHostPlatform () -{ - return GetHostPlatformSP (); -} +PlatformSP Platform::GetHostPlatform() { return GetHostPlatformSP(); } -static std::vector<PlatformSP> & -GetPlatformList() -{ - static std::vector<PlatformSP> g_platform_list; - return g_platform_list; +static std::vector<PlatformSP> &GetPlatformList() { + static std::vector<PlatformSP> g_platform_list; + return g_platform_list; } -static std::recursive_mutex & -GetPlatformListMutex() -{ - static std::recursive_mutex g_mutex; - return g_mutex; +static std::recursive_mutex &GetPlatformListMutex() { + static std::recursive_mutex g_mutex; + return g_mutex; } -void -Platform::Initialize () -{ - g_initialize_count++; -} +void Platform::Initialize() { g_initialize_count++; } -void -Platform::Terminate () -{ - if (g_initialize_count > 0) - { - if (--g_initialize_count == 0) - { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().clear(); - } +void Platform::Terminate() { + if (g_initialize_count > 0) { + if (--g_initialize_count == 0) { + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + GetPlatformList().clear(); } + } } -const PlatformPropertiesSP & -Platform::GetGlobalPlatformProperties () -{ - static const auto g_settings_sp (std::make_shared<PlatformProperties> ()); - return g_settings_sp; +const PlatformPropertiesSP &Platform::GetGlobalPlatformProperties() { + static const auto g_settings_sp(std::make_shared<PlatformProperties>()); + return g_settings_sp; } -void -Platform::SetHostPlatform (const lldb::PlatformSP &platform_sp) -{ - // The native platform should use its static void Platform::Initialize() - // function to register itself as the native platform. - GetHostPlatformSP () = platform_sp; +void Platform::SetHostPlatform(const lldb::PlatformSP &platform_sp) { + // The native platform should use its static void Platform::Initialize() + // function to register itself as the native platform. + GetHostPlatformSP() = platform_sp; - if (platform_sp) - { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - } + if (platform_sp) { + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + GetPlatformList().push_back(platform_sp); + } } -Error -Platform::GetFileWithUUID (const FileSpec &platform_file, - const UUID *uuid_ptr, - FileSpec &local_file) -{ - // Default to the local case - local_file = platform_file; - return Error(); +Error Platform::GetFileWithUUID(const FileSpec &platform_file, + const UUID *uuid_ptr, FileSpec &local_file) { + // Default to the local case + local_file = platform_file; + return Error(); } FileSpecList -Platform::LocateExecutableScriptingResources (Target *target, Module &module, Stream* feedback_stream) -{ - return FileSpecList(); +Platform::LocateExecutableScriptingResources(Target *target, Module &module, + Stream *feedback_stream) { + return FileSpecList(); } -//PlatformSP -//Platform::FindPlugin (Process *process, const ConstString &plugin_name) +// PlatformSP +// Platform::FindPlugin (Process *process, const ConstString &plugin_name) //{ // PlatformCreateInstance create_callback = nullptr; // if (plugin_name) // { -// create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); +// create_callback = +// PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name); // if (create_callback) // { // ArchSpec arch; @@ -246,7 +203,9 @@ Platform::LocateExecutableScriptingResources (Target *target, Module &module, St // } // else // { -// for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != nullptr; ++idx) +// for (uint32_t idx = 0; (create_callback = +// PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != nullptr; +// ++idx) // { // PlatformSP platform_sp(create_callback(process, nullptr)); // if (platform_sp) @@ -256,195 +215,162 @@ Platform::LocateExecutableScriptingResources (Target *target, Module &module, St // return PlatformSP(); //} -Error -Platform::GetSharedModule (const ModuleSpec &module_spec, - Process* process, - ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - ModuleSP *old_module_sp_ptr, - bool *did_create_ptr) -{ - if (IsHost ()) - return ModuleList::GetSharedModule (module_spec, - module_sp, - module_search_paths_ptr, - old_module_sp_ptr, - did_create_ptr, - false); - - return GetRemoteSharedModule (module_spec, - process, - module_sp, - [&](const ModuleSpec &spec) - { - Error error = ModuleList::GetSharedModule ( - spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, did_create_ptr, false); - if (error.Success() && module_sp) - module_sp->SetPlatformFileSpec(spec.GetFileSpec()); - return error; - }, - did_create_ptr); -} - -bool -Platform::GetModuleSpec (const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec &module_spec) -{ - ModuleSpecList module_specs; - if (ObjectFile::GetModuleSpecifications (module_file_spec, 0, 0, module_specs) == 0) - return false; +Error Platform::GetSharedModule(const ModuleSpec &module_spec, Process *process, + ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + ModuleSP *old_module_sp_ptr, + bool *did_create_ptr) { + if (IsHost()) + return ModuleList::GetSharedModule( + module_spec, module_sp, module_search_paths_ptr, old_module_sp_ptr, + did_create_ptr, false); + + return GetRemoteSharedModule(module_spec, process, module_sp, + [&](const ModuleSpec &spec) { + Error error = ModuleList::GetSharedModule( + spec, module_sp, module_search_paths_ptr, + old_module_sp_ptr, did_create_ptr, false); + if (error.Success() && module_sp) + module_sp->SetPlatformFileSpec( + spec.GetFileSpec()); + return error; + }, + did_create_ptr); +} + +bool Platform::GetModuleSpec(const FileSpec &module_file_spec, + const ArchSpec &arch, ModuleSpec &module_spec) { + ModuleSpecList module_specs; + if (ObjectFile::GetModuleSpecifications(module_file_spec, 0, 0, + module_specs) == 0) + return false; - ModuleSpec matched_module_spec; - return module_specs.FindMatchingModuleSpec (ModuleSpec (module_file_spec, arch), - module_spec); + ModuleSpec matched_module_spec; + return module_specs.FindMatchingModuleSpec(ModuleSpec(module_file_spec, arch), + module_spec); } -PlatformSP -Platform::Find (const ConstString &name) -{ - if (name) - { - static ConstString g_host_platform_name ("host"); - if (name == g_host_platform_name) - return GetHostPlatform(); - - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - for (const auto &platform_sp : GetPlatformList()) - { - if (platform_sp->GetName() == name) - return platform_sp; - } - } - return PlatformSP(); -} +PlatformSP Platform::Find(const ConstString &name) { + if (name) { + static ConstString g_host_platform_name("host"); + if (name == g_host_platform_name) + return GetHostPlatform(); -PlatformSP -Platform::Create (const ConstString &name, Error &error) -{ - PlatformCreateInstance create_callback = nullptr; - lldb::PlatformSP platform_sp; - if (name) - { - static ConstString g_host_platform_name ("host"); - if (name == g_host_platform_name) - return GetHostPlatform(); - - create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (name); - if (create_callback) - platform_sp = create_callback(true, nullptr); - else - error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", name.GetCString()); + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + for (const auto &platform_sp : GetPlatformList()) { + if (platform_sp->GetName() == name) + return platform_sp; } + } + return PlatformSP(); +} + +PlatformSP Platform::Create(const ConstString &name, Error &error) { + PlatformCreateInstance create_callback = nullptr; + lldb::PlatformSP platform_sp; + if (name) { + static ConstString g_host_platform_name("host"); + if (name == g_host_platform_name) + return GetHostPlatform(); + + create_callback = + PluginManager::GetPlatformCreateCallbackForPluginName(name); + if (create_callback) + platform_sp = create_callback(true, nullptr); else - error.SetErrorString ("invalid platform name"); + error.SetErrorStringWithFormat( + "unable to find a plug-in for the platform named \"%s\"", + name.GetCString()); + } else + error.SetErrorString("invalid platform name"); - if (platform_sp) - { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - } + if (platform_sp) { + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + GetPlatformList().push_back(platform_sp); + } - return platform_sp; + return platform_sp; } -PlatformSP -Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &error) -{ - lldb::PlatformSP platform_sp; - if (arch.IsValid()) +PlatformSP Platform::Create(const ArchSpec &arch, ArchSpec *platform_arch_ptr, + Error &error) { + lldb::PlatformSP platform_sp; + if (arch.IsValid()) { + // Scope for locker { - // Scope for locker - { - // First try exact arch matches across all platforms already created - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - for (const auto &platform_sp : GetPlatformList()) - { - if (platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr)) - return platform_sp; - } - - // Next try compatible arch matches across all platforms already created - for (const auto &platform_sp : GetPlatformList()) - { - if (platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr)) - return platform_sp; - } - } + // First try exact arch matches across all platforms already created + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + for (const auto &platform_sp : GetPlatformList()) { + if (platform_sp->IsCompatibleArchitecture(arch, true, + platform_arch_ptr)) + return platform_sp; + } + + // Next try compatible arch matches across all platforms already created + for (const auto &platform_sp : GetPlatformList()) { + if (platform_sp->IsCompatibleArchitecture(arch, false, + platform_arch_ptr)) + return platform_sp; + } + } - PlatformCreateInstance create_callback; - // First try exact arch matches across all platform plug-ins - uint32_t idx; - for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx) - { - if (create_callback) - { - platform_sp = create_callback(false, &arch); - if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr)) - { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - return platform_sp; - } - } + PlatformCreateInstance create_callback; + // First try exact arch matches across all platform plug-ins + uint32_t idx; + for (idx = 0; (create_callback = + PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + if (create_callback) { + platform_sp = create_callback(false, &arch); + if (platform_sp && + platform_sp->IsCompatibleArchitecture(arch, true, + platform_arch_ptr)) { + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + GetPlatformList().push_back(platform_sp); + return platform_sp; } - // Next try compatible arch matches across all platform plug-ins - for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx) - { - if (create_callback) - { - platform_sp = create_callback(false, &arch); - if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr)) - { - std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); - GetPlatformList().push_back(platform_sp); - return platform_sp; - } - } + } + } + // Next try compatible arch matches across all platform plug-ins + for (idx = 0; (create_callback = + PluginManager::GetPlatformCreateCallbackAtIndex(idx)); + ++idx) { + if (create_callback) { + platform_sp = create_callback(false, &arch); + if (platform_sp && + platform_sp->IsCompatibleArchitecture(arch, false, + platform_arch_ptr)) { + std::lock_guard<std::recursive_mutex> guard(GetPlatformListMutex()); + GetPlatformList().push_back(platform_sp); + return platform_sp; } + } } - else - error.SetErrorString ("invalid platform name"); - if (platform_arch_ptr) - platform_arch_ptr->Clear(); - platform_sp.reset(); - return platform_sp; + } else + error.SetErrorString("invalid platform name"); + if (platform_arch_ptr) + platform_arch_ptr->Clear(); + platform_sp.reset(); + return platform_sp; } //------------------------------------------------------------------ /// Default Constructor //------------------------------------------------------------------ Platform::Platform(bool is_host) - : m_is_host(is_host), - m_os_version_set_while_connected(false), - m_system_arch_set_while_connected(false), - m_sdk_sysroot(), - m_sdk_build(), - m_working_dir(), - m_remote_url(), - m_name(), - m_major_os_version(UINT32_MAX), - m_minor_os_version(UINT32_MAX), - m_update_os_version(UINT32_MAX), - m_system_arch(), - m_mutex(), - m_uid_map(), - m_gid_map(), - m_max_uid_name_len(0), - m_max_gid_name_len(0), - m_supports_rsync(false), - m_rsync_opts(), - m_rsync_prefix(), - m_supports_ssh(false), - m_ssh_opts(), - m_ignores_remote_hostname(false), - m_trap_handlers(), + : m_is_host(is_host), m_os_version_set_while_connected(false), + m_system_arch_set_while_connected(false), m_sdk_sysroot(), m_sdk_build(), + m_working_dir(), m_remote_url(), m_name(), m_major_os_version(UINT32_MAX), + m_minor_os_version(UINT32_MAX), m_update_os_version(UINT32_MAX), + m_system_arch(), m_mutex(), m_uid_map(), m_gid_map(), + m_max_uid_name_len(0), m_max_gid_name_len(0), m_supports_rsync(false), + m_rsync_opts(), m_rsync_prefix(), m_supports_ssh(false), m_ssh_opts(), + m_ignores_remote_hostname(false), m_trap_handlers(), m_calculated_trap_handlers(false), - m_module_cache(llvm::make_unique<ModuleCache>()) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p Platform::Platform()", static_cast<void *>(this)); + m_module_cache(llvm::make_unique<ModuleCache>()) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Platform::Platform()", static_cast<void *>(this)); } //------------------------------------------------------------------ @@ -453,1758 +379,1506 @@ Platform::Platform(bool is_host) /// The destructor is virtual since this class is designed to be /// inherited from by the plug-in instance. //------------------------------------------------------------------ -Platform::~Platform() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf ("%p Platform::~Platform()", static_cast<void*>(this)); -} - -void -Platform::GetStatus (Stream &strm) -{ - uint32_t major = UINT32_MAX; - uint32_t minor = UINT32_MAX; - uint32_t update = UINT32_MAX; - std::string s; - strm.Printf (" Platform: %s\n", GetPluginName().GetCString()); - - ArchSpec arch (GetSystemArchitecture()); - if (arch.IsValid()) - { - if (!arch.GetTriple().str().empty()) - { - strm.Printf(" Triple: "); - arch.DumpTriple(strm); - strm.EOL(); - } - } - - if (GetOSVersion(major, minor, update)) - { - strm.Printf("OS Version: %u", major); - if (minor != UINT32_MAX) - strm.Printf(".%u", minor); - if (update != UINT32_MAX) - strm.Printf(".%u", update); - - if (GetOSBuildString (s)) - strm.Printf(" (%s)", s.c_str()); - - strm.EOL(); +Platform::~Platform() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Platform::~Platform()", static_cast<void *>(this)); +} + +void Platform::GetStatus(Stream &strm) { + uint32_t major = UINT32_MAX; + uint32_t minor = UINT32_MAX; + uint32_t update = UINT32_MAX; + std::string s; + strm.Printf(" Platform: %s\n", GetPluginName().GetCString()); + + ArchSpec arch(GetSystemArchitecture()); + if (arch.IsValid()) { + if (!arch.GetTriple().str().empty()) { + strm.Printf(" Triple: "); + arch.DumpTriple(strm); + strm.EOL(); } - - if (GetOSKernelDescription (s)) - strm.Printf(" Kernel: %s\n", s.c_str()); - - if (IsHost()) - { - strm.Printf(" Hostname: %s\n", GetHostname()); + } + + if (GetOSVersion(major, minor, update)) { + strm.Printf("OS Version: %u", major); + if (minor != UINT32_MAX) + strm.Printf(".%u", minor); + if (update != UINT32_MAX) + strm.Printf(".%u", update); + + if (GetOSBuildString(s)) + strm.Printf(" (%s)", s.c_str()); + + strm.EOL(); + } + + if (GetOSKernelDescription(s)) + strm.Printf(" Kernel: %s\n", s.c_str()); + + if (IsHost()) { + strm.Printf(" Hostname: %s\n", GetHostname()); + } else { + const bool is_connected = IsConnected(); + if (is_connected) + strm.Printf(" Hostname: %s\n", GetHostname()); + strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); + } + + if (GetWorkingDirectory()) { + strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); + } + if (!IsConnected()) + return; + + std::string specific_info(GetPlatformSpecificConnectionInformation()); + + if (!specific_info.empty()) + strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); +} + +bool Platform::GetOSVersion(uint32_t &major, uint32_t &minor, uint32_t &update, + Process *process) { + std::lock_guard<std::mutex> guard(m_mutex); + + bool success = m_major_os_version != UINT32_MAX; + if (IsHost()) { + if (!success) { + // We have a local host platform + success = HostInfo::GetOSVersion(m_major_os_version, m_minor_os_version, + m_update_os_version); + m_os_version_set_while_connected = success; } - else - { - const bool is_connected = IsConnected(); - if (is_connected) - strm.Printf(" Hostname: %s\n", GetHostname()); - strm.Printf(" Connected: %s\n", is_connected ? "yes" : "no"); + } else { + // We have a remote platform. We can only fetch the remote + // OS version if we are connected, and we don't want to do it + // more than once. + + const bool is_connected = IsConnected(); + + bool fetch = false; + if (success) { + // We have valid OS version info, check to make sure it wasn't + // manually set prior to connecting. If it was manually set prior + // to connecting, then lets fetch the actual OS version info + // if we are now connected. + if (is_connected && !m_os_version_set_while_connected) + fetch = true; + } else { + // We don't have valid OS version info, fetch it if we are connected + fetch = is_connected; } - if (GetWorkingDirectory()) - { - strm.Printf("WorkingDir: %s\n", GetWorkingDirectory().GetCString()); - } - if (!IsConnected()) - return; - - std::string specific_info(GetPlatformSpecificConnectionInformation()); - - if (!specific_info.empty()) - strm.Printf("Platform-specific connection: %s\n", specific_info.c_str()); -} - -bool -Platform::GetOSVersion (uint32_t &major, - uint32_t &minor, - uint32_t &update, - Process *process) -{ - std::lock_guard<std::mutex> guard(m_mutex); - - bool success = m_major_os_version != UINT32_MAX; - if (IsHost()) - { - if (!success) - { - // We have a local host platform - success = HostInfo::GetOSVersion(m_major_os_version, m_minor_os_version, m_update_os_version); - m_os_version_set_while_connected = success; - } - } - else - { - // We have a remote platform. We can only fetch the remote - // OS version if we are connected, and we don't want to do it - // more than once. - - const bool is_connected = IsConnected(); - - bool fetch = false; - if (success) - { - // We have valid OS version info, check to make sure it wasn't - // manually set prior to connecting. If it was manually set prior - // to connecting, then lets fetch the actual OS version info - // if we are now connected. - if (is_connected && !m_os_version_set_while_connected) - fetch = true; - } - else - { - // We don't have valid OS version info, fetch it if we are connected - fetch = is_connected; - } - - if (fetch) - { - success = GetRemoteOSVersion (); - m_os_version_set_while_connected = success; - } + if (fetch) { + success = GetRemoteOSVersion(); + m_os_version_set_while_connected = success; } + } - if (success) - { - major = m_major_os_version; - minor = m_minor_os_version; - update = m_update_os_version; - } - else if (process) - { - // Check with the process in case it can answer the question if - // a process was provided - return process->GetHostOSVersion(major, minor, update); - } - return success; + if (success) { + major = m_major_os_version; + minor = m_minor_os_version; + update = m_update_os_version; + } else if (process) { + // Check with the process in case it can answer the question if + // a process was provided + return process->GetHostOSVersion(major, minor, update); + } + return success; } -bool -Platform::GetOSBuildString (std::string &s) -{ - s.clear(); +bool Platform::GetOSBuildString(std::string &s) { + s.clear(); - if (IsHost()) + if (IsHost()) #if !defined(__linux__) - return HostInfo::GetOSBuildString(s); + return HostInfo::GetOSBuildString(s); #else - return false; + return false; #endif - else - return GetRemoteOSBuildString (s); + else + return GetRemoteOSBuildString(s); } -bool -Platform::GetOSKernelDescription (std::string &s) -{ - if (IsHost()) +bool Platform::GetOSKernelDescription(std::string &s) { + if (IsHost()) #if !defined(__linux__) - return HostInfo::GetOSKernelDescription(s); + return HostInfo::GetOSKernelDescription(s); #else - return false; + return false; #endif - else - return GetRemoteOSKernelDescription (s); + else + return GetRemoteOSKernelDescription(s); } -void -Platform::AddClangModuleCompilationOptions (Target *target, std::vector<std::string> &options) -{ - std::vector<std::string> default_compilation_options = - { - "-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc" - }; - - options.insert(options.end(), - default_compilation_options.begin(), - default_compilation_options.end()); -} +void Platform::AddClangModuleCompilationOptions( + Target *target, std::vector<std::string> &options) { + std::vector<std::string> default_compilation_options = { + "-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc"}; -FileSpec -Platform::GetWorkingDirectory () -{ - if (IsHost()) - { - char cwd[PATH_MAX]; - if (getcwd(cwd, sizeof(cwd))) - return FileSpec{cwd, true}; - else - return FileSpec{}; - } - else - { - if (!m_working_dir) - m_working_dir = GetRemoteWorkingDirectory(); - return m_working_dir; - } + options.insert(options.end(), default_compilation_options.begin(), + default_compilation_options.end()); } -struct RecurseCopyBaton -{ - const FileSpec& dst; - Platform *platform_ptr; - Error error; +FileSpec Platform::GetWorkingDirectory() { + if (IsHost()) { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) + return FileSpec{cwd, true}; + else + return FileSpec{}; + } else { + if (!m_working_dir) + m_working_dir = GetRemoteWorkingDirectory(); + return m_working_dir; + } +} + +struct RecurseCopyBaton { + const FileSpec &dst; + Platform *platform_ptr; + Error error; }; static FileSpec::EnumerateDirectoryResult -RecurseCopy_Callback (void *baton, - FileSpec::FileType file_type, - const FileSpec &src) -{ - RecurseCopyBaton* rc_baton = (RecurseCopyBaton*)baton; - switch (file_type) - { - case FileSpec::eFileTypePipe: - case FileSpec::eFileTypeSocket: - // we have no way to copy pipes and sockets - ignore them and continue - return FileSpec::eEnumerateDirectoryResultNext; - break; - - case FileSpec::eFileTypeDirectory: - { - // make the new directory and get in there - FileSpec dst_dir = rc_baton->dst; - if (!dst_dir.GetFilename()) - dst_dir.GetFilename() = src.GetLastPathComponent(); - Error error = rc_baton->platform_ptr->MakeDirectory(dst_dir, lldb::eFilePermissionsDirectoryDefault); - if (error.Fail()) - { - rc_baton->error.SetErrorStringWithFormat("unable to setup directory %s on remote end", - dst_dir.GetCString()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - } - - // now recurse - std::string src_dir_path (src.GetPath()); - - // Make a filespec that only fills in the directory of a FileSpec so - // when we enumerate we can quickly fill in the filename for dst copies - FileSpec recurse_dst; - recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); - RecurseCopyBaton rc_baton2 = { recurse_dst, rc_baton->platform_ptr, Error() }; - FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &rc_baton2); - if (rc_baton2.error.Fail()) - { - rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - } - return FileSpec::eEnumerateDirectoryResultNext; - } - break; - - case FileSpec::eFileTypeSymbolicLink: - { - // copy the file and keep going - FileSpec dst_file = rc_baton->dst; - if (!dst_file.GetFilename()) - dst_file.GetFilename() = src.GetFilename(); - - FileSpec src_resolved; - - rc_baton->error = FileSystem::Readlink(src, src_resolved); - - if (rc_baton->error.Fail()) - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - - rc_baton->error = rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved); - - if (rc_baton->error.Fail()) - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - - return FileSpec::eEnumerateDirectoryResultNext; - } - break; - - case FileSpec::eFileTypeRegular: - { - // copy the file and keep going - FileSpec dst_file = rc_baton->dst; - if (!dst_file.GetFilename()) - dst_file.GetFilename() = src.GetFilename(); - Error err = rc_baton->platform_ptr->PutFile(src, dst_file); - if (err.Fail()) - { - rc_baton->error.SetErrorString(err.AsCString()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - } - return FileSpec::eEnumerateDirectoryResultNext; - } - break; - - case FileSpec::eFileTypeInvalid: - case FileSpec::eFileTypeOther: - case FileSpec::eFileTypeUnknown: - rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str()); - return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out - break; +RecurseCopy_Callback(void *baton, FileSpec::FileType file_type, + const FileSpec &src) { + RecurseCopyBaton *rc_baton = (RecurseCopyBaton *)baton; + switch (file_type) { + case FileSpec::eFileTypePipe: + case FileSpec::eFileTypeSocket: + // we have no way to copy pipes and sockets - ignore them and continue + return FileSpec::eEnumerateDirectoryResultNext; + break; + + case FileSpec::eFileTypeDirectory: { + // make the new directory and get in there + FileSpec dst_dir = rc_baton->dst; + if (!dst_dir.GetFilename()) + dst_dir.GetFilename() = src.GetLastPathComponent(); + Error error = rc_baton->platform_ptr->MakeDirectory( + dst_dir, lldb::eFilePermissionsDirectoryDefault); + if (error.Fail()) { + rc_baton->error.SetErrorStringWithFormat( + "unable to setup directory %s on remote end", dst_dir.GetCString()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out } - llvm_unreachable("Unhandled FileSpec::FileType!"); -} -Error -Platform::Install (const FileSpec& src, const FileSpec& dst) -{ - Error error; - - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); - if (log) - log->Printf ("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), dst.GetPath().c_str()); - FileSpec fixed_dst(dst); - - if (!fixed_dst.GetFilename()) - fixed_dst.GetFilename() = src.GetFilename(); + // now recurse + std::string src_dir_path(src.GetPath()); + + // Make a filespec that only fills in the directory of a FileSpec so + // when we enumerate we can quickly fill in the filename for dst copies + FileSpec recurse_dst; + recurse_dst.GetDirectory().SetCString(dst_dir.GetPath().c_str()); + RecurseCopyBaton rc_baton2 = {recurse_dst, rc_baton->platform_ptr, Error()}; + FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, + RecurseCopy_Callback, &rc_baton2); + if (rc_baton2.error.Fail()) { + rc_baton->error.SetErrorString(rc_baton2.error.AsCString()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + } + return FileSpec::eEnumerateDirectoryResultNext; + } break; - FileSpec working_dir = GetWorkingDirectory(); + case FileSpec::eFileTypeSymbolicLink: { + // copy the file and keep going + FileSpec dst_file = rc_baton->dst; + if (!dst_file.GetFilename()) + dst_file.GetFilename() = src.GetFilename(); - if (dst) - { - if (dst.GetDirectory()) - { - const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; - if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') - { - fixed_dst.GetDirectory() = dst.GetDirectory(); - } - // If the fixed destination file doesn't have a directory yet, - // then we must have a relative path. We will resolve this relative - // path against the platform's working directory - if (!fixed_dst.GetDirectory()) - { - FileSpec relative_spec; - std::string path; - if (working_dir) - { - relative_spec = working_dir; - relative_spec.AppendPathComponent(dst.GetPath()); - fixed_dst.GetDirectory() = relative_spec.GetDirectory(); - } - else - { - error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); - return error; - } - } - } - else - { - if (working_dir) - { - fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); - } - else - { - error.SetErrorStringWithFormat("platform working directory must be valid for relative path '%s'", dst.GetPath().c_str()); - return error; - } - } - } - else - { - if (working_dir) - { - fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); - } - else - { - error.SetErrorStringWithFormat("platform working directory must be valid when destination directory is empty"); - return error; - } - } - - if (log) - log->Printf ("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", src.GetPath().c_str(), dst.GetPath().c_str(), fixed_dst.GetPath().c_str()); + FileSpec src_resolved; - if (GetSupportsRSync()) - { - error = PutFile(src, dst); + rc_baton->error = FileSystem::Readlink(src, src_resolved); + + if (rc_baton->error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + + rc_baton->error = + rc_baton->platform_ptr->CreateSymlink(dst_file, src_resolved); + + if (rc_baton->error.Fail()) + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + + return FileSpec::eEnumerateDirectoryResultNext; + } break; + + case FileSpec::eFileTypeRegular: { + // copy the file and keep going + FileSpec dst_file = rc_baton->dst; + if (!dst_file.GetFilename()) + dst_file.GetFilename() = src.GetFilename(); + Error err = rc_baton->platform_ptr->PutFile(src, dst_file); + if (err.Fail()) { + rc_baton->error.SetErrorString(err.AsCString()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out } - else - { - switch (src.GetFileType()) - { - case FileSpec::eFileTypeDirectory: - { - if (GetFileExists (fixed_dst)) - Unlink(fixed_dst); - uint32_t permissions = src.GetPermissions(); - if (permissions == 0) - permissions = eFilePermissionsDirectoryDefault; - error = MakeDirectory(fixed_dst, permissions); - if (error.Success()) - { - // Make a filespec that only fills in the directory of a FileSpec so - // when we enumerate we can quickly fill in the filename for dst copies - FileSpec recurse_dst; - recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString()); - std::string src_dir_path (src.GetPath()); - RecurseCopyBaton baton = { recurse_dst, this, Error() }; - FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, RecurseCopy_Callback, &baton); - return baton.error; - } - } - break; - - case FileSpec::eFileTypeRegular: - if (GetFileExists (fixed_dst)) - Unlink(fixed_dst); - error = PutFile(src, fixed_dst); - break; - - case FileSpec::eFileTypeSymbolicLink: - { - if (GetFileExists (fixed_dst)) - Unlink(fixed_dst); - FileSpec src_resolved; - error = FileSystem::Readlink(src, src_resolved); - if (error.Success()) - error = CreateSymlink(dst, src_resolved); - } - break; - case FileSpec::eFileTypePipe: - error.SetErrorString("platform install doesn't handle pipes"); - break; - case FileSpec::eFileTypeSocket: - error.SetErrorString("platform install doesn't handle sockets"); - break; - case FileSpec::eFileTypeInvalid: - case FileSpec::eFileTypeUnknown: - case FileSpec::eFileTypeOther: - error.SetErrorString("platform install doesn't handle non file or directory items"); - break; + return FileSpec::eEnumerateDirectoryResultNext; + } break; + + case FileSpec::eFileTypeInvalid: + case FileSpec::eFileTypeOther: + case FileSpec::eFileTypeUnknown: + rc_baton->error.SetErrorStringWithFormat( + "invalid file detected during copy: %s", src.GetPath().c_str()); + return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out + break; + } + llvm_unreachable("Unhandled FileSpec::FileType!"); +} + +Error Platform::Install(const FileSpec &src, const FileSpec &dst) { + Error error; + + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf("Platform::Install (src='%s', dst='%s')", src.GetPath().c_str(), + dst.GetPath().c_str()); + FileSpec fixed_dst(dst); + + if (!fixed_dst.GetFilename()) + fixed_dst.GetFilename() = src.GetFilename(); + + FileSpec working_dir = GetWorkingDirectory(); + + if (dst) { + if (dst.GetDirectory()) { + const char first_dst_dir_char = dst.GetDirectory().GetCString()[0]; + if (first_dst_dir_char == '/' || first_dst_dir_char == '\\') { + fixed_dst.GetDirectory() = dst.GetDirectory(); + } + // If the fixed destination file doesn't have a directory yet, + // then we must have a relative path. We will resolve this relative + // path against the platform's working directory + if (!fixed_dst.GetDirectory()) { + FileSpec relative_spec; + std::string path; + if (working_dir) { + relative_spec = working_dir; + relative_spec.AppendPathComponent(dst.GetPath()); + fixed_dst.GetDirectory() = relative_spec.GetDirectory(); + } else { + error.SetErrorStringWithFormat( + "platform working directory must be valid for relative path '%s'", + dst.GetPath().c_str()); + return error; } + } + } else { + if (working_dir) { + fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); + } else { + error.SetErrorStringWithFormat( + "platform working directory must be valid for relative path '%s'", + dst.GetPath().c_str()); + return error; + } } - return error; -} - -bool -Platform::SetWorkingDirectory(const FileSpec &file_spec) -{ - if (IsHost()) - { - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); - if (log) - log->Printf("Platform::SetWorkingDirectory('%s')", - file_spec.GetCString()); - if (file_spec) - { - if (::chdir(file_spec.GetCString()) == 0) - return true; - } - return false; + } else { + if (working_dir) { + fixed_dst.GetDirectory().SetCString(working_dir.GetCString()); + } else { + error.SetErrorStringWithFormat("platform working directory must be valid " + "when destination directory is empty"); + return error; } - else - { - m_working_dir.Clear(); - return SetRemoteWorkingDirectory(file_spec); + } + + if (log) + log->Printf("Platform::Install (src='%s', dst='%s') fixed_dst='%s'", + src.GetPath().c_str(), dst.GetPath().c_str(), + fixed_dst.GetPath().c_str()); + + if (GetSupportsRSync()) { + error = PutFile(src, dst); + } else { + switch (src.GetFileType()) { + case FileSpec::eFileTypeDirectory: { + if (GetFileExists(fixed_dst)) + Unlink(fixed_dst); + uint32_t permissions = src.GetPermissions(); + if (permissions == 0) + permissions = eFilePermissionsDirectoryDefault; + error = MakeDirectory(fixed_dst, permissions); + if (error.Success()) { + // Make a filespec that only fills in the directory of a FileSpec so + // when we enumerate we can quickly fill in the filename for dst copies + FileSpec recurse_dst; + recurse_dst.GetDirectory().SetCString(fixed_dst.GetCString()); + std::string src_dir_path(src.GetPath()); + RecurseCopyBaton baton = {recurse_dst, this, Error()}; + FileSpec::EnumerateDirectory(src_dir_path.c_str(), true, true, true, + RecurseCopy_Callback, &baton); + return baton.error; + } + } break; + + case FileSpec::eFileTypeRegular: + if (GetFileExists(fixed_dst)) + Unlink(fixed_dst); + error = PutFile(src, fixed_dst); + break; + + case FileSpec::eFileTypeSymbolicLink: { + if (GetFileExists(fixed_dst)) + Unlink(fixed_dst); + FileSpec src_resolved; + error = FileSystem::Readlink(src, src_resolved); + if (error.Success()) + error = CreateSymlink(dst, src_resolved); + } break; + case FileSpec::eFileTypePipe: + error.SetErrorString("platform install doesn't handle pipes"); + break; + case FileSpec::eFileTypeSocket: + error.SetErrorString("platform install doesn't handle sockets"); + break; + case FileSpec::eFileTypeInvalid: + case FileSpec::eFileTypeUnknown: + case FileSpec::eFileTypeOther: + error.SetErrorString( + "platform install doesn't handle non file or directory items"); + break; } + } + return error; } -Error -Platform::MakeDirectory(const FileSpec &file_spec, uint32_t permissions) -{ - if (IsHost()) - return FileSystem::MakeDirectory(file_spec, permissions); - else - { - Error error; - error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), LLVM_PRETTY_FUNCTION); - return error; +bool Platform::SetWorkingDirectory(const FileSpec &file_spec) { + if (IsHost()) { + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf("Platform::SetWorkingDirectory('%s')", + file_spec.GetCString()); + if (file_spec) { + if (::chdir(file_spec.GetCString()) == 0) + return true; } + return false; + } else { + m_working_dir.Clear(); + return SetRemoteWorkingDirectory(file_spec); + } } -Error -Platform::GetFilePermissions(const FileSpec &file_spec, uint32_t &file_permissions) -{ - if (IsHost()) - return FileSystem::GetFilePermissions(file_spec, file_permissions); - else - { - Error error; - error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), LLVM_PRETTY_FUNCTION); - return error; - } +Error Platform::MakeDirectory(const FileSpec &file_spec, uint32_t permissions) { + if (IsHost()) + return FileSystem::MakeDirectory(file_spec, permissions); + else { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", + GetPluginName().GetCString(), + LLVM_PRETTY_FUNCTION); + return error; + } } -Error -Platform::SetFilePermissions(const FileSpec &file_spec, uint32_t file_permissions) -{ - if (IsHost()) - return FileSystem::SetFilePermissions(file_spec, file_permissions); - else - { - Error error; - error.SetErrorStringWithFormat("remote platform %s doesn't support %s", GetPluginName().GetCString(), LLVM_PRETTY_FUNCTION); - return error; - } +Error Platform::GetFilePermissions(const FileSpec &file_spec, + uint32_t &file_permissions) { + if (IsHost()) + return FileSystem::GetFilePermissions(file_spec, file_permissions); + else { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", + GetPluginName().GetCString(), + LLVM_PRETTY_FUNCTION); + return error; + } } -ConstString -Platform::GetName () -{ - return GetPluginName(); +Error Platform::SetFilePermissions(const FileSpec &file_spec, + uint32_t file_permissions) { + if (IsHost()) + return FileSystem::SetFilePermissions(file_spec, file_permissions); + else { + Error error; + error.SetErrorStringWithFormat("remote platform %s doesn't support %s", + GetPluginName().GetCString(), + LLVM_PRETTY_FUNCTION); + return error; + } } -const char * -Platform::GetHostname () -{ - if (IsHost()) - return "127.0.0.1"; +ConstString Platform::GetName() { return GetPluginName(); } + +const char *Platform::GetHostname() { + if (IsHost()) + return "127.0.0.1"; - if (m_name.empty()) - return nullptr; - return m_name.c_str(); + if (m_name.empty()) + return nullptr; + return m_name.c_str(); } -ConstString -Platform::GetFullNameForDylib (ConstString basename) -{ - return basename; +ConstString Platform::GetFullNameForDylib(ConstString basename) { + return basename; } -bool -Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) -{ - Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); - if (log) - log->Printf("Platform::SetRemoteWorkingDirectory('%s')", +bool Platform::SetRemoteWorkingDirectory(const FileSpec &working_dir) { + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + if (log) + log->Printf("Platform::SetRemoteWorkingDirectory('%s')", working_dir.GetCString()); - m_working_dir = working_dir; - return true; + m_working_dir = working_dir; + return true; } -const char * -Platform::GetUserName (uint32_t uid) -{ +const char *Platform::GetUserName(uint32_t uid) { #if !defined(LLDB_DISABLE_POSIX) - const char *user_name = GetCachedUserName(uid); - if (user_name) - return user_name; - if (IsHost()) - { - std::string name; - if (HostInfo::LookupUserName(uid, name)) - return SetCachedUserName (uid, name.c_str(), name.size()); - } + const char *user_name = GetCachedUserName(uid); + if (user_name) + return user_name; + if (IsHost()) { + std::string name; + if (HostInfo::LookupUserName(uid, name)) + return SetCachedUserName(uid, name.c_str(), name.size()); + } #endif - return nullptr; + return nullptr; } -const char * -Platform::GetGroupName (uint32_t gid) -{ +const char *Platform::GetGroupName(uint32_t gid) { #if !defined(LLDB_DISABLE_POSIX) - const char *group_name = GetCachedGroupName(gid); - if (group_name) - return group_name; - if (IsHost()) - { - std::string name; - if (HostInfo::LookupGroupName(gid, name)) - return SetCachedGroupName (gid, name.c_str(), name.size()); - } + const char *group_name = GetCachedGroupName(gid); + if (group_name) + return group_name; + if (IsHost()) { + std::string name; + if (HostInfo::LookupGroupName(gid, name)) + return SetCachedGroupName(gid, name.c_str(), name.size()); + } #endif - return nullptr; + return nullptr; } -bool -Platform::SetOSVersion (uint32_t major, - uint32_t minor, - uint32_t update) -{ - if (IsHost()) - { - // We don't need anyone setting the OS version for the host platform, - // we should be able to figure it out by calling HostInfo::GetOSVersion(...). - return false; - } - else - { - // We have a remote platform, allow setting the target OS version if - // we aren't connected, since if we are connected, we should be able to - // request the remote OS version from the connected platform. - if (IsConnected()) - return false; - else - { - // We aren't connected and we might want to set the OS version - // ahead of time before we connect so we can peruse files and - // use a local SDK or PDK cache of support files to disassemble - // or do other things. - m_major_os_version = major; - m_minor_os_version = minor; - m_update_os_version = update; - return true; - } - } +bool Platform::SetOSVersion(uint32_t major, uint32_t minor, uint32_t update) { + if (IsHost()) { + // We don't need anyone setting the OS version for the host platform, + // we should be able to figure it out by calling + // HostInfo::GetOSVersion(...). return false; -} - -Error -Platform::ResolveExecutable (const ModuleSpec &module_spec, - lldb::ModuleSP &exe_module_sp, - const FileSpecList *module_search_paths_ptr) -{ - Error error; - if (module_spec.GetFileSpec().Exists()) - { - if (module_spec.GetArchitecture().IsValid()) - { - error = ModuleList::GetSharedModule(module_spec, - exe_module_sp, - module_search_paths_ptr, - nullptr, - nullptr); - } - else - { - // No valid architecture was specified, ask the platform for - // the architectures that we should be using (in the correct order) - // and see if we can find a match that way - ModuleSpec arch_module_spec(module_spec); - for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, arch_module_spec.GetArchitecture()); ++idx) - { - error = ModuleList::GetSharedModule(arch_module_spec, - exe_module_sp, - module_search_paths_ptr, - nullptr, - nullptr); - // Did we find an executable using one of the - if (error.Success() && exe_module_sp) - break; - } - } + } else { + // We have a remote platform, allow setting the target OS version if + // we aren't connected, since if we are connected, we should be able to + // request the remote OS version from the connected platform. + if (IsConnected()) + return false; + else { + // We aren't connected and we might want to set the OS version + // ahead of time before we connect so we can peruse files and + // use a local SDK or PDK cache of support files to disassemble + // or do other things. + m_major_os_version = major; + m_minor_os_version = minor; + m_update_os_version = update; + return true; } - else - { - error.SetErrorStringWithFormat ("'%s' does not exist", - module_spec.GetFileSpec().GetPath().c_str()); + } + return false; +} + +Error Platform::ResolveExecutable(const ModuleSpec &module_spec, + lldb::ModuleSP &exe_module_sp, + const FileSpecList *module_search_paths_ptr) { + Error error; + if (module_spec.GetFileSpec().Exists()) { + if (module_spec.GetArchitecture().IsValid()) { + error = ModuleList::GetSharedModule(module_spec, exe_module_sp, + module_search_paths_ptr, nullptr, + nullptr); + } else { + // No valid architecture was specified, ask the platform for + // the architectures that we should be using (in the correct order) + // and see if we can find a match that way + ModuleSpec arch_module_spec(module_spec); + for (uint32_t idx = 0; GetSupportedArchitectureAtIndex( + idx, arch_module_spec.GetArchitecture()); + ++idx) { + error = ModuleList::GetSharedModule(arch_module_spec, exe_module_sp, + module_search_paths_ptr, nullptr, + nullptr); + // Did we find an executable using one of the + if (error.Success() && exe_module_sp) + break; + } } - return error; -} - -Error -Platform::ResolveSymbolFile (Target &target, - const ModuleSpec &sym_spec, - FileSpec &sym_file) -{ - Error error; - if (sym_spec.GetSymbolFileSpec().Exists()) - sym_file = sym_spec.GetSymbolFileSpec(); - else - error.SetErrorString("unable to resolve symbol file"); - return error; -} - -bool -Platform::ResolveRemotePath (const FileSpec &platform_path, - FileSpec &resolved_platform_path) -{ - resolved_platform_path = platform_path; - return resolved_platform_path.ResolvePath(); -} - -const ArchSpec & -Platform::GetSystemArchitecture() -{ - if (IsHost()) - { - if (!m_system_arch.IsValid()) - { - // We have a local host platform - m_system_arch = HostInfo::GetArchitecture(); - m_system_arch_set_while_connected = m_system_arch.IsValid(); - } + } else { + error.SetErrorStringWithFormat("'%s' does not exist", + module_spec.GetFileSpec().GetPath().c_str()); + } + return error; +} + +Error Platform::ResolveSymbolFile(Target &target, const ModuleSpec &sym_spec, + FileSpec &sym_file) { + Error error; + if (sym_spec.GetSymbolFileSpec().Exists()) + sym_file = sym_spec.GetSymbolFileSpec(); + else + error.SetErrorString("unable to resolve symbol file"); + return error; +} + +bool Platform::ResolveRemotePath(const FileSpec &platform_path, + FileSpec &resolved_platform_path) { + resolved_platform_path = platform_path; + return resolved_platform_path.ResolvePath(); +} + +const ArchSpec &Platform::GetSystemArchitecture() { + if (IsHost()) { + if (!m_system_arch.IsValid()) { + // We have a local host platform + m_system_arch = HostInfo::GetArchitecture(); + m_system_arch_set_while_connected = m_system_arch.IsValid(); } - else - { - // We have a remote platform. We can only fetch the remote - // system architecture if we are connected, and we don't want to do it - // more than once. - - const bool is_connected = IsConnected(); - - bool fetch = false; - if (m_system_arch.IsValid()) - { - // We have valid OS version info, check to make sure it wasn't - // manually set prior to connecting. If it was manually set prior - // to connecting, then lets fetch the actual OS version info - // if we are now connected. - if (is_connected && !m_system_arch_set_while_connected) - fetch = true; - } - else - { - // We don't have valid OS version info, fetch it if we are connected - fetch = is_connected; - } - - if (fetch) - { - m_system_arch = GetRemoteSystemArchitecture (); - m_system_arch_set_while_connected = m_system_arch.IsValid(); - } + } else { + // We have a remote platform. We can only fetch the remote + // system architecture if we are connected, and we don't want to do it + // more than once. + + const bool is_connected = IsConnected(); + + bool fetch = false; + if (m_system_arch.IsValid()) { + // We have valid OS version info, check to make sure it wasn't + // manually set prior to connecting. If it was manually set prior + // to connecting, then lets fetch the actual OS version info + // if we are now connected. + if (is_connected && !m_system_arch_set_while_connected) + fetch = true; + } else { + // We don't have valid OS version info, fetch it if we are connected + fetch = is_connected; } - return m_system_arch; -} - -Error -Platform::ConnectRemote (Args& args) -{ - Error error; - if (IsHost()) - error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString()); - else - error.SetErrorStringWithFormat ("Platform::ConnectRemote() is not supported by %s", GetPluginName().GetCString()); - return error; -} - -Error -Platform::DisconnectRemote () -{ - Error error; - if (IsHost()) - error.SetErrorStringWithFormat ("The currently selected platform (%s) is the host platform and is always connected.", GetPluginName().GetCString()); - else - error.SetErrorStringWithFormat ("Platform::DisconnectRemote() is not supported by %s", GetPluginName().GetCString()); - return error; -} - -bool -Platform::GetProcessInfo (lldb::pid_t pid, ProcessInstanceInfo &process_info) -{ - // Take care of the host case so that each subclass can just - // call this function to get the host functionality. - if (IsHost()) - return Host::GetProcessInfo (pid, process_info); - return false; -} - -uint32_t -Platform::FindProcesses (const ProcessInstanceInfoMatch &match_info, - ProcessInstanceInfoList &process_infos) -{ - // Take care of the host case so that each subclass can just - // call this function to get the host functionality. - uint32_t match_count = 0; - if (IsHost()) - match_count = Host::FindProcesses (match_info, process_infos); - return match_count; -} - -Error -Platform::LaunchProcess (ProcessLaunchInfo &launch_info) -{ - Error error; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf ("Platform::%s()", __FUNCTION__); - - // Take care of the host case so that each subclass can just - // call this function to get the host functionality. - if (IsHost()) - { - if (::getenv ("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY")) - launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY); - - if (launch_info.GetFlags().Test (eLaunchFlagLaunchInShell)) - { - const bool is_localhost = true; - const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); - const bool first_arg_is_full_shell_command = false; - uint32_t num_resumes = GetResumeCountForLaunchInfo (launch_info); - if (log) - { - const FileSpec &shell = launch_info.GetShell(); - const char *shell_str = (shell) ? shell.GetPath().c_str() : "<null>"; - log->Printf ("Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 ", shell is '%s'", - __FUNCTION__, - num_resumes, - shell_str); - } - - if (!launch_info.ConvertArgumentsForLaunchingInShell (error, - is_localhost, - will_debug, - first_arg_is_full_shell_command, - num_resumes)) - return error; - } - else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) - { - error = ShellExpandArguments(launch_info); - if (error.Fail()) - { - error.SetErrorStringWithFormat("shell expansion failed (reason: %s). consider launching with 'process launch'.", - error.AsCString("unknown")); - return error; - } - } - if (log) - log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ()); - - error = Host::LaunchProcess (launch_info); + if (fetch) { + m_system_arch = GetRemoteSystemArchitecture(); + m_system_arch_set_while_connected = m_system_arch.IsValid(); + } + } + return m_system_arch; +} + +Error Platform::ConnectRemote(Args &args) { + Error error; + if (IsHost()) + error.SetErrorStringWithFormat("The currently selected platform (%s) is " + "the host platform and is always connected.", + GetPluginName().GetCString()); + else + error.SetErrorStringWithFormat( + "Platform::ConnectRemote() is not supported by %s", + GetPluginName().GetCString()); + return error; +} + +Error Platform::DisconnectRemote() { + Error error; + if (IsHost()) + error.SetErrorStringWithFormat("The currently selected platform (%s) is " + "the host platform and is always connected.", + GetPluginName().GetCString()); + else + error.SetErrorStringWithFormat( + "Platform::DisconnectRemote() is not supported by %s", + GetPluginName().GetCString()); + return error; +} + +bool Platform::GetProcessInfo(lldb::pid_t pid, + ProcessInstanceInfo &process_info) { + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + if (IsHost()) + return Host::GetProcessInfo(pid, process_info); + return false; +} + +uint32_t Platform::FindProcesses(const ProcessInstanceInfoMatch &match_info, + ProcessInstanceInfoList &process_infos) { + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + uint32_t match_count = 0; + if (IsHost()) + match_count = Host::FindProcesses(match_info, process_infos); + return match_count; +} + +Error Platform::LaunchProcess(ProcessLaunchInfo &launch_info) { + Error error; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Platform::%s()", __FUNCTION__); + + // Take care of the host case so that each subclass can just + // call this function to get the host functionality. + if (IsHost()) { + if (::getenv("LLDB_LAUNCH_FLAG_LAUNCH_IN_TTY")) + launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); + + if (launch_info.GetFlags().Test(eLaunchFlagLaunchInShell)) { + const bool is_localhost = true; + const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug); + const bool first_arg_is_full_shell_command = false; + uint32_t num_resumes = GetResumeCountForLaunchInfo(launch_info); + if (log) { + const FileSpec &shell = launch_info.GetShell(); + const char *shell_str = (shell) ? shell.GetPath().c_str() : "<null>"; + log->Printf( + "Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 + ", shell is '%s'", + __FUNCTION__, num_resumes, shell_str); + } + + if (!launch_info.ConvertArgumentsForLaunchingInShell( + error, is_localhost, will_debug, first_arg_is_full_shell_command, + num_resumes)) + return error; + } else if (launch_info.GetFlags().Test(eLaunchFlagShellExpandArguments)) { + error = ShellExpandArguments(launch_info); + if (error.Fail()) { + error.SetErrorStringWithFormat("shell expansion failed (reason: %s). " + "consider launching with 'process " + "launch'.", + error.AsCString("unknown")); + return error; + } } - else - error.SetErrorString ("base lldb_private::Platform class can't launch remote processes"); - return error; -} - -Error -Platform::ShellExpandArguments (ProcessLaunchInfo &launch_info) -{ - if (IsHost()) - return Host::ShellExpandArguments(launch_info); - return Error("base lldb_private::Platform class can't expand arguments"); -} -Error -Platform::KillProcess (const lldb::pid_t pid) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); if (log) - log->Printf ("Platform::%s, pid %" PRIu64, __FUNCTION__, pid); - - // Try to find a process plugin to handle this Kill request. If we can't, fall back to - // the default OS implementation. - size_t num_debuggers = Debugger::GetNumDebuggers(); - for (size_t didx = 0; didx < num_debuggers; ++didx) - { - DebuggerSP debugger = Debugger::GetDebuggerAtIndex(didx); - lldb_private::TargetList &targets = debugger->GetTargetList(); - for (int tidx = 0; tidx < targets.GetNumTargets(); ++tidx) - { - ProcessSP process = targets.GetTargetAtIndex(tidx)->GetProcessSP(); - if (process->GetID() == pid) - return process->Destroy(true); - } + log->Printf("Platform::%s final launch_info resume count: %" PRIu32, + __FUNCTION__, launch_info.GetResumeCount()); + + error = Host::LaunchProcess(launch_info); + } else + error.SetErrorString( + "base lldb_private::Platform class can't launch remote processes"); + return error; +} + +Error Platform::ShellExpandArguments(ProcessLaunchInfo &launch_info) { + if (IsHost()) + return Host::ShellExpandArguments(launch_info); + return Error("base lldb_private::Platform class can't expand arguments"); +} + +Error Platform::KillProcess(const lldb::pid_t pid) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Platform::%s, pid %" PRIu64, __FUNCTION__, pid); + + // Try to find a process plugin to handle this Kill request. If we can't, + // fall back to + // the default OS implementation. + size_t num_debuggers = Debugger::GetNumDebuggers(); + for (size_t didx = 0; didx < num_debuggers; ++didx) { + DebuggerSP debugger = Debugger::GetDebuggerAtIndex(didx); + lldb_private::TargetList &targets = debugger->GetTargetList(); + for (int tidx = 0; tidx < targets.GetNumTargets(); ++tidx) { + ProcessSP process = targets.GetTargetAtIndex(tidx)->GetProcessSP(); + if (process->GetID() == pid) + return process->Destroy(true); } + } - if (!IsHost()) - { - return Error("base lldb_private::Platform class can't kill remote processes unless " - "they are controlled by a process plugin"); - } - Host::Kill(pid, SIGTERM); - return Error(); + if (!IsHost()) { + return Error( + "base lldb_private::Platform class can't kill remote processes unless " + "they are controlled by a process plugin"); + } + Host::Kill(pid, SIGTERM); + return Error(); } lldb::ProcessSP -Platform::DebugProcess (ProcessLaunchInfo &launch_info, - Debugger &debugger, - Target *target, // Can be nullptr, if nullptr create a new target, else use existing one - Error &error) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf ("Platform::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target)); - - ProcessSP process_sp; - // Make sure we stop at the entry point - launch_info.GetFlags ().Set (eLaunchFlagDebug); - // We always launch the process we are going to debug in a separate process - // group, since then we can handle ^C interrupts ourselves w/o having to worry - // about the target getting them as well. - launch_info.SetLaunchInSeparateProcessGroup(true); - - // Allow any StructuredData process-bound plugins to adjust the launch info - // if needed - size_t i = 0; - bool iteration_complete = false; - // Note iteration can't simply go until a nullptr callback is returned, as - // it is valid for a plugin to not supply a filter. - auto get_filter_func = - PluginManager::GetStructuredDataFilterCallbackAtIndex; - for (auto filter_callback = get_filter_func(i, iteration_complete); - !iteration_complete; - filter_callback = get_filter_func(++i, iteration_complete)) - { - if (filter_callback) - { - // Give this ProcessLaunchInfo filter a chance to adjust the launch - // info. - error = (*filter_callback)(launch_info, target); - if (!error.Success()) - { - if (log) - log->Printf("Platform::%s() StructuredDataPlugin launch " - "filter failed.", __FUNCTION__); - return process_sp; - } - } +Platform::DebugProcess(ProcessLaunchInfo &launch_info, Debugger &debugger, + Target *target, // Can be nullptr, if nullptr create a + // new target, else use existing one + Error &error) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("Platform::%s entered (target %p)", __FUNCTION__, + static_cast<void *>(target)); + + ProcessSP process_sp; + // Make sure we stop at the entry point + launch_info.GetFlags().Set(eLaunchFlagDebug); + // We always launch the process we are going to debug in a separate process + // group, since then we can handle ^C interrupts ourselves w/o having to worry + // about the target getting them as well. + launch_info.SetLaunchInSeparateProcessGroup(true); + + // Allow any StructuredData process-bound plugins to adjust the launch info + // if needed + size_t i = 0; + bool iteration_complete = false; + // Note iteration can't simply go until a nullptr callback is returned, as + // it is valid for a plugin to not supply a filter. + auto get_filter_func = PluginManager::GetStructuredDataFilterCallbackAtIndex; + for (auto filter_callback = get_filter_func(i, iteration_complete); + !iteration_complete; + filter_callback = get_filter_func(++i, iteration_complete)) { + if (filter_callback) { + // Give this ProcessLaunchInfo filter a chance to adjust the launch + // info. + error = (*filter_callback)(launch_info, target); + if (!error.Success()) { + if (log) + log->Printf("Platform::%s() StructuredDataPlugin launch " + "filter failed.", + __FUNCTION__); + return process_sp; + } } + } - error = LaunchProcess (launch_info); - if (error.Success()) - { + error = LaunchProcess(launch_info); + if (error.Success()) { + if (log) + log->Printf("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 + ")", + __FUNCTION__, launch_info.GetProcessID()); + if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) { + ProcessAttachInfo attach_info(launch_info); + process_sp = Attach(attach_info, debugger, target, error); + if (process_sp) { if (log) - log->Printf ("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")", __FUNCTION__, launch_info.GetProcessID ()); - if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID) - { - ProcessAttachInfo attach_info (launch_info); - process_sp = Attach (attach_info, debugger, target, error); - if (process_sp) - { - if (log) - log->Printf ("Platform::%s Attach() succeeded, Process plugin: %s", __FUNCTION__, process_sp->GetPluginName ().AsCString ()); - launch_info.SetHijackListener(attach_info.GetHijackListener()); - - // Since we attached to the process, it will think it needs to detach - // if the process object just goes away without an explicit call to - // Process::Kill() or Process::Detach(), so let it know to kill the - // process if this happens. - process_sp->SetShouldDetach (false); - - // If we didn't have any file actions, the pseudo terminal might - // have been used where the slave side was given as the file to - // open for stdin/out/err after we have already opened the master - // so we can read/write stdin/out/err. - int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); - if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) - { - process_sp->SetSTDIOFileDescriptor(pty_fd); - } - } - else - { - if (log) - log->Printf ("Platform::%s Attach() failed: %s", __FUNCTION__, error.AsCString ()); - } + log->Printf("Platform::%s Attach() succeeded, Process plugin: %s", + __FUNCTION__, process_sp->GetPluginName().AsCString()); + launch_info.SetHijackListener(attach_info.GetHijackListener()); + + // Since we attached to the process, it will think it needs to detach + // if the process object just goes away without an explicit call to + // Process::Kill() or Process::Detach(), so let it know to kill the + // process if this happens. + process_sp->SetShouldDetach(false); + + // If we didn't have any file actions, the pseudo terminal might + // have been used where the slave side was given as the file to + // open for stdin/out/err after we have already opened the master + // so we can read/write stdin/out/err. + int pty_fd = launch_info.GetPTY().ReleaseMasterFileDescriptor(); + if (pty_fd != lldb_utility::PseudoTerminal::invalid_fd) { + process_sp->SetSTDIOFileDescriptor(pty_fd); } - else - { - if (log) - log->Printf ("Platform::%s LaunchProcess() returned launch_info with invalid process id", __FUNCTION__); - } - } - else - { + } else { if (log) - log->Printf ("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, error.AsCString ()); + log->Printf("Platform::%s Attach() failed: %s", __FUNCTION__, + error.AsCString()); + } + } else { + if (log) + log->Printf("Platform::%s LaunchProcess() returned launch_info with " + "invalid process id", + __FUNCTION__); } + } else { + if (log) + log->Printf("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, + error.AsCString()); + } - return process_sp; + return process_sp; } lldb::PlatformSP -Platform::GetPlatformForArchitecture (const ArchSpec &arch, ArchSpec *platform_arch_ptr) -{ - lldb::PlatformSP platform_sp; - Error error; - if (arch.IsValid()) - platform_sp = Platform::Create (arch, platform_arch_ptr, error); - return platform_sp; +Platform::GetPlatformForArchitecture(const ArchSpec &arch, + ArchSpec *platform_arch_ptr) { + lldb::PlatformSP platform_sp; + Error error; + if (arch.IsValid()) + platform_sp = Platform::Create(arch, platform_arch_ptr, error); + return platform_sp; } //------------------------------------------------------------------ /// Lets a platform answer if it is compatible with a given /// architecture and the target triple contained within. //------------------------------------------------------------------ -bool -Platform::IsCompatibleArchitecture (const ArchSpec &arch, bool exact_arch_match, ArchSpec *compatible_arch_ptr) -{ - // If the architecture is invalid, we must answer true... - if (arch.IsValid()) - { - ArchSpec platform_arch; - // Try for an exact architecture match first. - if (exact_arch_match) - { - for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx) - { - if (arch.IsExactMatch(platform_arch)) - { - if (compatible_arch_ptr) - *compatible_arch_ptr = platform_arch; - return true; - } - } +bool Platform::IsCompatibleArchitecture(const ArchSpec &arch, + bool exact_arch_match, + ArchSpec *compatible_arch_ptr) { + // If the architecture is invalid, we must answer true... + if (arch.IsValid()) { + ArchSpec platform_arch; + // Try for an exact architecture match first. + if (exact_arch_match) { + for (uint32_t arch_idx = 0; + GetSupportedArchitectureAtIndex(arch_idx, platform_arch); + ++arch_idx) { + if (arch.IsExactMatch(platform_arch)) { + if (compatible_arch_ptr) + *compatible_arch_ptr = platform_arch; + return true; } - else - { - for (uint32_t arch_idx=0; GetSupportedArchitectureAtIndex (arch_idx, platform_arch); ++arch_idx) - { - if (arch.IsCompatibleMatch(platform_arch)) - { - if (compatible_arch_ptr) - *compatible_arch_ptr = platform_arch; - return true; - } - } + } + } else { + for (uint32_t arch_idx = 0; + GetSupportedArchitectureAtIndex(arch_idx, platform_arch); + ++arch_idx) { + if (arch.IsCompatibleMatch(platform_arch)) { + if (compatible_arch_ptr) + *compatible_arch_ptr = platform_arch; + return true; } + } } - if (compatible_arch_ptr) - compatible_arch_ptr->Clear(); - return false; -} - -Error -Platform::PutFile (const FileSpec& source, - const FileSpec& destination, - uint32_t uid, - uint32_t gid) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM)); - if (log) - log->Printf("[PutFile] Using block by block transfer....\n"); - - uint32_t source_open_options = File::eOpenOptionRead | File::eOpenOptionCloseOnExec; - if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink) - source_open_options |= File::eOpenOptionDontFollowSymlinks; - - File source_file(source, source_open_options, lldb::eFilePermissionsUserRW); - Error error; - uint32_t permissions = source_file.GetPermissions(error); - if (permissions == 0) - permissions = lldb::eFilePermissionsFileDefault; - - if (!source_file.IsValid()) - return Error("PutFile: unable to open source file"); - lldb::user_id_t dest_file = OpenFile (destination, - File::eOpenOptionCanCreate | - File::eOpenOptionWrite | - File::eOpenOptionTruncate | - File::eOpenOptionCloseOnExec, - permissions, - error); - if (log) - log->Printf ("dest_file = %" PRIu64 "\n", dest_file); - + } + if (compatible_arch_ptr) + compatible_arch_ptr->Clear(); + return false; +} + +Error Platform::PutFile(const FileSpec &source, const FileSpec &destination, + uint32_t uid, uint32_t gid) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PLATFORM)); + if (log) + log->Printf("[PutFile] Using block by block transfer....\n"); + + uint32_t source_open_options = + File::eOpenOptionRead | File::eOpenOptionCloseOnExec; + if (source.GetFileType() == FileSpec::eFileTypeSymbolicLink) + source_open_options |= File::eOpenOptionDontFollowSymlinks; + + File source_file(source, source_open_options, lldb::eFilePermissionsUserRW); + Error error; + uint32_t permissions = source_file.GetPermissions(error); + if (permissions == 0) + permissions = lldb::eFilePermissionsFileDefault; + + if (!source_file.IsValid()) + return Error("PutFile: unable to open source file"); + lldb::user_id_t dest_file = OpenFile( + destination, File::eOpenOptionCanCreate | File::eOpenOptionWrite | + File::eOpenOptionTruncate | File::eOpenOptionCloseOnExec, + permissions, error); + if (log) + log->Printf("dest_file = %" PRIu64 "\n", dest_file); + + if (error.Fail()) + return error; + if (dest_file == UINT64_MAX) + return Error("unable to open target file"); + lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); + uint64_t offset = 0; + for (;;) { + size_t bytes_read = buffer_sp->GetByteSize(); + error = source_file.Read(buffer_sp->GetBytes(), bytes_read); + if (error.Fail() || bytes_read == 0) + break; + + const uint64_t bytes_written = + WriteFile(dest_file, offset, buffer_sp->GetBytes(), bytes_read, error); if (error.Fail()) - return error; - if (dest_file == UINT64_MAX) - return Error("unable to open target file"); - lldb::DataBufferSP buffer_sp(new DataBufferHeap(1024, 0)); - uint64_t offset = 0; - for (;;) - { - size_t bytes_read = buffer_sp->GetByteSize(); - error = source_file.Read(buffer_sp->GetBytes(), bytes_read); - if (error.Fail() || bytes_read == 0) - break; - - const uint64_t bytes_written = WriteFile(dest_file, offset, - buffer_sp->GetBytes(), bytes_read, error); - if (error.Fail()) - break; - - offset += bytes_written; - if (bytes_written != bytes_read) - { - // We didn't write the correct number of bytes, so adjust - // the file position in the source file we are reading from... - source_file.SeekFromStart(offset); - } + break; + + offset += bytes_written; + if (bytes_written != bytes_read) { + // We didn't write the correct number of bytes, so adjust + // the file position in the source file we are reading from... + source_file.SeekFromStart(offset); } - CloseFile(dest_file, error); + } + CloseFile(dest_file, error); - if (uid == UINT32_MAX && gid == UINT32_MAX) - return error; + if (uid == UINT32_MAX && gid == UINT32_MAX) + return error; - // TODO: ChownFile? + // TODO: ChownFile? - return error; + return error; } -Error -Platform::GetFile(const FileSpec &source, - const FileSpec &destination) -{ - Error error("unimplemented"); - return error; +Error Platform::GetFile(const FileSpec &source, const FileSpec &destination) { + Error error("unimplemented"); + return error; } -Error -Platform::CreateSymlink(const FileSpec &src, // The name of the link is in src - const FileSpec &dst) // The symlink points to dst +Error Platform::CreateSymlink( + const FileSpec &src, // The name of the link is in src + const FileSpec &dst) // The symlink points to dst { - Error error("unimplemented"); - return error; + Error error("unimplemented"); + return error; } -bool -Platform::GetFileExists(const lldb_private::FileSpec &file_spec) -{ - return false; +bool Platform::GetFileExists(const lldb_private::FileSpec &file_spec) { + return false; } -Error -Platform::Unlink(const FileSpec &path) -{ - Error error("unimplemented"); - return error; +Error Platform::Unlink(const FileSpec &path) { + Error error("unimplemented"); + return error; } -uint64_t -Platform::ConvertMmapFlagsToPlatform(const ArchSpec &arch, unsigned flags) -{ - uint64_t flags_platform = 0; - if (flags & eMmapFlagsPrivate) - flags_platform |= MAP_PRIVATE; - if (flags & eMmapFlagsAnon) - flags_platform |= MAP_ANON; - return flags_platform; +uint64_t Platform::ConvertMmapFlagsToPlatform(const ArchSpec &arch, + unsigned flags) { + uint64_t flags_platform = 0; + if (flags & eMmapFlagsPrivate) + flags_platform |= MAP_PRIVATE; + if (flags & eMmapFlagsAnon) + flags_platform |= MAP_ANON; + return flags_platform; } -lldb_private::Error -Platform::RunShellCommand(const char *command, // Shouldn't be nullptr - const FileSpec &working_dir, // Pass empty FileSpec to use the current working directory - int *status_ptr, // Pass nullptr if you don't want the process exit status - int *signo_ptr, // Pass nullptr if you don't want the signal that caused the process to exit - std::string *command_output, // Pass nullptr if you don't want the command output - uint32_t timeout_sec) // Timeout in seconds to wait for shell program to finish +lldb_private::Error Platform::RunShellCommand( + const char *command, // Shouldn't be nullptr + const FileSpec & + working_dir, // Pass empty FileSpec to use the current working directory + int *status_ptr, // Pass nullptr if you don't want the process exit status + int *signo_ptr, // Pass nullptr if you don't want the signal that caused the + // process to exit + std::string + *command_output, // Pass nullptr if you don't want the command output + uint32_t + timeout_sec) // Timeout in seconds to wait for shell program to finish { - if (IsHost()) - return Host::RunShellCommand (command, working_dir, status_ptr, signo_ptr, command_output, timeout_sec); - else - return Error("unimplemented"); + if (IsHost()) + return Host::RunShellCommand(command, working_dir, status_ptr, signo_ptr, + command_output, timeout_sec); + else + return Error("unimplemented"); } -bool -Platform::CalculateMD5 (const FileSpec& file_spec, - uint64_t &low, - uint64_t &high) -{ - if (IsHost()) - return FileSystem::CalculateMD5(file_spec, low, high); - else - return false; +bool Platform::CalculateMD5(const FileSpec &file_spec, uint64_t &low, + uint64_t &high) { + if (IsHost()) + return FileSystem::CalculateMD5(file_spec, low, high); + else + return false; } -void -Platform::SetLocalCacheDirectory (const char* local) -{ - m_local_cache_directory.assign(local); +void Platform::SetLocalCacheDirectory(const char *local) { + m_local_cache_directory.assign(local); } -const char* -Platform::GetLocalCacheDirectory () -{ - return m_local_cache_directory.c_str(); +const char *Platform::GetLocalCacheDirectory() { + return m_local_cache_directory.c_str(); } -static OptionDefinition -g_rsync_option_table[] = -{ - { LLDB_OPT_SET_ALL, false, "rsync" , 'r', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone , "Enable rsync." }, - { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." }, - { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." }, - { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone , "Do not automatically fill in the remote hostname when composing the rsync command." }, +static OptionDefinition g_rsync_option_table[] = { + {LLDB_OPT_SET_ALL, false, "rsync", 'r', OptionParser::eNoArgument, nullptr, + nullptr, 0, eArgTypeNone, "Enable rsync."}, + {LLDB_OPT_SET_ALL, false, "rsync-opts", 'R', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommandName, + "Platform-specific options required for rsync to work."}, + {LLDB_OPT_SET_ALL, false, "rsync-prefix", 'P', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommandName, + "Platform-specific rsync prefix put before the remote path."}, + {LLDB_OPT_SET_ALL, false, "ignore-remote-hostname", 'i', + OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, + "Do not automatically fill in the remote hostname when composing the " + "rsync command."}, }; -static OptionDefinition -g_ssh_option_table[] = -{ - { LLDB_OPT_SET_ALL, false, "ssh" , 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone , "Enable SSH." }, - { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeCommandName , "Platform-specific options required for SSH to work." }, +static OptionDefinition g_ssh_option_table[] = { + {LLDB_OPT_SET_ALL, false, "ssh", 's', OptionParser::eNoArgument, nullptr, + nullptr, 0, eArgTypeNone, "Enable SSH."}, + {LLDB_OPT_SET_ALL, false, "ssh-opts", 'S', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeCommandName, + "Platform-specific options required for SSH to work."}, }; -static OptionDefinition -g_caching_option_table[] = -{ - { LLDB_OPT_SET_ALL, false, "local-cache-dir" , 'c', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePath , "Path in which to store local copies of files." }, +static OptionDefinition g_caching_option_table[] = { + {LLDB_OPT_SET_ALL, false, "local-cache-dir", 'c', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePath, + "Path in which to store local copies of files."}, }; -const lldb_private::OptionDefinition* -OptionGroupPlatformRSync::GetDefinitions () -{ - return g_rsync_option_table; +const lldb_private::OptionDefinition * +OptionGroupPlatformRSync::GetDefinitions() { + return g_rsync_option_table; } -void -OptionGroupPlatformRSync::OptionParsingStarting(ExecutionContext *execution_context) -{ - m_rsync = false; - m_rsync_opts.clear(); - m_rsync_prefix.clear(); - m_ignores_remote_hostname = false; +void OptionGroupPlatformRSync::OptionParsingStarting( + ExecutionContext *execution_context) { + m_rsync = false; + m_rsync_opts.clear(); + m_rsync_prefix.clear(); + m_ignores_remote_hostname = false; } lldb_private::Error OptionGroupPlatformRSync::SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) -{ - Error error; - char short_option = (char) GetDefinitions()[option_idx].short_option; - switch (short_option) - { - case 'r': - m_rsync = true; - break; - - case 'R': - m_rsync_opts.assign(option_arg); - break; - - case 'P': - m_rsync_prefix.assign(option_arg); - break; - - case 'i': - m_ignores_remote_hostname = true; - break; - - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; + ExecutionContext *execution_context) { + Error error; + char short_option = (char)GetDefinitions()[option_idx].short_option; + switch (short_option) { + case 'r': + m_rsync = true; + break; + + case 'R': + m_rsync_opts.assign(option_arg); + break; + + case 'P': + m_rsync_prefix.assign(option_arg); + break; + + case 'i': + m_ignores_remote_hostname = true; + break; + + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); + break; + } + + return error; } -uint32_t -OptionGroupPlatformRSync::GetNumDefinitions () -{ - return llvm::array_lengthof(g_rsync_option_table); +uint32_t OptionGroupPlatformRSync::GetNumDefinitions() { + return llvm::array_lengthof(g_rsync_option_table); } lldb::BreakpointSP -Platform::SetThreadCreationBreakpoint (lldb_private::Target &target) -{ - return lldb::BreakpointSP(); +Platform::SetThreadCreationBreakpoint(lldb_private::Target &target) { + return lldb::BreakpointSP(); } -const lldb_private::OptionDefinition* -OptionGroupPlatformSSH::GetDefinitions () -{ - return g_ssh_option_table; +const lldb_private::OptionDefinition *OptionGroupPlatformSSH::GetDefinitions() { + return g_ssh_option_table; } -void -OptionGroupPlatformSSH::OptionParsingStarting(ExecutionContext - *execution_context) -{ - m_ssh = false; - m_ssh_opts.clear(); +void OptionGroupPlatformSSH::OptionParsingStarting( + ExecutionContext *execution_context) { + m_ssh = false; + m_ssh_opts.clear(); } lldb_private::Error OptionGroupPlatformSSH::SetOptionValue(uint32_t option_idx, const char *option_arg, - ExecutionContext *execution_context) -{ - Error error; - char short_option = (char) GetDefinitions()[option_idx].short_option; - switch (short_option) - { - case 's': - m_ssh = true; - break; - - case 'S': - m_ssh_opts.assign(option_arg); - break; - - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; -} + ExecutionContext *execution_context) { + Error error; + char short_option = (char)GetDefinitions()[option_idx].short_option; + switch (short_option) { + case 's': + m_ssh = true; + break; -uint32_t -OptionGroupPlatformSSH::GetNumDefinitions () -{ - return llvm::array_lengthof(g_ssh_option_table); -} + case 'S': + m_ssh_opts.assign(option_arg); + break; -const lldb_private::OptionDefinition* -OptionGroupPlatformCaching::GetDefinitions () -{ - return g_caching_option_table; -} + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); + break; + } -void -OptionGroupPlatformCaching::OptionParsingStarting(ExecutionContext - *execution_context) -{ - m_cache_dir.clear(); + return error; } -lldb_private::Error -OptionGroupPlatformCaching::SetOptionValue(uint32_t option_idx, - const char *option_arg, - ExecutionContext *execution_context) -{ - Error error; - char short_option = (char) GetDefinitions()[option_idx].short_option; - switch (short_option) - { - case 'c': - m_cache_dir.assign(option_arg); - break; - - default: - error.SetErrorStringWithFormat ("unrecognized option '%c'", short_option); - break; - } - - return error; +uint32_t OptionGroupPlatformSSH::GetNumDefinitions() { + return llvm::array_lengthof(g_ssh_option_table); } -uint32_t -OptionGroupPlatformCaching::GetNumDefinitions () -{ - return llvm::array_lengthof(g_caching_option_table); +const lldb_private::OptionDefinition * +OptionGroupPlatformCaching::GetDefinitions() { + return g_caching_option_table; } -size_t -Platform::GetEnvironment (StringList &environment) -{ - environment.Clear(); - return false; +void OptionGroupPlatformCaching::OptionParsingStarting( + ExecutionContext *execution_context) { + m_cache_dir.clear(); } -const std::vector<ConstString> & -Platform::GetTrapHandlerSymbolNames () -{ - if (!m_calculated_trap_handlers) - { - std::lock_guard<std::mutex> guard(m_mutex); - if (!m_calculated_trap_handlers) - { - CalculateTrapHandlerSymbolNames(); - m_calculated_trap_handlers = true; - } - } - return m_trap_handlers; +lldb_private::Error OptionGroupPlatformCaching::SetOptionValue( + uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) { + Error error; + char short_option = (char)GetDefinitions()[option_idx].short_option; + switch (short_option) { + case 'c': + m_cache_dir.assign(option_arg); + break; + + default: + error.SetErrorStringWithFormat("unrecognized option '%c'", short_option); + break; + } + + return error; } -Error -Platform::GetCachedExecutable (ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - Platform &remote_platform) -{ - const auto platform_spec = module_spec.GetFileSpec (); - const auto error = LoadCachedExecutable (module_spec, - module_sp, - module_search_paths_ptr, - remote_platform); - if (error.Success ()) - { - module_spec.GetFileSpec () = module_sp->GetFileSpec (); - module_spec.GetPlatformFileSpec () = platform_spec; - } +uint32_t OptionGroupPlatformCaching::GetNumDefinitions() { + return llvm::array_lengthof(g_caching_option_table); +} - return error; +size_t Platform::GetEnvironment(StringList &environment) { + environment.Clear(); + return false; } -Error -Platform::LoadCachedExecutable (const ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - const FileSpecList *module_search_paths_ptr, - Platform &remote_platform) -{ - return GetRemoteSharedModule (module_spec, - nullptr, - module_sp, - [&](const ModuleSpec &spec) - { - return remote_platform.ResolveExecutable ( - spec, module_sp, module_search_paths_ptr); - }, - nullptr); -} - -Error -Platform::GetRemoteSharedModule (const ModuleSpec &module_spec, - Process* process, - lldb::ModuleSP &module_sp, - const ModuleResolver &module_resolver, - bool *did_create_ptr) -{ - // Get module information from a target. - ModuleSpec resolved_module_spec; - bool got_module_spec = false; - if (process) - { - // Try to get module information from the process - if (process->GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec)) - { - if (module_spec.GetUUID().IsValid() == false || module_spec.GetUUID() == resolved_module_spec.GetUUID()) - { - got_module_spec = true; - } - } +const std::vector<ConstString> &Platform::GetTrapHandlerSymbolNames() { + if (!m_calculated_trap_handlers) { + std::lock_guard<std::mutex> guard(m_mutex); + if (!m_calculated_trap_handlers) { + CalculateTrapHandlerSymbolNames(); + m_calculated_trap_handlers = true; } - - if (!got_module_spec) - { - // Get module information from a target. - if (!GetModuleSpec (module_spec.GetFileSpec (), module_spec.GetArchitecture (), resolved_module_spec)) - { - if (module_spec.GetUUID().IsValid() == false || module_spec.GetUUID() == resolved_module_spec.GetUUID()) - { - return module_resolver (module_spec); - } - } + } + return m_trap_handlers; +} + +Error Platform::GetCachedExecutable(ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, + Platform &remote_platform) { + const auto platform_spec = module_spec.GetFileSpec(); + const auto error = LoadCachedExecutable( + module_spec, module_sp, module_search_paths_ptr, remote_platform); + if (error.Success()) { + module_spec.GetFileSpec() = module_sp->GetFileSpec(); + module_spec.GetPlatformFileSpec() = platform_spec; + } + + return error; +} + +Error Platform::LoadCachedExecutable( + const ModuleSpec &module_spec, lldb::ModuleSP &module_sp, + const FileSpecList *module_search_paths_ptr, Platform &remote_platform) { + return GetRemoteSharedModule(module_spec, nullptr, module_sp, + [&](const ModuleSpec &spec) { + return remote_platform.ResolveExecutable( + spec, module_sp, module_search_paths_ptr); + }, + nullptr); +} + +Error Platform::GetRemoteSharedModule(const ModuleSpec &module_spec, + Process *process, + lldb::ModuleSP &module_sp, + const ModuleResolver &module_resolver, + bool *did_create_ptr) { + // Get module information from a target. + ModuleSpec resolved_module_spec; + bool got_module_spec = false; + if (process) { + // Try to get module information from the process + if (process->GetModuleSpec(module_spec.GetFileSpec(), + module_spec.GetArchitecture(), + resolved_module_spec)) { + if (module_spec.GetUUID().IsValid() == false || + module_spec.GetUUID() == resolved_module_spec.GetUUID()) { + got_module_spec = true; + } } + } - // If we are looking for a specific UUID, make sure resolved_module_spec has the same one before we search. - if (module_spec.GetUUID().IsValid()) - { - resolved_module_spec.GetUUID() = module_spec.GetUUID(); + if (!got_module_spec) { + // Get module information from a target. + if (!GetModuleSpec(module_spec.GetFileSpec(), module_spec.GetArchitecture(), + resolved_module_spec)) { + if (module_spec.GetUUID().IsValid() == false || + module_spec.GetUUID() == resolved_module_spec.GetUUID()) { + return module_resolver(module_spec); + } } + } - // Trying to find a module by UUID on local file system. - const auto error = module_resolver (resolved_module_spec); - if (error.Fail ()) - { - if (GetCachedSharedModule (resolved_module_spec, module_sp, did_create_ptr)) - return Error (); - } + // If we are looking for a specific UUID, make sure resolved_module_spec has + // the same one before we search. + if (module_spec.GetUUID().IsValid()) { + resolved_module_spec.GetUUID() = module_spec.GetUUID(); + } - return error; -} + // Trying to find a module by UUID on local file system. + const auto error = module_resolver(resolved_module_spec); + if (error.Fail()) { + if (GetCachedSharedModule(resolved_module_spec, module_sp, did_create_ptr)) + return Error(); + } -bool -Platform::GetCachedSharedModule (const ModuleSpec &module_spec, - lldb::ModuleSP &module_sp, - bool *did_create_ptr) -{ - if (IsHost() || - !GetGlobalPlatformProperties ()->GetUseModuleCache () || - !GetGlobalPlatformProperties ()->GetModuleCacheDirectory ()) - return false; - - Log *log = GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PLATFORM); - - // Check local cache for a module. - auto error = m_module_cache->GetAndPut ( - GetModuleCacheRoot (), - GetCacheHostname (), - module_spec, - [this](const ModuleSpec &module_spec, const FileSpec &tmp_download_file_spec) - { - return DownloadModuleSlice (module_spec.GetFileSpec (), - module_spec.GetObjectOffset (), - module_spec.GetObjectSize (), - tmp_download_file_spec); - - }, - [this](const ModuleSP& module_sp, const FileSpec& tmp_download_file_spec) - { - return DownloadSymbolFile (module_sp, tmp_download_file_spec); - }, - module_sp, - did_create_ptr); - if (error.Success ()) - return true; + return error; +} - if (log) - log->Printf("Platform::%s - module %s not found in local cache: %s", - __FUNCTION__, module_spec.GetUUID ().GetAsString ().c_str (), error.AsCString ()); +bool Platform::GetCachedSharedModule(const ModuleSpec &module_spec, + lldb::ModuleSP &module_sp, + bool *did_create_ptr) { + if (IsHost() || !GetGlobalPlatformProperties()->GetUseModuleCache() || + !GetGlobalPlatformProperties()->GetModuleCacheDirectory()) return false; + + Log *log = GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PLATFORM); + + // Check local cache for a module. + auto error = m_module_cache->GetAndPut( + GetModuleCacheRoot(), GetCacheHostname(), module_spec, + [this](const ModuleSpec &module_spec, + const FileSpec &tmp_download_file_spec) { + return DownloadModuleSlice( + module_spec.GetFileSpec(), module_spec.GetObjectOffset(), + module_spec.GetObjectSize(), tmp_download_file_spec); + + }, + [this](const ModuleSP &module_sp, + const FileSpec &tmp_download_file_spec) { + return DownloadSymbolFile(module_sp, tmp_download_file_spec); + }, + module_sp, did_create_ptr); + if (error.Success()) + return true; + + if (log) + log->Printf("Platform::%s - module %s not found in local cache: %s", + __FUNCTION__, module_spec.GetUUID().GetAsString().c_str(), + error.AsCString()); + return false; } -Error -Platform::DownloadModuleSlice (const FileSpec& src_file_spec, - const uint64_t src_offset, - const uint64_t src_size, - const FileSpec& dst_file_spec) -{ - Error error; +Error Platform::DownloadModuleSlice(const FileSpec &src_file_spec, + const uint64_t src_offset, + const uint64_t src_size, + const FileSpec &dst_file_spec) { + Error error; - std::ofstream dst (dst_file_spec.GetPath(), std::ios::out | std::ios::binary); - if (!dst.is_open()) - { - error.SetErrorStringWithFormat ("unable to open destination file: %s", dst_file_spec.GetPath ().c_str ()); - return error; - } + std::ofstream dst(dst_file_spec.GetPath(), std::ios::out | std::ios::binary); + if (!dst.is_open()) { + error.SetErrorStringWithFormat("unable to open destination file: %s", + dst_file_spec.GetPath().c_str()); + return error; + } - auto src_fd = OpenFile (src_file_spec, - File::eOpenOptionRead, - lldb::eFilePermissionsFileDefault, - error); - - if (error.Fail ()) - { - error.SetErrorStringWithFormat ("unable to open source file: %s", error.AsCString ()); - return error; - } - - std::vector<char> buffer (1024); - auto offset = src_offset; - uint64_t total_bytes_read = 0; - while (total_bytes_read < src_size) - { - const auto to_read = std::min (static_cast<uint64_t>(buffer.size ()), src_size - total_bytes_read); - const uint64_t n_read = ReadFile (src_fd, offset, &buffer[0], to_read, error); - if (error.Fail ()) - break; - if (n_read == 0) - { - error.SetErrorString ("read 0 bytes"); - break; - } - offset += n_read; - total_bytes_read += n_read; - dst.write (&buffer[0], n_read); + auto src_fd = OpenFile(src_file_spec, File::eOpenOptionRead, + lldb::eFilePermissionsFileDefault, error); + + if (error.Fail()) { + error.SetErrorStringWithFormat("unable to open source file: %s", + error.AsCString()); + return error; + } + + std::vector<char> buffer(1024); + auto offset = src_offset; + uint64_t total_bytes_read = 0; + while (total_bytes_read < src_size) { + const auto to_read = std::min(static_cast<uint64_t>(buffer.size()), + src_size - total_bytes_read); + const uint64_t n_read = + ReadFile(src_fd, offset, &buffer[0], to_read, error); + if (error.Fail()) + break; + if (n_read == 0) { + error.SetErrorString("read 0 bytes"); + break; } + offset += n_read; + total_bytes_read += n_read; + dst.write(&buffer[0], n_read); + } - Error close_error; - CloseFile (src_fd, close_error); // Ignoring close error. + Error close_error; + CloseFile(src_fd, close_error); // Ignoring close error. - return error; + return error; } -Error -Platform::DownloadSymbolFile (const lldb::ModuleSP& module_sp, const FileSpec& dst_file_spec) -{ - return Error ("Symbol file downloading not supported by the default platform."); +Error Platform::DownloadSymbolFile(const lldb::ModuleSP &module_sp, + const FileSpec &dst_file_spec) { + return Error( + "Symbol file downloading not supported by the default platform."); } -FileSpec -Platform::GetModuleCacheRoot () -{ - auto dir_spec = GetGlobalPlatformProperties ()->GetModuleCacheDirectory (); - dir_spec.AppendPathComponent (GetName ().AsCString ()); - return dir_spec; +FileSpec Platform::GetModuleCacheRoot() { + auto dir_spec = GetGlobalPlatformProperties()->GetModuleCacheDirectory(); + dir_spec.AppendPathComponent(GetName().AsCString()); + return dir_spec; } -const char * -Platform::GetCacheHostname () -{ - return GetHostname (); -} +const char *Platform::GetCacheHostname() { return GetHostname(); } -const UnixSignalsSP & -Platform::GetRemoteUnixSignals() -{ - static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>(); - return s_default_unix_signals_sp; +const UnixSignalsSP &Platform::GetRemoteUnixSignals() { + static const auto s_default_unix_signals_sp = std::make_shared<UnixSignals>(); + return s_default_unix_signals_sp; } -const UnixSignalsSP & -Platform::GetUnixSignals() -{ - if (IsHost()) - return Host::GetUnixSignals(); - return GetRemoteUnixSignals(); +const UnixSignalsSP &Platform::GetUnixSignals() { + if (IsHost()) + return Host::GetUnixSignals(); + return GetRemoteUnixSignals(); } -uint32_t -Platform::LoadImage(lldb_private::Process* process, - const lldb_private::FileSpec& local_file, - const lldb_private::FileSpec& remote_file, - lldb_private::Error& error) -{ - if (local_file && remote_file) - { - // Both local and remote file was specified. Install the local file to the given location. - if (IsRemote() || local_file != remote_file) - { - error = Install(local_file, remote_file); - if (error.Fail()) - return LLDB_INVALID_IMAGE_TOKEN; - } - return DoLoadImage(process, remote_file, error); +uint32_t Platform::LoadImage(lldb_private::Process *process, + const lldb_private::FileSpec &local_file, + const lldb_private::FileSpec &remote_file, + lldb_private::Error &error) { + if (local_file && remote_file) { + // Both local and remote file was specified. Install the local file to the + // given location. + if (IsRemote() || local_file != remote_file) { + error = Install(local_file, remote_file); + if (error.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; } - - if (local_file) - { - // Only local file was specified. Install it to the current working directory. - FileSpec target_file = GetWorkingDirectory(); - target_file.AppendPathComponent(local_file.GetFilename().AsCString()); - if (IsRemote() || local_file != target_file) - { - error = Install(local_file, target_file); - if (error.Fail()) - return LLDB_INVALID_IMAGE_TOKEN; - } - return DoLoadImage(process, target_file, error); + return DoLoadImage(process, remote_file, error); + } + + if (local_file) { + // Only local file was specified. Install it to the current working + // directory. + FileSpec target_file = GetWorkingDirectory(); + target_file.AppendPathComponent(local_file.GetFilename().AsCString()); + if (IsRemote() || local_file != target_file) { + error = Install(local_file, target_file); + if (error.Fail()) + return LLDB_INVALID_IMAGE_TOKEN; } + return DoLoadImage(process, target_file, error); + } - if (remote_file) - { - // Only remote file was specified so we don't have to do any copying - return DoLoadImage(process, remote_file, error); - } + if (remote_file) { + // Only remote file was specified so we don't have to do any copying + return DoLoadImage(process, remote_file, error); + } - error.SetErrorString("Neither local nor remote file was specified"); - return LLDB_INVALID_IMAGE_TOKEN; + error.SetErrorString("Neither local nor remote file was specified"); + return LLDB_INVALID_IMAGE_TOKEN; } -uint32_t -Platform::DoLoadImage (lldb_private::Process* process, - const lldb_private::FileSpec& remote_file, - lldb_private::Error& error) -{ - error.SetErrorString("LoadImage is not supported on the current platform"); - return LLDB_INVALID_IMAGE_TOKEN; +uint32_t Platform::DoLoadImage(lldb_private::Process *process, + const lldb_private::FileSpec &remote_file, + lldb_private::Error &error) { + error.SetErrorString("LoadImage is not supported on the current platform"); + return LLDB_INVALID_IMAGE_TOKEN; } -Error -Platform::UnloadImage(lldb_private::Process* process, uint32_t image_token) -{ - return Error("UnloadImage is not supported on the current platform"); +Error Platform::UnloadImage(lldb_private::Process *process, + uint32_t image_token) { + return Error("UnloadImage is not supported on the current platform"); } -lldb::ProcessSP -Platform::ConnectProcess(const char* connect_url, - const char* plugin_name, - lldb_private::Debugger &debugger, - lldb_private::Target *target, - lldb_private::Error &error) -{ - error.Clear(); +lldb::ProcessSP Platform::ConnectProcess(const char *connect_url, + const char *plugin_name, + lldb_private::Debugger &debugger, + lldb_private::Target *target, + lldb_private::Error &error) { + error.Clear(); - if (!target) - { - TargetSP new_target_sp; - error = debugger.GetTargetList().CreateTarget(debugger, - nullptr, - nullptr, - false, - nullptr, - new_target_sp); - target = new_target_sp.get(); - } + if (!target) { + TargetSP new_target_sp; + error = debugger.GetTargetList().CreateTarget( + debugger, nullptr, nullptr, false, nullptr, new_target_sp); + target = new_target_sp.get(); + } - if (!target || error.Fail()) - return nullptr; + if (!target || error.Fail()) + return nullptr; - debugger.GetTargetList().SetSelectedTarget(target); + debugger.GetTargetList().SetSelectedTarget(target); - lldb::ProcessSP process_sp = target->CreateProcess(debugger.GetListener(), - plugin_name, - nullptr); - if (!process_sp) - return nullptr; + lldb::ProcessSP process_sp = + target->CreateProcess(debugger.GetListener(), plugin_name, nullptr); + if (!process_sp) + return nullptr; - error = process_sp->ConnectRemote(debugger.GetOutputFile().get(), connect_url); - if (error.Fail()) - return nullptr; + error = + process_sp->ConnectRemote(debugger.GetOutputFile().get(), connect_url); + if (error.Fail()) + return nullptr; - return process_sp; + return process_sp; } -size_t -Platform::ConnectToWaitingProcesses(lldb_private::Debugger& debugger, lldb_private::Error& error) -{ - error.Clear(); - return 0; +size_t Platform::ConnectToWaitingProcesses(lldb_private::Debugger &debugger, + lldb_private::Error &error) { + error.Clear(); + return 0; } -size_t -Platform::GetSoftwareBreakpointTrapOpcode(Target &target, BreakpointSite *bp_site) -{ - ArchSpec arch = target.GetArchitecture(); - const uint8_t *trap_opcode = nullptr; - size_t trap_opcode_size = 0; +size_t Platform::GetSoftwareBreakpointTrapOpcode(Target &target, + BreakpointSite *bp_site) { + ArchSpec arch = target.GetArchitecture(); + const uint8_t *trap_opcode = nullptr; + size_t trap_opcode_size = 0; - switch (arch.GetMachine()) - { - case llvm::Triple::aarch64: - { - static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4}; - trap_opcode = g_aarch64_opcode; - trap_opcode_size = sizeof(g_aarch64_opcode); - } - break; - - // TODO: support big-endian arm and thumb trap codes. - case llvm::Triple::arm: - { - // The ARM reference recommends the use of 0xe7fddefe and 0xdefe - // but the linux kernel does otherwise. - static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; - static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; - - lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); - AddressClass addr_class = eAddressClassUnknown; - - if (bp_loc_sp) - { - addr_class = bp_loc_sp->GetAddress().GetAddressClass(); - if (addr_class == eAddressClassUnknown && (bp_loc_sp->GetAddress().GetFileAddress() & 1)) - addr_class = eAddressClassCodeAlternateISA; - } - - if (addr_class == eAddressClassCodeAlternateISA) - { - trap_opcode = g_thumb_breakpoint_opcode; - trap_opcode_size = sizeof(g_thumb_breakpoint_opcode); - } - else - { - trap_opcode = g_arm_breakpoint_opcode; - trap_opcode_size = sizeof(g_arm_breakpoint_opcode); - } - } - break; - - case llvm::Triple::mips: - case llvm::Triple::mips64: - { - static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d}; - trap_opcode = g_hex_opcode; - trap_opcode_size = sizeof(g_hex_opcode); - } - break; - - case llvm::Triple::mipsel: - case llvm::Triple::mips64el: - { - static const uint8_t g_hex_opcode[] = {0x0d, 0x00, 0x00, 0x00}; - trap_opcode = g_hex_opcode; - trap_opcode_size = sizeof(g_hex_opcode); - } - break; + switch (arch.GetMachine()) { + case llvm::Triple::aarch64: { + static const uint8_t g_aarch64_opcode[] = {0x00, 0x00, 0x20, 0xd4}; + trap_opcode = g_aarch64_opcode; + trap_opcode_size = sizeof(g_aarch64_opcode); + } break; - case llvm::Triple::systemz: - { - static const uint8_t g_hex_opcode[] = {0x00, 0x01}; - trap_opcode = g_hex_opcode; - trap_opcode_size = sizeof(g_hex_opcode); - } - break; + // TODO: support big-endian arm and thumb trap codes. + case llvm::Triple::arm: { + // The ARM reference recommends the use of 0xe7fddefe and 0xdefe + // but the linux kernel does otherwise. + static const uint8_t g_arm_breakpoint_opcode[] = {0xf0, 0x01, 0xf0, 0xe7}; + static const uint8_t g_thumb_breakpoint_opcode[] = {0x01, 0xde}; - case llvm::Triple::hexagon: - { - static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54}; - trap_opcode = g_hex_opcode; - trap_opcode_size = sizeof(g_hex_opcode); - } - break; - - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - { - static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; - trap_opcode = g_ppc_opcode; - trap_opcode_size = sizeof(g_ppc_opcode); - } - break; - - case llvm::Triple::x86: - case llvm::Triple::x86_64: - { - static const uint8_t g_i386_opcode[] = {0xCC}; - trap_opcode = g_i386_opcode; - trap_opcode_size = sizeof(g_i386_opcode); - } - break; + lldb::BreakpointLocationSP bp_loc_sp(bp_site->GetOwnerAtIndex(0)); + AddressClass addr_class = eAddressClassUnknown; - default: - assert(!"Unhandled architecture in Platform::GetSoftwareBreakpointTrapOpcode"); - break; + if (bp_loc_sp) { + addr_class = bp_loc_sp->GetAddress().GetAddressClass(); + if (addr_class == eAddressClassUnknown && + (bp_loc_sp->GetAddress().GetFileAddress() & 1)) + addr_class = eAddressClassCodeAlternateISA; } - assert(bp_site); - if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) - return trap_opcode_size; - - return 0; + if (addr_class == eAddressClassCodeAlternateISA) { + trap_opcode = g_thumb_breakpoint_opcode; + trap_opcode_size = sizeof(g_thumb_breakpoint_opcode); + } else { + trap_opcode = g_arm_breakpoint_opcode; + trap_opcode_size = sizeof(g_arm_breakpoint_opcode); + } + } break; + + case llvm::Triple::mips: + case llvm::Triple::mips64: { + static const uint8_t g_hex_opcode[] = {0x00, 0x00, 0x00, 0x0d}; + trap_opcode = g_hex_opcode; + trap_opcode_size = sizeof(g_hex_opcode); + } break; + + case llvm::Triple::mipsel: + case llvm::Triple::mips64el: { + static const uint8_t g_hex_opcode[] = {0x0d, 0x00, 0x00, 0x00}; + trap_opcode = g_hex_opcode; + trap_opcode_size = sizeof(g_hex_opcode); + } break; + + case llvm::Triple::systemz: { + static const uint8_t g_hex_opcode[] = {0x00, 0x01}; + trap_opcode = g_hex_opcode; + trap_opcode_size = sizeof(g_hex_opcode); + } break; + + case llvm::Triple::hexagon: { + static const uint8_t g_hex_opcode[] = {0x0c, 0xdb, 0x00, 0x54}; + trap_opcode = g_hex_opcode; + trap_opcode_size = sizeof(g_hex_opcode); + } break; + + case llvm::Triple::ppc: + case llvm::Triple::ppc64: { + static const uint8_t g_ppc_opcode[] = {0x7f, 0xe0, 0x00, 0x08}; + trap_opcode = g_ppc_opcode; + trap_opcode_size = sizeof(g_ppc_opcode); + } break; + + case llvm::Triple::x86: + case llvm::Triple::x86_64: { + static const uint8_t g_i386_opcode[] = {0xCC}; + trap_opcode = g_i386_opcode; + trap_opcode_size = sizeof(g_i386_opcode); + } break; + + default: + assert( + !"Unhandled architecture in Platform::GetSoftwareBreakpointTrapOpcode"); + break; + } + + assert(bp_site); + if (bp_site->SetTrapOpcode(trap_opcode, trap_opcode_size)) + return trap_opcode_size; + + return 0; } diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp index 302d5bad7fa..f370676e73a 100644 --- a/lldb/source/Target/Process.cpp +++ b/lldb/source/Target/Process.cpp @@ -68,7 +68,8 @@ using namespace lldb; using namespace lldb_private; -// Comment out line below to disable memory caching, overriding the process setting +// Comment out line below to disable memory caching, overriding the process +// setting // target.process.disable-memory-cache #define ENABLE_MEMORY_CACHING @@ -78,6693 +79,6194 @@ using namespace lldb_private; #define DISABLE_MEM_CACHE_DEFAULT true #endif -class ProcessOptionValueProperties : public OptionValueProperties -{ +class ProcessOptionValueProperties : public OptionValueProperties { public: - ProcessOptionValueProperties (const ConstString &name) : - OptionValueProperties (name) - { - } - - // This constructor is used when creating ProcessOptionValueProperties when it - // is part of a new lldb_private::Process instance. It will copy all current - // global property values as needed - ProcessOptionValueProperties (ProcessProperties *global_properties) : - OptionValueProperties(*global_properties->GetValueProperties()) - { - } - - const Property * - GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override - { - // When getting the value for a key from the process options, we will always - // try and grab the setting from the current process if there is one. Else we just - // use the one from this instance. - if (exe_ctx) - { - Process *process = exe_ctx->GetProcessPtr(); - if (process) - { - ProcessOptionValueProperties *instance_properties = static_cast<ProcessOptionValueProperties *>(process->GetValueProperties().get()); - if (this != instance_properties) - return instance_properties->ProtectedGetPropertyAtIndex (idx); - } - } - return ProtectedGetPropertyAtIndex (idx); - } + ProcessOptionValueProperties(const ConstString &name) + : OptionValueProperties(name) {} + + // This constructor is used when creating ProcessOptionValueProperties when it + // is part of a new lldb_private::Process instance. It will copy all current + // global property values as needed + ProcessOptionValueProperties(ProcessProperties *global_properties) + : OptionValueProperties(*global_properties->GetValueProperties()) {} + + const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, + bool will_modify, + uint32_t idx) const override { + // When getting the value for a key from the process options, we will always + // try and grab the setting from the current process if there is one. Else + // we just + // use the one from this instance. + if (exe_ctx) { + Process *process = exe_ctx->GetProcessPtr(); + if (process) { + ProcessOptionValueProperties *instance_properties = + static_cast<ProcessOptionValueProperties *>( + process->GetValueProperties().get()); + if (this != instance_properties) + return instance_properties->ProtectedGetPropertyAtIndex(idx); + } + } + return ProtectedGetPropertyAtIndex(idx); + } }; -static PropertyDefinition -g_properties[] = -{ - { "disable-memory-cache" , OptionValue::eTypeBoolean, false, DISABLE_MEM_CACHE_DEFAULT, nullptr, nullptr, "Disable reading and caching of memory in fixed-size units." }, - { "extra-startup-command", OptionValue::eTypeArray , false, OptionValue::eTypeString, nullptr, nullptr, "A list containing extra commands understood by the particular process plugin used. " - "For instance, to turn on debugserver logging set this to \"QSetLogging:bitmask=LOG_DEFAULT;\"" }, - { "ignore-breakpoints-in-expressions", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, breakpoints will be ignored during expression evaluation." }, - { "unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, errors in expression evaluation will unwind the stack back to the state before the call." }, - { "python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, nullptr, nullptr, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." }, - { "stop-on-sharedlibrary-events" , OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, stop when a shared library is loaded or unloaded." }, - { "detach-keeps-stopped" , OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, detach will attempt to keep the process stopped." }, - { "memory-cache-line-size" , OptionValue::eTypeUInt64, false, 512, nullptr, nullptr, "The memory cache line size" }, - { "optimization-warnings" , OptionValue::eTypeBoolean, false, true, nullptr, nullptr, "If true, warn when stopped in code that is optimized where stepping and variable availability may not behave as expected." }, - { nullptr , OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr } -}; +static PropertyDefinition g_properties[] = { + {"disable-memory-cache", OptionValue::eTypeBoolean, false, + DISABLE_MEM_CACHE_DEFAULT, nullptr, nullptr, + "Disable reading and caching of memory in fixed-size units."}, + {"extra-startup-command", OptionValue::eTypeArray, false, + OptionValue::eTypeString, nullptr, nullptr, + "A list containing extra commands understood by the particular process " + "plugin used. " + "For instance, to turn on debugserver logging set this to " + "\"QSetLogging:bitmask=LOG_DEFAULT;\""}, + {"ignore-breakpoints-in-expressions", OptionValue::eTypeBoolean, true, true, + nullptr, nullptr, + "If true, breakpoints will be ignored during expression evaluation."}, + {"unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, true, + nullptr, nullptr, "If true, errors in expression evaluation will unwind " + "the stack back to the state before the call."}, + {"python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, nullptr, + nullptr, "A path to a python OS plug-in module file that contains a " + "OperatingSystemPlugIn class."}, + {"stop-on-sharedlibrary-events", OptionValue::eTypeBoolean, true, false, + nullptr, nullptr, + "If true, stop when a shared library is loaded or unloaded."}, + {"detach-keeps-stopped", OptionValue::eTypeBoolean, true, false, nullptr, + nullptr, "If true, detach will attempt to keep the process stopped."}, + {"memory-cache-line-size", OptionValue::eTypeUInt64, false, 512, nullptr, + nullptr, "The memory cache line size"}, + {"optimization-warnings", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "If true, warn when stopped in code that is optimized where " + "stepping and variable availability may not behave as expected."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; enum { - ePropertyDisableMemCache, - ePropertyExtraStartCommand, - ePropertyIgnoreBreakpointsInExpressions, - ePropertyUnwindOnErrorInExpressions, - ePropertyPythonOSPluginPath, - ePropertyStopOnSharedLibraryEvents, - ePropertyDetachKeepsStopped, - ePropertyMemCacheLineSize, - ePropertyWarningOptimization + ePropertyDisableMemCache, + ePropertyExtraStartCommand, + ePropertyIgnoreBreakpointsInExpressions, + ePropertyUnwindOnErrorInExpressions, + ePropertyPythonOSPluginPath, + ePropertyStopOnSharedLibraryEvents, + ePropertyDetachKeepsStopped, + ePropertyMemCacheLineSize, + ePropertyWarningOptimization }; -ProcessProperties::ProcessProperties (lldb_private::Process *process) : - Properties(), - m_process(process) // Can be nullptr for global ProcessProperties -{ - if (process == nullptr) - { - // Global process properties, set them up one time - m_collection_sp.reset (new ProcessOptionValueProperties(ConstString("process"))); - m_collection_sp->Initialize(g_properties); - m_collection_sp->AppendProperty(ConstString("thread"), - ConstString("Settings specific to threads."), - true, - Thread::GetGlobalProperties()->GetValueProperties()); - } - else - { - m_collection_sp.reset (new ProcessOptionValueProperties(Process::GetGlobalProperties().get())); - m_collection_sp->SetValueChangedCallback(ePropertyPythonOSPluginPath, ProcessProperties::OptionValueChangedCallback, this); - } +ProcessProperties::ProcessProperties(lldb_private::Process *process) + : Properties(), + m_process(process) // Can be nullptr for global ProcessProperties +{ + if (process == nullptr) { + // Global process properties, set them up one time + m_collection_sp.reset( + new ProcessOptionValueProperties(ConstString("process"))); + m_collection_sp->Initialize(g_properties); + m_collection_sp->AppendProperty( + ConstString("thread"), ConstString("Settings specific to threads."), + true, Thread::GetGlobalProperties()->GetValueProperties()); + } else { + m_collection_sp.reset( + new ProcessOptionValueProperties(Process::GetGlobalProperties().get())); + m_collection_sp->SetValueChangedCallback( + ePropertyPythonOSPluginPath, + ProcessProperties::OptionValueChangedCallback, this); + } } ProcessProperties::~ProcessProperties() = default; -void -ProcessProperties::OptionValueChangedCallback (void *baton, OptionValue *option_value) -{ - ProcessProperties *properties = (ProcessProperties *)baton; - if (properties->m_process) - properties->m_process->LoadOperatingSystemPlugin(true); +void ProcessProperties::OptionValueChangedCallback(void *baton, + OptionValue *option_value) { + ProcessProperties *properties = (ProcessProperties *)baton; + if (properties->m_process) + properties->m_process->LoadOperatingSystemPlugin(true); } -bool -ProcessProperties::GetDisableMemoryCache() const -{ - const uint32_t idx = ePropertyDisableMemCache; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool ProcessProperties::GetDisableMemoryCache() const { + const uint32_t idx = ePropertyDisableMemCache; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -uint64_t -ProcessProperties::GetMemoryCacheLineSize() const -{ - const uint32_t idx = ePropertyMemCacheLineSize; - return m_collection_sp->GetPropertyAtIndexAsUInt64(nullptr, idx, g_properties[idx].default_uint_value); +uint64_t ProcessProperties::GetMemoryCacheLineSize() const { + const uint32_t idx = ePropertyMemCacheLineSize; + return m_collection_sp->GetPropertyAtIndexAsUInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -Args -ProcessProperties::GetExtraStartupCommands () const -{ - Args args; - const uint32_t idx = ePropertyExtraStartCommand; - m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); - return args; +Args ProcessProperties::GetExtraStartupCommands() const { + Args args; + const uint32_t idx = ePropertyExtraStartCommand; + m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); + return args; } -void -ProcessProperties::SetExtraStartupCommands (const Args &args) -{ - const uint32_t idx = ePropertyExtraStartCommand; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); +void ProcessProperties::SetExtraStartupCommands(const Args &args) { + const uint32_t idx = ePropertyExtraStartCommand; + m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); } -FileSpec -ProcessProperties::GetPythonOSPluginPath () const -{ - const uint32_t idx = ePropertyPythonOSPluginPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +FileSpec ProcessProperties::GetPythonOSPluginPath() const { + const uint32_t idx = ePropertyPythonOSPluginPath; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); } -void -ProcessProperties::SetPythonOSPluginPath (const FileSpec &file) -{ - const uint32_t idx = ePropertyPythonOSPluginPath; - m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file); +void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) { + const uint32_t idx = ePropertyPythonOSPluginPath; + m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file); } -bool -ProcessProperties::GetIgnoreBreakpointsInExpressions () const -{ - const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); -} - -void -ProcessProperties::SetIgnoreBreakpointsInExpressions (bool ignore) -{ - const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore); +bool ProcessProperties::GetIgnoreBreakpointsInExpressions() const { + const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -ProcessProperties::GetUnwindOnErrorInExpressions () const -{ - const uint32_t idx = ePropertyUnwindOnErrorInExpressions; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); -} - -void -ProcessProperties::SetUnwindOnErrorInExpressions (bool ignore) -{ - const uint32_t idx = ePropertyUnwindOnErrorInExpressions; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore); +void ProcessProperties::SetIgnoreBreakpointsInExpressions(bool ignore) { + const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore); } -bool -ProcessProperties::GetStopOnSharedLibraryEvents () const -{ - const uint32_t idx = ePropertyStopOnSharedLibraryEvents; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); -} - -void -ProcessProperties::SetStopOnSharedLibraryEvents (bool stop) -{ - const uint32_t idx = ePropertyStopOnSharedLibraryEvents; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); +bool ProcessProperties::GetUnwindOnErrorInExpressions() const { + const uint32_t idx = ePropertyUnwindOnErrorInExpressions; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -ProcessProperties::GetDetachKeepsStopped () const -{ - const uint32_t idx = ePropertyDetachKeepsStopped; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); -} - -void -ProcessProperties::SetDetachKeepsStopped (bool stop) -{ - const uint32_t idx = ePropertyDetachKeepsStopped; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); +void ProcessProperties::SetUnwindOnErrorInExpressions(bool ignore) { + const uint32_t idx = ePropertyUnwindOnErrorInExpressions; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore); } -bool -ProcessProperties::GetWarningsOptimization () const -{ - const uint32_t idx = ePropertyWarningOptimization; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool ProcessProperties::GetStopOnSharedLibraryEvents() const { + const uint32_t idx = ePropertyStopOnSharedLibraryEvents; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const -{ - const char *cstr; - if (m_pid != LLDB_INVALID_PROCESS_ID) - s.Printf (" pid = %" PRIu64 "\n", m_pid); - - if (m_parent_pid != LLDB_INVALID_PROCESS_ID) - s.Printf (" parent = %" PRIu64 "\n", m_parent_pid); - - if (m_executable) - { - s.Printf (" name = %s\n", m_executable.GetFilename().GetCString()); - s.PutCString (" file = "); - m_executable.Dump(&s); - s.EOL(); - } - const uint32_t argc = m_arguments.GetArgumentCount(); - if (argc > 0) - { - for (uint32_t i = 0; i < argc; i++) - { - const char *arg = m_arguments.GetArgumentAtIndex(i); - if (i < 10) - s.Printf (" arg[%u] = %s\n", i, arg); - else - s.Printf ("arg[%u] = %s\n", i, arg); - } - } - - const uint32_t envc = m_environment.GetArgumentCount(); - if (envc > 0) - { - for (uint32_t i = 0; i < envc; i++) - { - const char *env = m_environment.GetArgumentAtIndex(i); - if (i < 10) - s.Printf (" env[%u] = %s\n", i, env); - else - s.Printf ("env[%u] = %s\n", i, env); - } - } - - if (m_arch.IsValid()) - { - s.Printf (" arch = "); - m_arch.DumpTriple(s); - s.EOL(); - } - - if (m_uid != UINT32_MAX) - { - cstr = platform->GetUserName (m_uid); - s.Printf (" uid = %-5u (%s)\n", m_uid, cstr ? cstr : ""); - } - if (m_gid != UINT32_MAX) - { - cstr = platform->GetGroupName (m_gid); - s.Printf (" gid = %-5u (%s)\n", m_gid, cstr ? cstr : ""); - } - if (m_euid != UINT32_MAX) - { - cstr = platform->GetUserName (m_euid); - s.Printf (" euid = %-5u (%s)\n", m_euid, cstr ? cstr : ""); - } - if (m_egid != UINT32_MAX) - { - cstr = platform->GetGroupName (m_egid); - s.Printf (" egid = %-5u (%s)\n", m_egid, cstr ? cstr : ""); - } +void ProcessProperties::SetStopOnSharedLibraryEvents(bool stop) { + const uint32_t idx = ePropertyStopOnSharedLibraryEvents; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); } -void -ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose) -{ - const char *label; - if (show_args || verbose) - label = "ARGUMENTS"; - else - label = "NAME"; - - if (verbose) - { - s.Printf ("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE %s\n", label); - s.PutCString ("====== ====== ========== ========== ========== ========== ======================== ============================\n"); - } - else - { - s.Printf ("PID PARENT USER TRIPLE %s\n", label); - s.PutCString ("====== ====== ========== ======================== ============================\n"); - } +bool ProcessProperties::GetDetachKeepsStopped() const { + const uint32_t idx = ePropertyDetachKeepsStopped; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const -{ - if (m_pid != LLDB_INVALID_PROCESS_ID) - { - const char *cstr; - s.Printf ("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid); - - StreamString arch_strm; - if (m_arch.IsValid()) - m_arch.DumpTriple(arch_strm); - - if (verbose) - { - cstr = platform->GetUserName (m_uid); - if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf ("%-10s ", cstr); - else - s.Printf ("%-10u ", m_uid); - - cstr = platform->GetGroupName (m_gid); - if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf ("%-10s ", cstr); - else - s.Printf ("%-10u ", m_gid); - - cstr = platform->GetUserName (m_euid); - if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf ("%-10s ", cstr); - else - s.Printf ("%-10u ", m_euid); - - cstr = platform->GetGroupName (m_egid); - if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed - s.Printf ("%-10s ", cstr); - else - s.Printf ("%-10u ", m_egid); - - s.Printf ("%-24s ", arch_strm.GetString().c_str()); - } - else - { - s.Printf ("%-10s %-24s ", - platform->GetUserName (m_euid), - arch_strm.GetString().c_str()); - } - - if (verbose || show_args) - { - const uint32_t argc = m_arguments.GetArgumentCount(); - if (argc > 0) - { - for (uint32_t i = 0; i < argc; i++) - { - if (i > 0) - s.PutChar (' '); - s.PutCString (m_arguments.GetArgumentAtIndex(i)); - } - } - } - else - { - s.PutCString (GetName()); - } - - s.EOL(); - } +void ProcessProperties::SetDetachKeepsStopped(bool stop) { + const uint32_t idx = ePropertyDetachKeepsStopped; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop); } -Error -ProcessLaunchCommandOptions::SetOptionValue(uint32_t option_idx, - const char *option_arg, - ExecutionContext *execution_context) -{ - Error error; - const int short_option = m_getopt_table[option_idx].val; - - switch (short_option) - { - case 's': // Stop at program entry point - launch_info.GetFlags().Set (eLaunchFlagStopAtEntry); - break; - - case 'i': // STDIN for read only - { - FileAction action; - if (action.Open(STDIN_FILENO, FileSpec{option_arg, false}, true, false)) - launch_info.AppendFileAction (action); - break; - } - - case 'o': // Open STDOUT for write only - { - FileAction action; - if (action.Open(STDOUT_FILENO, FileSpec{option_arg, false}, false, true)) - launch_info.AppendFileAction (action); - break; - } - - case 'e': // STDERR for write only - { - FileAction action; - if (action.Open(STDERR_FILENO, FileSpec{option_arg, false}, false, true)) - launch_info.AppendFileAction (action); - break; - } - - case 'p': // Process plug-in name - launch_info.SetProcessPluginName (option_arg); - break; - - case 'n': // Disable STDIO - { - FileAction action; - const FileSpec dev_null{FileSystem::DEV_NULL, false}; - if (action.Open(STDIN_FILENO, dev_null, true, false)) - launch_info.AppendFileAction (action); - if (action.Open(STDOUT_FILENO, dev_null, false, true)) - launch_info.AppendFileAction (action); - if (action.Open(STDERR_FILENO, dev_null, false, true)) - launch_info.AppendFileAction (action); - break; - } - - case 'w': - launch_info.SetWorkingDirectory(FileSpec{option_arg, false}); - break; - - case 't': // Open process in new terminal window - launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY); - break; - - case 'a': - { - TargetSP target_sp = execution_context ? - execution_context->GetTargetSP() : TargetSP(); - PlatformSP platform_sp = target_sp ? - target_sp->GetPlatform() : PlatformSP(); - if (!launch_info.GetArchitecture().SetTriple (option_arg, platform_sp.get())) - launch_info.GetArchitecture().SetTriple (option_arg); - } - break; - - case 'A': // Disable ASLR. - { - bool success; - const bool disable_aslr_arg = Args::StringToBoolean (option_arg, true, &success); - if (success) - disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo; - else - error.SetErrorStringWithFormat ("Invalid boolean value for disable-aslr option: '%s'", option_arg ? option_arg : "<null>"); - break; - } - - case 'X': // shell expand args. - { - bool success; - const bool expand_args = Args::StringToBoolean (option_arg, true, &success); - if (success) - launch_info.SetShellExpandArguments(expand_args); - else - error.SetErrorStringWithFormat ("Invalid boolean value for shell-expand-args option: '%s'", option_arg ? option_arg : "<null>"); - break; - } - - case 'c': - if (option_arg && option_arg[0]) - launch_info.SetShell (FileSpec(option_arg, false)); - else - launch_info.SetShell (HostInfo::GetDefaultShell()); - break; - - case 'v': - launch_info.GetEnvironmentEntries().AppendArgument(option_arg); - break; - - default: - error.SetErrorStringWithFormat("unrecognized short option character '%c'", short_option); - break; - } - return error; +bool ProcessProperties::GetWarningsOptimization() const { + const uint32_t idx = ePropertyWarningOptimization; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -OptionDefinition -ProcessLaunchCommandOptions::g_option_table[] = -{ -{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process." }, -{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set whether to disable address space layout randomization when launching a process." }, -{ LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePlugin, "Name of the process plugin you want to use." }, -{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior." }, -{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous." }, -{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries." }, -{ LLDB_OPT_SET_1|LLDB_OPT_SET_2|LLDB_OPT_SET_3, false, "shell", 'c', OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)." }, - -{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>." }, -{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>." }, -{ LLDB_OPT_SET_1 , false, "stderr", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>." }, - -{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)." }, - -{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process." }, -{ LLDB_OPT_SET_4, false, "shell-expand-args", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set whether to shell expand arguments to the process when launching." }, -{ 0 , false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr } -}; - -bool -ProcessInstanceInfoMatch::NameMatches (const char *process_name) const -{ - if (m_name_match_type == eNameMatchIgnore || process_name == nullptr) - return true; - const char *match_name = m_match_info.GetName(); - if (!match_name) - return true; - - return lldb_private::NameMatches (process_name, m_name_match_type, match_name); -} - -bool -ProcessInstanceInfoMatch::Matches (const ProcessInstanceInfo &proc_info) const -{ - if (!NameMatches (proc_info.GetName())) - return false; - - if (m_match_info.ProcessIDIsValid() && - m_match_info.GetProcessID() != proc_info.GetProcessID()) - return false; - - if (m_match_info.ParentProcessIDIsValid() && - m_match_info.GetParentProcessID() != proc_info.GetParentProcessID()) - return false; - - if (m_match_info.UserIDIsValid () && - m_match_info.GetUserID() != proc_info.GetUserID()) - return false; - - if (m_match_info.GroupIDIsValid () && - m_match_info.GetGroupID() != proc_info.GetGroupID()) - return false; - - if (m_match_info.EffectiveUserIDIsValid () && - m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID()) - return false; - - if (m_match_info.EffectiveGroupIDIsValid () && - m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID()) - return false; - - if (m_match_info.GetArchitecture().IsValid() && - !m_match_info.GetArchitecture().IsCompatibleMatch(proc_info.GetArchitecture())) - return false; - return true; -} +void ProcessInstanceInfo::Dump(Stream &s, Platform *platform) const { + const char *cstr; + if (m_pid != LLDB_INVALID_PROCESS_ID) + s.Printf(" pid = %" PRIu64 "\n", m_pid); -bool -ProcessInstanceInfoMatch::MatchAllProcesses () const -{ - if (m_name_match_type != eNameMatchIgnore) - return false; - - if (m_match_info.ProcessIDIsValid()) - return false; - - if (m_match_info.ParentProcessIDIsValid()) - return false; - - if (m_match_info.UserIDIsValid ()) - return false; - - if (m_match_info.GroupIDIsValid ()) - return false; - - if (m_match_info.EffectiveUserIDIsValid ()) - return false; - - if (m_match_info.EffectiveGroupIDIsValid ()) - return false; - - if (m_match_info.GetArchitecture().IsValid()) - return false; - - if (m_match_all_users) - return false; + if (m_parent_pid != LLDB_INVALID_PROCESS_ID) + s.Printf(" parent = %" PRIu64 "\n", m_parent_pid); - return true; -} + if (m_executable) { + s.Printf(" name = %s\n", m_executable.GetFilename().GetCString()); + s.PutCString(" file = "); + m_executable.Dump(&s); + s.EOL(); + } + const uint32_t argc = m_arguments.GetArgumentCount(); + if (argc > 0) { + for (uint32_t i = 0; i < argc; i++) { + const char *arg = m_arguments.GetArgumentAtIndex(i); + if (i < 10) + s.Printf(" arg[%u] = %s\n", i, arg); + else + s.Printf("arg[%u] = %s\n", i, arg); + } + } -void -ProcessInstanceInfoMatch::Clear() -{ - m_match_info.Clear(); - m_name_match_type = eNameMatchIgnore; - m_match_all_users = false; -} + const uint32_t envc = m_environment.GetArgumentCount(); + if (envc > 0) { + for (uint32_t i = 0; i < envc; i++) { + const char *env = m_environment.GetArgumentAtIndex(i); + if (i < 10) + s.Printf(" env[%u] = %s\n", i, env); + else + s.Printf("env[%u] = %s\n", i, env); + } + } + + if (m_arch.IsValid()) { + s.Printf(" arch = "); + m_arch.DumpTriple(s); + s.EOL(); + } + + if (m_uid != UINT32_MAX) { + cstr = platform->GetUserName(m_uid); + s.Printf(" uid = %-5u (%s)\n", m_uid, cstr ? cstr : ""); + } + if (m_gid != UINT32_MAX) { + cstr = platform->GetGroupName(m_gid); + s.Printf(" gid = %-5u (%s)\n", m_gid, cstr ? cstr : ""); + } + if (m_euid != UINT32_MAX) { + cstr = platform->GetUserName(m_euid); + s.Printf(" euid = %-5u (%s)\n", m_euid, cstr ? cstr : ""); + } + if (m_egid != UINT32_MAX) { + cstr = platform->GetGroupName(m_egid); + s.Printf(" egid = %-5u (%s)\n", m_egid, cstr ? cstr : ""); + } +} + +void ProcessInstanceInfo::DumpTableHeader(Stream &s, Platform *platform, + bool show_args, bool verbose) { + const char *label; + if (show_args || verbose) + label = "ARGUMENTS"; + else + label = "NAME"; + + if (verbose) { + s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE " + " %s\n", + label); + s.PutCString("====== ====== ========== ========== ========== ========== " + "======================== ============================\n"); + } else { + s.Printf("PID PARENT USER TRIPLE %s\n", label); + s.PutCString("====== ====== ========== ======================== " + "============================\n"); + } +} + +void ProcessInstanceInfo::DumpAsTableRow(Stream &s, Platform *platform, + bool show_args, bool verbose) const { + if (m_pid != LLDB_INVALID_PROCESS_ID) { + const char *cstr; + s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid); -ProcessSP -Process::FindPlugin (lldb::TargetSP target_sp, const char *plugin_name, ListenerSP listener_sp, const FileSpec *crash_file_path) -{ - static uint32_t g_process_unique_id = 0; - - ProcessSP process_sp; - ProcessCreateInstance create_callback = nullptr; - if (plugin_name) - { - ConstString const_plugin_name(plugin_name); - create_callback = PluginManager::GetProcessCreateCallbackForPluginName (const_plugin_name); - if (create_callback) - { - process_sp = create_callback(target_sp, listener_sp, crash_file_path); - if (process_sp) - { - if (process_sp->CanDebug(target_sp, true)) - { - process_sp->m_process_unique_id = ++g_process_unique_id; - } - else - process_sp.reset(); - } + StreamString arch_strm; + if (m_arch.IsValid()) + m_arch.DumpTriple(arch_strm); + + if (verbose) { + cstr = platform->GetUserName(m_uid); + if (cstr && + cstr[0]) // Watch for empty string that indicates lookup failed + s.Printf("%-10s ", cstr); + else + s.Printf("%-10u ", m_uid); + + cstr = platform->GetGroupName(m_gid); + if (cstr && + cstr[0]) // Watch for empty string that indicates lookup failed + s.Printf("%-10s ", cstr); + else + s.Printf("%-10u ", m_gid); + + cstr = platform->GetUserName(m_euid); + if (cstr && + cstr[0]) // Watch for empty string that indicates lookup failed + s.Printf("%-10s ", cstr); + else + s.Printf("%-10u ", m_euid); + + cstr = platform->GetGroupName(m_egid); + if (cstr && + cstr[0]) // Watch for empty string that indicates lookup failed + s.Printf("%-10s ", cstr); + else + s.Printf("%-10u ", m_egid); + + s.Printf("%-24s ", arch_strm.GetString().c_str()); + } else { + s.Printf("%-10s %-24s ", platform->GetUserName(m_euid), + arch_strm.GetString().c_str()); + } + + if (verbose || show_args) { + const uint32_t argc = m_arguments.GetArgumentCount(); + if (argc > 0) { + for (uint32_t i = 0; i < argc; i++) { + if (i > 0) + s.PutChar(' '); + s.PutCString(m_arguments.GetArgumentAtIndex(i)); } - } + } + } else { + s.PutCString(GetName()); + } + + s.EOL(); + } +} + +Error ProcessLaunchCommandOptions::SetOptionValue( + uint32_t option_idx, const char *option_arg, + ExecutionContext *execution_context) { + Error error; + const int short_option = m_getopt_table[option_idx].val; + + switch (short_option) { + case 's': // Stop at program entry point + launch_info.GetFlags().Set(eLaunchFlagStopAtEntry); + break; + + case 'i': // STDIN for read only + { + FileAction action; + if (action.Open(STDIN_FILENO, FileSpec{option_arg, false}, true, false)) + launch_info.AppendFileAction(action); + break; + } + + case 'o': // Open STDOUT for write only + { + FileAction action; + if (action.Open(STDOUT_FILENO, FileSpec{option_arg, false}, false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'e': // STDERR for write only + { + FileAction action; + if (action.Open(STDERR_FILENO, FileSpec{option_arg, false}, false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'p': // Process plug-in name + launch_info.SetProcessPluginName(option_arg); + break; + + case 'n': // Disable STDIO + { + FileAction action; + const FileSpec dev_null{FileSystem::DEV_NULL, false}; + if (action.Open(STDIN_FILENO, dev_null, true, false)) + launch_info.AppendFileAction(action); + if (action.Open(STDOUT_FILENO, dev_null, false, true)) + launch_info.AppendFileAction(action); + if (action.Open(STDERR_FILENO, dev_null, false, true)) + launch_info.AppendFileAction(action); + break; + } + + case 'w': + launch_info.SetWorkingDirectory(FileSpec{option_arg, false}); + break; + + case 't': // Open process in new terminal window + launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY); + break; + + case 'a': { + TargetSP target_sp = + execution_context ? execution_context->GetTargetSP() : TargetSP(); + PlatformSP platform_sp = + target_sp ? target_sp->GetPlatform() : PlatformSP(); + if (!launch_info.GetArchitecture().SetTriple(option_arg, platform_sp.get())) + launch_info.GetArchitecture().SetTriple(option_arg); + } break; + + case 'A': // Disable ASLR. + { + bool success; + const bool disable_aslr_arg = + Args::StringToBoolean(option_arg, true, &success); + if (success) + disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo; else - { - for (uint32_t idx = 0; (create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx)) != nullptr; ++idx) - { - process_sp = create_callback(target_sp, listener_sp, crash_file_path); - if (process_sp) - { - if (process_sp->CanDebug(target_sp, false)) - { - process_sp->m_process_unique_id = ++g_process_unique_id; - break; - } - else - process_sp.reset(); - } - } - } - return process_sp; -} - -ConstString & -Process::GetStaticBroadcasterClass () -{ - static ConstString class_name ("lldb.process"); - return class_name; -} + error.SetErrorStringWithFormat( + "Invalid boolean value for disable-aslr option: '%s'", + option_arg ? option_arg : "<null>"); + break; + } + + case 'X': // shell expand args. + { + bool success; + const bool expand_args = Args::StringToBoolean(option_arg, true, &success); + if (success) + launch_info.SetShellExpandArguments(expand_args); + else + error.SetErrorStringWithFormat( + "Invalid boolean value for shell-expand-args option: '%s'", + option_arg ? option_arg : "<null>"); + break; + } + + case 'c': + if (option_arg && option_arg[0]) + launch_info.SetShell(FileSpec(option_arg, false)); + else + launch_info.SetShell(HostInfo::GetDefaultShell()); + break; + + case 'v': + launch_info.GetEnvironmentEntries().AppendArgument(option_arg); + break; + + default: + error.SetErrorStringWithFormat("unrecognized short option character '%c'", + short_option); + break; + } + return error; +} + +OptionDefinition ProcessLaunchCommandOptions::g_option_table[] = { + {LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, + nullptr, nullptr, 0, eArgTypeNone, + "Stop at the entry point of the program when launching a process."}, + {LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, + "Set whether to disable address space layout randomization when launching " + "a process."}, + {LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypePlugin, + "Name of the process plugin you want to use."}, + {LLDB_OPT_SET_ALL, false, "working-dir", 'w', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, + eArgTypeDirectoryName, + "Set the current working directory to <path> when running the inferior."}, + {LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeArchitecture, + "Set the architecture for the process to launch when ambiguous."}, + {LLDB_OPT_SET_ALL, false, "environment", 'v', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, + "Specify an environment variable name/value string (--environment " + "NAME=VALUE). Can be specified multiple times for subsequent environment " + "entries."}, + {LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "shell", 'c', + OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeFilename, + "Run the process in a shell (not supported on all platforms)."}, + + {LLDB_OPT_SET_1, false, "stdin", 'i', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeFilename, + "Redirect stdin for the process to <filename>."}, + {LLDB_OPT_SET_1, false, "stdout", 'o', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeFilename, + "Redirect stdout for the process to <filename>."}, + {LLDB_OPT_SET_1, false, "stderr", 'e', OptionParser::eRequiredArgument, + nullptr, nullptr, 0, eArgTypeFilename, + "Redirect stderr for the process to <filename>."}, + + {LLDB_OPT_SET_2, false, "tty", 't', OptionParser::eNoArgument, nullptr, + nullptr, 0, eArgTypeNone, + "Start the process in a terminal (not supported on all platforms)."}, + + {LLDB_OPT_SET_3, false, "no-stdio", 'n', OptionParser::eNoArgument, nullptr, + nullptr, 0, eArgTypeNone, + "Do not set up for terminal I/O to go to running process."}, + {LLDB_OPT_SET_4, false, "shell-expand-args", 'X', + OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, + "Set whether to shell expand arguments to the process when launching."}, + {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}}; + +bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const { + if (m_name_match_type == eNameMatchIgnore || process_name == nullptr) + return true; + const char *match_name = m_match_info.GetName(); + if (!match_name) + return true; -Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp) : - Process(target_sp, listener_sp, UnixSignals::Create(HostInfo::GetArchitecture())) -{ - // This constructor just delegates to the full Process constructor, - // defaulting to using the Host's UnixSignals. + return lldb_private::NameMatches(process_name, m_name_match_type, match_name); } -Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, const UnixSignalsSP &unix_signals_sp) - : ProcessProperties(this), - UserID(LLDB_INVALID_PROCESS_ID), - Broadcaster((target_sp->GetDebugger().GetBroadcasterManager()), Process::GetStaticBroadcasterClass().AsCString()), - m_target_sp(target_sp), - m_public_state(eStateUnloaded), - m_private_state(eStateUnloaded), - m_private_state_broadcaster(nullptr, "lldb.process.internal_state_broadcaster"), - m_private_state_control_broadcaster(nullptr, "lldb.process.internal_state_control_broadcaster"), - m_private_state_listener_sp(Listener::MakeListener("lldb.process.internal_state_listener")), - m_mod_id(), - m_process_unique_id(0), - m_thread_index_id(0), - m_thread_id_to_index_id_map(), - m_exit_status(-1), - m_exit_string(), - m_exit_status_mutex(), - m_thread_mutex(), - m_thread_list_real(this), - m_thread_list(this), - m_extended_thread_list(this), - m_extended_thread_stop_id(0), - m_queue_list(this), - m_queue_list_stop_id(0), - m_notifications(), - m_image_tokens(), - m_listener_sp(listener_sp), - m_breakpoint_site_list(), - m_dynamic_checkers_ap(), - m_unix_signals_sp(unix_signals_sp), - m_abi_sp(), - m_process_input_reader(), - m_stdio_communication("process.stdio"), - m_stdio_communication_mutex(), - m_stdin_forward(false), - m_stdout_data(), - m_stderr_data(), - m_profile_data_comm_mutex(), - m_profile_data(), - m_iohandler_sync(0), - m_memory_cache(*this), - m_allocated_memory_cache(*this), - m_should_detach(false), - m_next_event_action_ap(), - m_public_run_lock(), - m_private_run_lock(), - m_stop_info_override_callback(nullptr), - m_finalizing(false), - m_finalize_called(false), - m_clear_thread_plans_on_stop(false), - m_force_next_event_delivery(false), - m_last_broadcast_state(eStateInvalid), - m_destroy_in_process(false), - m_can_interpret_function_calls(false), - m_warnings_issued(), - m_run_thread_plan_lock(), - m_can_jit(eCanJITDontKnow) -{ - CheckInWithManager(); - - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p Process::Process()", static_cast<void *>(this)); +bool ProcessInstanceInfoMatch::Matches( + const ProcessInstanceInfo &proc_info) const { + if (!NameMatches(proc_info.GetName())) + return false; - if (!m_unix_signals_sp) - m_unix_signals_sp = std::make_shared<UnixSignals>(); + if (m_match_info.ProcessIDIsValid() && + m_match_info.GetProcessID() != proc_info.GetProcessID()) + return false; - SetEventName(eBroadcastBitStateChanged, "state-changed"); - SetEventName(eBroadcastBitInterrupt, "interrupt"); - SetEventName(eBroadcastBitSTDOUT, "stdout-available"); - SetEventName(eBroadcastBitSTDERR, "stderr-available"); - SetEventName(eBroadcastBitProfileData, "profile-data-available"); - SetEventName(eBroadcastBitStructuredData, "structured-data-available"); + if (m_match_info.ParentProcessIDIsValid() && + m_match_info.GetParentProcessID() != proc_info.GetParentProcessID()) + return false; - m_private_state_control_broadcaster.SetEventName(eBroadcastInternalStateControlStop, "control-stop"); - m_private_state_control_broadcaster.SetEventName(eBroadcastInternalStateControlPause, "control-pause"); - m_private_state_control_broadcaster.SetEventName(eBroadcastInternalStateControlResume, "control-resume"); + if (m_match_info.UserIDIsValid() && + m_match_info.GetUserID() != proc_info.GetUserID()) + return false; - m_listener_sp->StartListeningForEvents(this, eBroadcastBitStateChanged | eBroadcastBitInterrupt | - eBroadcastBitSTDOUT | eBroadcastBitSTDERR | - eBroadcastBitProfileData | - eBroadcastBitStructuredData); + if (m_match_info.GroupIDIsValid() && + m_match_info.GetGroupID() != proc_info.GetGroupID()) + return false; - m_private_state_listener_sp->StartListeningForEvents(&m_private_state_broadcaster, - eBroadcastBitStateChanged | eBroadcastBitInterrupt); + if (m_match_info.EffectiveUserIDIsValid() && + m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID()) + return false; - m_private_state_listener_sp->StartListeningForEvents( - &m_private_state_control_broadcaster, eBroadcastInternalStateControlStop | eBroadcastInternalStateControlPause | - eBroadcastInternalStateControlResume); - // We need something valid here, even if just the default UnixSignalsSP. - assert(m_unix_signals_sp && "null m_unix_signals_sp after initialization"); + if (m_match_info.EffectiveGroupIDIsValid() && + m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID()) + return false; - // Allow the platform to override the default cache line size - OptionValueSP value_sp = m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyMemCacheLineSize)->GetValue(); - uint32_t platform_cache_line_size = target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize(); - if (!value_sp->OptionWasSet() && platform_cache_line_size != 0) - value_sp->SetUInt64Value(platform_cache_line_size); + if (m_match_info.GetArchitecture().IsValid() && + !m_match_info.GetArchitecture().IsCompatibleMatch( + proc_info.GetArchitecture())) + return false; + return true; } -Process::~Process() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf ("%p Process::~Process()", static_cast<void*>(this)); - StopPrivateStateThread(); +bool ProcessInstanceInfoMatch::MatchAllProcesses() const { + if (m_name_match_type != eNameMatchIgnore) + return false; - // ThreadList::Clear() will try to acquire this process's mutex, so - // explicitly clear the thread list here to ensure that the mutex - // is not destroyed before the thread list. - m_thread_list.Clear(); -} + if (m_match_info.ProcessIDIsValid()) + return false; -const ProcessPropertiesSP & -Process::GetGlobalProperties() -{ - // NOTE: intentional leak so we don't crash if global destructor chain gets - // called as other threads still use the result of this function - static ProcessPropertiesSP *g_settings_sp_ptr = nullptr; - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_settings_sp_ptr = new ProcessPropertiesSP(new ProcessProperties(nullptr)); - }); - return *g_settings_sp_ptr; -} + if (m_match_info.ParentProcessIDIsValid()) + return false; -void -Process::Finalize() -{ - m_finalizing = true; - - // Destroy this process if needed - switch (GetPrivateState()) - { - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateStopped: - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - Destroy(false); - break; - - case eStateInvalid: - case eStateUnloaded: - case eStateDetached: - case eStateExited: - break; - } + if (m_match_info.UserIDIsValid()) + return false; - // Clear our broadcaster before we proceed with destroying - Broadcaster::Clear(); - - // Do any cleanup needed prior to being destructed... Subclasses - // that override this method should call this superclass method as well. - - // We need to destroy the loader before the derived Process class gets destroyed - // since it is very likely that undoing the loader will require access to the real process. - m_dynamic_checkers_ap.reset(); - m_abi_sp.reset(); - m_os_ap.reset(); - m_system_runtime_ap.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); - m_thread_list_real.Destroy(); - m_thread_list.Destroy(); - m_extended_thread_list.Destroy(); - m_queue_list.Clear(); - m_queue_list_stop_id = 0; - std::vector<Notifications> empty_notifications; - m_notifications.swap(empty_notifications); - m_image_tokens.clear(); - m_memory_cache.Clear(); - m_allocated_memory_cache.Clear(); - m_language_runtimes.clear(); - m_instrumentation_runtimes.clear(); - m_next_event_action_ap.reset(); - m_stop_info_override_callback = nullptr; - // Clear the last natural stop ID since it has a strong - // reference to this process - m_mod_id.SetStopEventForLastNaturalStopID(EventSP()); -//#ifdef LLDB_CONFIGURATION_DEBUG -// StreamFile s(stdout, false); -// EventSP event_sp; -// while (m_private_state_listener_sp->GetNextEvent(event_sp)) -// { -// event_sp->Dump (&s); -// s.EOL(); -// } -//#endif - // We have to be very careful here as the m_private_state_listener might - // contain events that have ProcessSP values in them which can keep this - // process around forever. These events need to be cleared out. - m_private_state_listener_sp->Clear(); - m_public_run_lock.TrySetRunning(); // This will do nothing if already locked - m_public_run_lock.SetStopped(); - m_private_run_lock.TrySetRunning(); // This will do nothing if already locked - m_private_run_lock.SetStopped(); - m_finalize_called = true; -} + if (m_match_info.GroupIDIsValid()) + return false; -void -Process::RegisterNotificationCallbacks (const Notifications& callbacks) -{ - m_notifications.push_back(callbacks); - if (callbacks.initialize != nullptr) - callbacks.initialize (callbacks.baton, this); -} + if (m_match_info.EffectiveUserIDIsValid()) + return false; -bool -Process::UnregisterNotificationCallbacks(const Notifications& callbacks) -{ - std::vector<Notifications>::iterator pos, end = m_notifications.end(); - for (pos = m_notifications.begin(); pos != end; ++pos) - { - if (pos->baton == callbacks.baton && - pos->initialize == callbacks.initialize && - pos->process_state_changed == callbacks.process_state_changed) - { - m_notifications.erase(pos); - return true; - } - } + if (m_match_info.EffectiveGroupIDIsValid()) return false; -} -void -Process::SynchronouslyNotifyStateChanged (StateType state) -{ - std::vector<Notifications>::iterator notification_pos, notification_end = m_notifications.end(); - for (notification_pos = m_notifications.begin(); notification_pos != notification_end; ++notification_pos) - { - if (notification_pos->process_state_changed) - notification_pos->process_state_changed (notification_pos->baton, this, state); - } -} + if (m_match_info.GetArchitecture().IsValid()) + return false; + + if (m_match_all_users) + return false; -// FIXME: We need to do some work on events before the general Listener sees them. -// For instance if we are continuing from a breakpoint, we need to ensure that we do -// the little "insert real insn, step & stop" trick. But we can't do that when the -// event is delivered by the broadcaster - since that is done on the thread that is -// waiting for new events, so if we needed more than one event for our handling, we would + return true; +} + +void ProcessInstanceInfoMatch::Clear() { + m_match_info.Clear(); + m_name_match_type = eNameMatchIgnore; + m_match_all_users = false; +} + +ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, const char *plugin_name, + ListenerSP listener_sp, + const FileSpec *crash_file_path) { + static uint32_t g_process_unique_id = 0; + + ProcessSP process_sp; + ProcessCreateInstance create_callback = nullptr; + if (plugin_name) { + ConstString const_plugin_name(plugin_name); + create_callback = + PluginManager::GetProcessCreateCallbackForPluginName(const_plugin_name); + if (create_callback) { + process_sp = create_callback(target_sp, listener_sp, crash_file_path); + if (process_sp) { + if (process_sp->CanDebug(target_sp, true)) { + process_sp->m_process_unique_id = ++g_process_unique_id; + } else + process_sp.reset(); + } + } + } else { + for (uint32_t idx = 0; + (create_callback = + PluginManager::GetProcessCreateCallbackAtIndex(idx)) != nullptr; + ++idx) { + process_sp = create_callback(target_sp, listener_sp, crash_file_path); + if (process_sp) { + if (process_sp->CanDebug(target_sp, false)) { + process_sp->m_process_unique_id = ++g_process_unique_id; + break; + } else + process_sp.reset(); + } + } + } + return process_sp; +} + +ConstString &Process::GetStaticBroadcasterClass() { + static ConstString class_name("lldb.process"); + return class_name; +} + +Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp) + : Process(target_sp, listener_sp, + UnixSignals::Create(HostInfo::GetArchitecture())) { + // This constructor just delegates to the full Process constructor, + // defaulting to using the Host's UnixSignals. +} + +Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, + const UnixSignalsSP &unix_signals_sp) + : ProcessProperties(this), UserID(LLDB_INVALID_PROCESS_ID), + Broadcaster((target_sp->GetDebugger().GetBroadcasterManager()), + Process::GetStaticBroadcasterClass().AsCString()), + m_target_sp(target_sp), m_public_state(eStateUnloaded), + m_private_state(eStateUnloaded), + m_private_state_broadcaster(nullptr, + "lldb.process.internal_state_broadcaster"), + m_private_state_control_broadcaster( + nullptr, "lldb.process.internal_state_control_broadcaster"), + m_private_state_listener_sp( + Listener::MakeListener("lldb.process.internal_state_listener")), + m_mod_id(), m_process_unique_id(0), m_thread_index_id(0), + m_thread_id_to_index_id_map(), m_exit_status(-1), m_exit_string(), + m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this), + m_thread_list(this), m_extended_thread_list(this), + m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0), + m_notifications(), m_image_tokens(), m_listener_sp(listener_sp), + m_breakpoint_site_list(), m_dynamic_checkers_ap(), + m_unix_signals_sp(unix_signals_sp), m_abi_sp(), m_process_input_reader(), + m_stdio_communication("process.stdio"), m_stdio_communication_mutex(), + m_stdin_forward(false), m_stdout_data(), m_stderr_data(), + m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0), + m_memory_cache(*this), m_allocated_memory_cache(*this), + m_should_detach(false), m_next_event_action_ap(), m_public_run_lock(), + m_private_run_lock(), m_stop_info_override_callback(nullptr), + m_finalizing(false), m_finalize_called(false), + m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false), + m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false), + m_can_interpret_function_calls(false), m_warnings_issued(), + m_run_thread_plan_lock(), m_can_jit(eCanJITDontKnow) { + CheckInWithManager(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Process::Process()", static_cast<void *>(this)); + + if (!m_unix_signals_sp) + m_unix_signals_sp = std::make_shared<UnixSignals>(); + + SetEventName(eBroadcastBitStateChanged, "state-changed"); + SetEventName(eBroadcastBitInterrupt, "interrupt"); + SetEventName(eBroadcastBitSTDOUT, "stdout-available"); + SetEventName(eBroadcastBitSTDERR, "stderr-available"); + SetEventName(eBroadcastBitProfileData, "profile-data-available"); + SetEventName(eBroadcastBitStructuredData, "structured-data-available"); + + m_private_state_control_broadcaster.SetEventName( + eBroadcastInternalStateControlStop, "control-stop"); + m_private_state_control_broadcaster.SetEventName( + eBroadcastInternalStateControlPause, "control-pause"); + m_private_state_control_broadcaster.SetEventName( + eBroadcastInternalStateControlResume, "control-resume"); + + m_listener_sp->StartListeningForEvents( + this, eBroadcastBitStateChanged | eBroadcastBitInterrupt | + eBroadcastBitSTDOUT | eBroadcastBitSTDERR | + eBroadcastBitProfileData | eBroadcastBitStructuredData); + + m_private_state_listener_sp->StartListeningForEvents( + &m_private_state_broadcaster, + eBroadcastBitStateChanged | eBroadcastBitInterrupt); + + m_private_state_listener_sp->StartListeningForEvents( + &m_private_state_control_broadcaster, + eBroadcastInternalStateControlStop | eBroadcastInternalStateControlPause | + eBroadcastInternalStateControlResume); + // We need something valid here, even if just the default UnixSignalsSP. + assert(m_unix_signals_sp && "null m_unix_signals_sp after initialization"); + + // Allow the platform to override the default cache line size + OptionValueSP value_sp = + m_collection_sp + ->GetPropertyAtIndex(nullptr, true, ePropertyMemCacheLineSize) + ->GetValue(); + uint32_t platform_cache_line_size = + target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize(); + if (!value_sp->OptionWasSet() && platform_cache_line_size != 0) + value_sp->SetUInt64Value(platform_cache_line_size); +} + +Process::~Process() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Process::~Process()", static_cast<void *>(this)); + StopPrivateStateThread(); + + // ThreadList::Clear() will try to acquire this process's mutex, so + // explicitly clear the thread list here to ensure that the mutex + // is not destroyed before the thread list. + m_thread_list.Clear(); +} + +const ProcessPropertiesSP &Process::GetGlobalProperties() { + // NOTE: intentional leak so we don't crash if global destructor chain gets + // called as other threads still use the result of this function + static ProcessPropertiesSP *g_settings_sp_ptr = nullptr; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_settings_sp_ptr = new ProcessPropertiesSP(new ProcessProperties(nullptr)); + }); + return *g_settings_sp_ptr; +} + +void Process::Finalize() { + m_finalizing = true; + + // Destroy this process if needed + switch (GetPrivateState()) { + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + Destroy(false); + break; + + case eStateInvalid: + case eStateUnloaded: + case eStateDetached: + case eStateExited: + break; + } + + // Clear our broadcaster before we proceed with destroying + Broadcaster::Clear(); + + // Do any cleanup needed prior to being destructed... Subclasses + // that override this method should call this superclass method as well. + + // We need to destroy the loader before the derived Process class gets + // destroyed + // since it is very likely that undoing the loader will require access to the + // real process. + m_dynamic_checkers_ap.reset(); + m_abi_sp.reset(); + m_os_ap.reset(); + m_system_runtime_ap.reset(); + m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); + m_thread_list_real.Destroy(); + m_thread_list.Destroy(); + m_extended_thread_list.Destroy(); + m_queue_list.Clear(); + m_queue_list_stop_id = 0; + std::vector<Notifications> empty_notifications; + m_notifications.swap(empty_notifications); + m_image_tokens.clear(); + m_memory_cache.Clear(); + m_allocated_memory_cache.Clear(); + m_language_runtimes.clear(); + m_instrumentation_runtimes.clear(); + m_next_event_action_ap.reset(); + m_stop_info_override_callback = nullptr; + // Clear the last natural stop ID since it has a strong + // reference to this process + m_mod_id.SetStopEventForLastNaturalStopID(EventSP()); + //#ifdef LLDB_CONFIGURATION_DEBUG + // StreamFile s(stdout, false); + // EventSP event_sp; + // while (m_private_state_listener_sp->GetNextEvent(event_sp)) + // { + // event_sp->Dump (&s); + // s.EOL(); + // } + //#endif + // We have to be very careful here as the m_private_state_listener might + // contain events that have ProcessSP values in them which can keep this + // process around forever. These events need to be cleared out. + m_private_state_listener_sp->Clear(); + m_public_run_lock.TrySetRunning(); // This will do nothing if already locked + m_public_run_lock.SetStopped(); + m_private_run_lock.TrySetRunning(); // This will do nothing if already locked + m_private_run_lock.SetStopped(); + m_finalize_called = true; +} + +void Process::RegisterNotificationCallbacks(const Notifications &callbacks) { + m_notifications.push_back(callbacks); + if (callbacks.initialize != nullptr) + callbacks.initialize(callbacks.baton, this); +} + +bool Process::UnregisterNotificationCallbacks(const Notifications &callbacks) { + std::vector<Notifications>::iterator pos, end = m_notifications.end(); + for (pos = m_notifications.begin(); pos != end; ++pos) { + if (pos->baton == callbacks.baton && + pos->initialize == callbacks.initialize && + pos->process_state_changed == callbacks.process_state_changed) { + m_notifications.erase(pos); + return true; + } + } + return false; +} + +void Process::SynchronouslyNotifyStateChanged(StateType state) { + std::vector<Notifications>::iterator notification_pos, + notification_end = m_notifications.end(); + for (notification_pos = m_notifications.begin(); + notification_pos != notification_end; ++notification_pos) { + if (notification_pos->process_state_changed) + notification_pos->process_state_changed(notification_pos->baton, this, + state); + } +} + +// FIXME: We need to do some work on events before the general Listener sees +// them. +// For instance if we are continuing from a breakpoint, we need to ensure that +// we do +// the little "insert real insn, step & stop" trick. But we can't do that when +// the +// event is delivered by the broadcaster - since that is done on the thread that +// is +// waiting for new events, so if we needed more than one event for our handling, +// we would // stall. So instead we do it when we fetch the event off of the queue. // -StateType -Process::GetNextEvent (EventSP &event_sp) -{ - StateType state = eStateInvalid; +StateType Process::GetNextEvent(EventSP &event_sp) { + StateType state = eStateInvalid; - if (m_listener_sp->GetNextEventForBroadcaster (this, event_sp) && event_sp) - state = Process::ProcessEventData::GetStateFromEvent (event_sp.get()); + if (m_listener_sp->GetNextEventForBroadcaster(this, event_sp) && event_sp) + state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - return state; + return state; } -void -Process::SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec) -{ - // don't sync (potentially context switch) in case where there is no process IO - if (!m_process_input_reader) - return; +void Process::SyncIOHandler(uint32_t iohandler_id, uint64_t timeout_msec) { + // don't sync (potentially context switch) in case where there is no process + // IO + if (!m_process_input_reader) + return; - uint32_t new_iohandler_id = 0; - m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, new_iohandler_id, std::chrono::milliseconds(timeout_msec)); + uint32_t new_iohandler_id = 0; + m_iohandler_sync.WaitForValueNotEqualTo( + iohandler_id, new_iohandler_id, std::chrono::milliseconds(timeout_msec)); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::%s waited for m_iohandler_sync to change from %u, new value is %u", __FUNCTION__, iohandler_id, new_iohandler_id); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::%s waited for m_iohandler_sync to change from %u, " + "new value is %u", + __FUNCTION__, iohandler_id, new_iohandler_id); } StateType -Process::WaitForProcessToStop(const std::chrono::microseconds &timeout, EventSP *event_sp_ptr, bool wait_always, - ListenerSP hijack_listener_sp, Stream *stream, bool use_run_lock) -{ - // We can't just wait for a "stopped" event, because the stopped event may have restarted the target. - // We have to actually check each event, and in the case of a stopped event check the restarted flag - // on the event. - if (event_sp_ptr) - event_sp_ptr->reset(); - StateType state = GetState(); - // If we are exited or detached, we won't ever get back to any - // other valid state... - if (state == eStateDetached || state == eStateExited) - return state; +Process::WaitForProcessToStop(const std::chrono::microseconds &timeout, + EventSP *event_sp_ptr, bool wait_always, + ListenerSP hijack_listener_sp, Stream *stream, + bool use_run_lock) { + // We can't just wait for a "stopped" event, because the stopped event may + // have restarted the target. + // We have to actually check each event, and in the case of a stopped event + // check the restarted flag + // on the event. + if (event_sp_ptr) + event_sp_ptr->reset(); + StateType state = GetState(); + // If we are exited or detached, we won't ever get back to any + // other valid state... + if (state == eStateDetached || state == eStateExited) + return state; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::%s (timeout = %llu)", __FUNCTION__, + static_cast<unsigned long long>(timeout.count())); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (!wait_always && StateIsStoppedState(state, true) && + StateIsStoppedState(GetPrivateState(), true)) { if (log) - log->Printf("Process::%s (timeout = %llu)", __FUNCTION__, static_cast<unsigned long long>(timeout.count())); + log->Printf("Process::%s returning without waiting for events; process " + "private and public states are already 'stopped'.", + __FUNCTION__); + // We need to toggle the run lock as this won't get done in + // SetPublicState() if the process is hijacked. + if (hijack_listener_sp && use_run_lock) + m_public_run_lock.SetStopped(); + return state; + } - if (!wait_always && - StateIsStoppedState(state, true) && - StateIsStoppedState(GetPrivateState(), true)) - { - if (log) - log->Printf("Process::%s returning without waiting for events; process private and public states are already 'stopped'.", - __FUNCTION__); + while (state != eStateInvalid) { + EventSP event_sp; + state = WaitForStateChangedEvents(timeout, event_sp, hijack_listener_sp); + if (event_sp_ptr && event_sp) + *event_sp_ptr = event_sp; + + bool pop_process_io_handler = (hijack_listener_sp.get() != nullptr); + Process::HandleProcessStateChangedEvent(event_sp, stream, + pop_process_io_handler); + + switch (state) { + case eStateCrashed: + case eStateDetached: + case eStateExited: + case eStateUnloaded: + // We need to toggle the run lock as this won't get done in + // SetPublicState() if the process is hijacked. + if (hijack_listener_sp && use_run_lock) + m_public_run_lock.SetStopped(); + return state; + case eStateStopped: + if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) + continue; + else { // We need to toggle the run lock as this won't get done in // SetPublicState() if the process is hijacked. if (hijack_listener_sp && use_run_lock) - m_public_run_lock.SetStopped(); + m_public_run_lock.SetStopped(); return state; + } + default: + continue; } - - while (state != eStateInvalid) - { - EventSP event_sp; - state = WaitForStateChangedEvents(timeout, event_sp, hijack_listener_sp); - if (event_sp_ptr && event_sp) - *event_sp_ptr = event_sp; - - bool pop_process_io_handler = (hijack_listener_sp.get() != nullptr); - Process::HandleProcessStateChangedEvent (event_sp, stream, pop_process_io_handler); - - switch (state) - { - case eStateCrashed: - case eStateDetached: - case eStateExited: - case eStateUnloaded: - // We need to toggle the run lock as this won't get done in - // SetPublicState() if the process is hijacked. - if (hijack_listener_sp && use_run_lock) - m_public_run_lock.SetStopped(); - return state; - case eStateStopped: - if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) - continue; - else - { - // We need to toggle the run lock as this won't get done in - // SetPublicState() if the process is hijacked. - if (hijack_listener_sp && use_run_lock) - m_public_run_lock.SetStopped(); - return state; - } - default: - continue; - } - } - return state; + } + return state; } -bool -Process::HandleProcessStateChangedEvent (const EventSP &event_sp, - Stream *stream, - bool &pop_process_io_handler) -{ - const bool handle_pop = pop_process_io_handler; - - pop_process_io_handler = false; - ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); - - if (!process_sp) - return false; - - StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get()); - if (event_state == eStateInvalid) - return false; - - switch (event_state) - { - case eStateInvalid: - case eStateUnloaded: - case eStateAttaching: - case eStateLaunching: - case eStateStepping: - case eStateDetached: - if (stream) - stream->Printf("Process %" PRIu64 " %s\n", - process_sp->GetID(), - StateAsCString (event_state)); - if (event_state == eStateDetached) - pop_process_io_handler = true; - break; +bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp, + Stream *stream, + bool &pop_process_io_handler) { + const bool handle_pop = pop_process_io_handler; - case eStateConnected: - case eStateRunning: - // Don't be chatty when we run... - break; + pop_process_io_handler = false; + ProcessSP process_sp = + Process::ProcessEventData::GetProcessFromEvent(event_sp.get()); - case eStateExited: - if (stream) - process_sp->GetStatus(*stream); - pop_process_io_handler = true; - break; + if (!process_sp) + return false; - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - // Make sure the program hasn't been auto-restarted: - if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get())) - { - if (stream) - { - size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get()); - if (num_reasons > 0) - { - // FIXME: Do we want to report this, or would that just be annoyingly chatty? - if (num_reasons == 1) - { - const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0); - stream->Printf ("Process %" PRIu64 " stopped and restarted: %s\n", - process_sp->GetID(), - reason ? reason : "<UNKNOWN REASON>"); - } - else - { - stream->Printf ("Process %" PRIu64 " stopped and restarted, reasons:\n", - process_sp->GetID()); - - - for (size_t i = 0; i < num_reasons; i++) - { - const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i); - stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>"); - } - } - } - } + StateType event_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (event_state == eStateInvalid) + return false; + + switch (event_state) { + case eStateInvalid: + case eStateUnloaded: + case eStateAttaching: + case eStateLaunching: + case eStateStepping: + case eStateDetached: + if (stream) + stream->Printf("Process %" PRIu64 " %s\n", process_sp->GetID(), + StateAsCString(event_state)); + if (event_state == eStateDetached) + pop_process_io_handler = true; + break; + + case eStateConnected: + case eStateRunning: + // Don't be chatty when we run... + break; + + case eStateExited: + if (stream) + process_sp->GetStatus(*stream); + pop_process_io_handler = true; + break; + + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + // Make sure the program hasn't been auto-restarted: + if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) { + if (stream) { + size_t num_reasons = + Process::ProcessEventData::GetNumRestartedReasons(event_sp.get()); + if (num_reasons > 0) { + // FIXME: Do we want to report this, or would that just be annoyingly + // chatty? + if (num_reasons == 1) { + const char *reason = + Process::ProcessEventData::GetRestartedReasonAtIndex( + event_sp.get(), 0); + stream->Printf("Process %" PRIu64 " stopped and restarted: %s\n", + process_sp->GetID(), + reason ? reason : "<UNKNOWN REASON>"); + } else { + stream->Printf("Process %" PRIu64 + " stopped and restarted, reasons:\n", + process_sp->GetID()); + + for (size_t i = 0; i < num_reasons; i++) { + const char *reason = + Process::ProcessEventData::GetRestartedReasonAtIndex( + event_sp.get(), i); + stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>"); } + } + } + } + } else { + StopInfoSP curr_thread_stop_info_sp; + // Lock the thread list so it doesn't change on us, this is the scope for + // the locker: + { + ThreadList &thread_list = process_sp->GetThreadList(); + std::lock_guard<std::recursive_mutex> guard(thread_list.GetMutex()); + + ThreadSP curr_thread(thread_list.GetSelectedThread()); + ThreadSP thread; + StopReason curr_thread_stop_reason = eStopReasonInvalid; + if (curr_thread) { + curr_thread_stop_reason = curr_thread->GetStopReason(); + curr_thread_stop_info_sp = curr_thread->GetStopInfo(); + } + if (!curr_thread || !curr_thread->IsValid() || + curr_thread_stop_reason == eStopReasonInvalid || + curr_thread_stop_reason == eStopReasonNone) { + // Prefer a thread that has just completed its plan over another + // thread as current thread. + ThreadSP plan_thread; + ThreadSP other_thread; + + const size_t num_threads = thread_list.GetSize(); + size_t i; + for (i = 0; i < num_threads; ++i) { + thread = thread_list.GetThreadAtIndex(i); + StopReason thread_stop_reason = thread->GetStopReason(); + switch (thread_stop_reason) { + case eStopReasonInvalid: + case eStopReasonNone: + break; + + case eStopReasonSignal: { + // Don't select a signal thread if we weren't going to stop at + // that + // signal. We have to have had another reason for stopping here, + // and + // the user doesn't want to see this thread. + uint64_t signo = thread->GetStopInfo()->GetValue(); + if (process_sp->GetUnixSignals()->GetShouldStop(signo)) { + if (!other_thread) + other_thread = thread; + } + break; + } + case eStopReasonTrace: + case eStopReasonBreakpoint: + case eStopReasonWatchpoint: + case eStopReasonException: + case eStopReasonExec: + case eStopReasonThreadExiting: + case eStopReasonInstrumentation: + if (!other_thread) + other_thread = thread; + break; + case eStopReasonPlanComplete: + if (!plan_thread) + plan_thread = thread; + break; + } + } + if (plan_thread) + thread_list.SetSelectedThreadByID(plan_thread->GetID()); + else if (other_thread) + thread_list.SetSelectedThreadByID(other_thread->GetID()); + else { + if (curr_thread && curr_thread->IsValid()) + thread = curr_thread; else - { - StopInfoSP curr_thread_stop_info_sp; - // Lock the thread list so it doesn't change on us, this is the scope for the locker: - { - ThreadList &thread_list = process_sp->GetThreadList(); - std::lock_guard<std::recursive_mutex> guard(thread_list.GetMutex()); - - ThreadSP curr_thread (thread_list.GetSelectedThread()); - ThreadSP thread; - StopReason curr_thread_stop_reason = eStopReasonInvalid; - if (curr_thread) - { - curr_thread_stop_reason = curr_thread->GetStopReason(); - curr_thread_stop_info_sp = curr_thread->GetStopInfo(); - } - if (!curr_thread || - !curr_thread->IsValid() || - curr_thread_stop_reason == eStopReasonInvalid || - curr_thread_stop_reason == eStopReasonNone) - { - // Prefer a thread that has just completed its plan over another thread as current thread. - ThreadSP plan_thread; - ThreadSP other_thread; - - const size_t num_threads = thread_list.GetSize(); - size_t i; - for (i = 0; i < num_threads; ++i) - { - thread = thread_list.GetThreadAtIndex(i); - StopReason thread_stop_reason = thread->GetStopReason(); - switch (thread_stop_reason) - { - case eStopReasonInvalid: - case eStopReasonNone: - break; - - case eStopReasonSignal: - { - // Don't select a signal thread if we weren't going to stop at that - // signal. We have to have had another reason for stopping here, and - // the user doesn't want to see this thread. - uint64_t signo = thread->GetStopInfo()->GetValue(); - if (process_sp->GetUnixSignals()->GetShouldStop(signo)) - { - if (!other_thread) - other_thread = thread; - } - break; - } - case eStopReasonTrace: - case eStopReasonBreakpoint: - case eStopReasonWatchpoint: - case eStopReasonException: - case eStopReasonExec: - case eStopReasonThreadExiting: - case eStopReasonInstrumentation: - if (!other_thread) - other_thread = thread; - break; - case eStopReasonPlanComplete: - if (!plan_thread) - plan_thread = thread; - break; - } - } - if (plan_thread) - thread_list.SetSelectedThreadByID (plan_thread->GetID()); - else if (other_thread) - thread_list.SetSelectedThreadByID (other_thread->GetID()); - else - { - if (curr_thread && curr_thread->IsValid()) - thread = curr_thread; - else - thread = thread_list.GetThreadAtIndex(0); - - if (thread) - thread_list.SetSelectedThreadByID (thread->GetID()); - } - } - } - // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code, - // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to - // have a hard time restarting the process. - if (stream) - { - Debugger &debugger = process_sp->GetTarget().GetDebugger(); - if (debugger.GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget()) - { - const bool only_threads_with_stop_reason = true; - const uint32_t start_frame = 0; - const uint32_t num_frames = 1; - const uint32_t num_frames_with_source = 1; - process_sp->GetStatus(*stream); - process_sp->GetThreadStatus (*stream, - only_threads_with_stop_reason, - start_frame, - num_frames, - num_frames_with_source); - if (curr_thread_stop_info_sp) - { - lldb::addr_t crashing_address; - ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference(curr_thread_stop_info_sp, &crashing_address); - if (valobj_sp) - { - const bool qualify_cxx_base_classes = false; - - const ValueObject::GetExpressionPathFormat format = ValueObject::GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers; - stream->PutCString("Likely cause: "); - valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes, format); - stream->Printf(" accessed 0x%" PRIx64 "\n", crashing_address); - } - } - } - else - { - uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this()); - if (target_idx != UINT32_MAX) - stream->Printf ("Target %d: (", target_idx); - else - stream->Printf ("Target <unknown index>: ("); - process_sp->GetTarget().Dump (stream, eDescriptionLevelBrief); - stream->Printf (") stopped.\n"); - } - } + thread = thread_list.GetThreadAtIndex(0); - // Pop the process IO handler - pop_process_io_handler = true; + if (thread) + thread_list.SetSelectedThreadByID(thread->GetID()); + } + } + } + // Drop the ThreadList mutex by here, since GetThreadStatus below might + // have to run code, + // e.g. for Data formatters, and if we hold the ThreadList mutex, then the + // process is going to + // have a hard time restarting the process. + if (stream) { + Debugger &debugger = process_sp->GetTarget().GetDebugger(); + if (debugger.GetTargetList().GetSelectedTarget().get() == + &process_sp->GetTarget()) { + const bool only_threads_with_stop_reason = true; + const uint32_t start_frame = 0; + const uint32_t num_frames = 1; + const uint32_t num_frames_with_source = 1; + process_sp->GetStatus(*stream); + process_sp->GetThreadStatus(*stream, only_threads_with_stop_reason, + start_frame, num_frames, + num_frames_with_source); + if (curr_thread_stop_info_sp) { + lldb::addr_t crashing_address; + ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference( + curr_thread_stop_info_sp, &crashing_address); + if (valobj_sp) { + const bool qualify_cxx_base_classes = false; + + const ValueObject::GetExpressionPathFormat format = + ValueObject::GetExpressionPathFormat:: + eGetExpressionPathFormatHonorPointers; + stream->PutCString("Likely cause: "); + valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes, + format); + stream->Printf(" accessed 0x%" PRIx64 "\n", crashing_address); } - break; + } + } else { + uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget( + process_sp->GetTarget().shared_from_this()); + if (target_idx != UINT32_MAX) + stream->Printf("Target %d: (", target_idx); + else + stream->Printf("Target <unknown index>: ("); + process_sp->GetTarget().Dump(stream, eDescriptionLevelBrief); + stream->Printf(") stopped.\n"); + } + } + + // Pop the process IO handler + pop_process_io_handler = true; } + break; + } - if (handle_pop && pop_process_io_handler) - process_sp->PopProcessIOHandler(); + if (handle_pop && pop_process_io_handler) + process_sp->PopProcessIOHandler(); - return true; + return true; } -StateType -Process::WaitForState(const std::chrono::microseconds &timeout, const StateType *match_states, - const uint32_t num_match_states) -{ - EventSP event_sp; - StateType state = GetState(); - while (state != eStateInvalid) - { - // If we are exited or detached, we won't ever get back to any - // other valid state... - if (state == eStateDetached || state == eStateExited) - return state; - - state = WaitForStateChangedEvents(timeout, event_sp, nullptr); - - for (uint32_t i = 0; i < num_match_states; ++i) - { - if (match_states[i] == state) - return state; - } - } - return state; -} +StateType Process::WaitForState(const std::chrono::microseconds &timeout, + const StateType *match_states, + const uint32_t num_match_states) { + EventSP event_sp; + StateType state = GetState(); + while (state != eStateInvalid) { + // If we are exited or detached, we won't ever get back to any + // other valid state... + if (state == eStateDetached || state == eStateExited) + return state; -bool -Process::HijackProcessEvents (ListenerSP listener_sp) -{ - if (listener_sp) - { - return HijackBroadcaster(listener_sp, eBroadcastBitStateChanged | eBroadcastBitInterrupt); + state = WaitForStateChangedEvents(timeout, event_sp, nullptr); + + for (uint32_t i = 0; i < num_match_states; ++i) { + if (match_states[i] == state) + return state; } - else - return false; + } + return state; } -void -Process::RestoreProcessEvents () -{ - RestoreBroadcaster(); +bool Process::HijackProcessEvents(ListenerSP listener_sp) { + if (listener_sp) { + return HijackBroadcaster(listener_sp, eBroadcastBitStateChanged | + eBroadcastBitInterrupt); + } else + return false; } -StateType -Process::WaitForStateChangedEvents(const std::chrono::microseconds &timeout, EventSP &event_sp, - ListenerSP hijack_listener_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +void Process::RestoreProcessEvents() { RestoreBroadcaster(); } - if (log) - log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__, - static_cast<unsigned long long>(timeout.count())); - - ListenerSP listener_sp = hijack_listener_sp; - if (!listener_sp) - listener_sp = m_listener_sp; - - StateType state = eStateInvalid; - if (listener_sp->WaitForEventForBroadcasterWithType (timeout, - this, - eBroadcastBitStateChanged | eBroadcastBitInterrupt, - event_sp)) - { - if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) - state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - else if (log) - log->Printf ("Process::%s got no event or was interrupted.", __FUNCTION__); - } +StateType +Process::WaitForStateChangedEvents(const std::chrono::microseconds &timeout, + EventSP &event_sp, + ListenerSP hijack_listener_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (log) + log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__, + static_cast<unsigned long long>(timeout.count())); + + ListenerSP listener_sp = hijack_listener_sp; + if (!listener_sp) + listener_sp = m_listener_sp; + + StateType state = eStateInvalid; + if (listener_sp->WaitForEventForBroadcasterWithType( + timeout, this, eBroadcastBitStateChanged | eBroadcastBitInterrupt, + event_sp)) { + if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) + state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + else if (log) + log->Printf("Process::%s got no event or was interrupted.", __FUNCTION__); + } - if (log) - log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__, - static_cast<unsigned long long>(timeout.count()), StateAsCString(state)); - return state; + if (log) + log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__, + static_cast<unsigned long long>(timeout.count()), + StateAsCString(state)); + return state; } -Event * -Process::PeekAtStateChangedEvents () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +Event *Process::PeekAtStateChangedEvents() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::%s...", __FUNCTION__); + if (log) + log->Printf("Process::%s...", __FUNCTION__); - Event *event_ptr; - event_ptr = m_listener_sp->PeekAtNextEventForBroadcasterWithType (this, - eBroadcastBitStateChanged); - if (log) - { - if (event_ptr) - { - log->Printf ("Process::%s (event_ptr) => %s", - __FUNCTION__, - StateAsCString(ProcessEventData::GetStateFromEvent (event_ptr))); - } - else - { - log->Printf ("Process::%s no events found", - __FUNCTION__); - } + Event *event_ptr; + event_ptr = m_listener_sp->PeekAtNextEventForBroadcasterWithType( + this, eBroadcastBitStateChanged); + if (log) { + if (event_ptr) { + log->Printf( + "Process::%s (event_ptr) => %s", __FUNCTION__, + StateAsCString(ProcessEventData::GetStateFromEvent(event_ptr))); + } else { + log->Printf("Process::%s no events found", __FUNCTION__); } - return event_ptr; + } + return event_ptr; } -StateType -Process::WaitForStateChangedEventsPrivate(const std::chrono::microseconds &timeout, EventSP &event_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +StateType Process::WaitForStateChangedEventsPrivate( + const std::chrono::microseconds &timeout, EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__, - static_cast<unsigned long long>(timeout.count())); - - StateType state = eStateInvalid; - if (m_private_state_listener_sp->WaitForEventForBroadcasterWithType (timeout, - &m_private_state_broadcaster, - eBroadcastBitStateChanged | eBroadcastBitInterrupt, - event_sp)) - if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) - state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - - // This is a bit of a hack, but when we wait here we could very well return - // to the command-line, and that could disable the log, which would render the - // log we got above invalid. - if (log) - log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__, - static_cast<unsigned long long>(timeout.count()), - state == eStateInvalid ? "TIMEOUT" : StateAsCString(state)); - return state; + if (log) + log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__, + static_cast<unsigned long long>(timeout.count())); + + StateType state = eStateInvalid; + if (m_private_state_listener_sp->WaitForEventForBroadcasterWithType( + timeout, &m_private_state_broadcaster, + eBroadcastBitStateChanged | eBroadcastBitInterrupt, event_sp)) + if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged) + state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + + // This is a bit of a hack, but when we wait here we could very well return + // to the command-line, and that could disable the log, which would render the + // log we got above invalid. + if (log) + log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__, + static_cast<unsigned long long>(timeout.count()), + state == eStateInvalid ? "TIMEOUT" : StateAsCString(state)); + return state; } -bool -Process::WaitForEventsPrivate(const std::chrono::microseconds &timeout, EventSP &event_sp, bool control_only) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); +bool Process::WaitForEventsPrivate(const std::chrono::microseconds &timeout, + EventSP &event_sp, bool control_only) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__, - static_cast<unsigned long long>(timeout.count())); + if (log) + log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__, + static_cast<unsigned long long>(timeout.count())); - if (control_only) - return m_private_state_listener_sp->WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp); - else - return m_private_state_listener_sp->WaitForEvent(timeout, event_sp); + if (control_only) + return m_private_state_listener_sp->WaitForEventForBroadcaster( + timeout, &m_private_state_control_broadcaster, event_sp); + else + return m_private_state_listener_sp->WaitForEvent(timeout, event_sp); } -bool -Process::IsRunning () const -{ - return StateIsRunningState (m_public_state.GetValue()); +bool Process::IsRunning() const { + return StateIsRunningState(m_public_state.GetValue()); } -int -Process::GetExitStatus () -{ - std::lock_guard<std::mutex> guard(m_exit_status_mutex); +int Process::GetExitStatus() { + std::lock_guard<std::mutex> guard(m_exit_status_mutex); - if (m_public_state.GetValue() == eStateExited) - return m_exit_status; - return -1; + if (m_public_state.GetValue() == eStateExited) + return m_exit_status; + return -1; } -const char * -Process::GetExitDescription () -{ - std::lock_guard<std::mutex> guard(m_exit_status_mutex); +const char *Process::GetExitDescription() { + std::lock_guard<std::mutex> guard(m_exit_status_mutex); - if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty()) - return m_exit_string.c_str(); - return nullptr; + if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty()) + return m_exit_string.c_str(); + return nullptr; } -bool -Process::SetExitStatus (int status, const char *cstr) -{ - // Use a mutex to protect setting the exit status. - std::lock_guard<std::mutex> guard(m_exit_status_mutex); +bool Process::SetExitStatus(int status, const char *cstr) { + // Use a mutex to protect setting the exit status. + std::lock_guard<std::mutex> guard(m_exit_status_mutex); + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)", + status, status, cstr ? "\"" : "", cstr ? cstr : "NULL", + cstr ? "\"" : ""); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); + // We were already in the exited state + if (m_private_state.GetValue() == eStateExited) { if (log) - log->Printf("Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)", - status, status, - cstr ? "\"" : "", - cstr ? cstr : "NULL", - cstr ? "\"" : ""); - - // We were already in the exited state - if (m_private_state.GetValue() == eStateExited) - { - if (log) - log->Printf("Process::SetExitStatus () ignoring exit status because state was already set to eStateExited"); - return false; - } + log->Printf("Process::SetExitStatus () ignoring exit status because " + "state was already set to eStateExited"); + return false; + } - m_exit_status = status; - if (cstr) - m_exit_string = cstr; - else - m_exit_string.clear(); + m_exit_status = status; + if (cstr) + m_exit_string = cstr; + else + m_exit_string.clear(); - // Clear the last natural stop ID since it has a strong - // reference to this process - m_mod_id.SetStopEventForLastNaturalStopID(EventSP()); + // Clear the last natural stop ID since it has a strong + // reference to this process + m_mod_id.SetStopEventForLastNaturalStopID(EventSP()); - SetPrivateState (eStateExited); + SetPrivateState(eStateExited); - // Allow subclasses to do some cleanup - DidExit (); + // Allow subclasses to do some cleanup + DidExit(); - return true; + return true; } -bool -Process::IsAlive () -{ - switch (m_private_state.GetValue()) - { - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateStopped: - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - return true; - default: - return false; - } +bool Process::IsAlive() { + switch (m_private_state.GetValue()) { + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + return true; + default: + return false; + } } // This static callback can be used to watch for local child processes on // the current host. The child process exits, the process will be // found in the global target list (we want to be completely sure that the // lldb_private::Process doesn't go away before we can deliver the signal. -bool -Process::SetProcessExitStatus(lldb::pid_t pid, bool exited, - int signo, // Zero for no signal - int exit_status // Exit value of process if signal is zero - ) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::SetProcessExitStatus (pid=%" PRIu64 ", exited=%i, signal=%i, exit_status=%i)\n", pid, - exited, signo, exit_status); - - if (exited) - { - TargetSP target_sp(Debugger::FindTargetWithProcessID (pid)); - if (target_sp) - { - ProcessSP process_sp (target_sp->GetProcessSP()); - if (process_sp) - { - const char *signal_cstr = nullptr; - if (signo) - signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo); - - process_sp->SetExitStatus (exit_status, signal_cstr); - } - } - return true; +bool Process::SetProcessExitStatus( + lldb::pid_t pid, bool exited, + int signo, // Zero for no signal + int exit_status // Exit value of process if signal is zero + ) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::SetProcessExitStatus (pid=%" PRIu64 + ", exited=%i, signal=%i, exit_status=%i)\n", + pid, exited, signo, exit_status); + + if (exited) { + TargetSP target_sp(Debugger::FindTargetWithProcessID(pid)); + if (target_sp) { + ProcessSP process_sp(target_sp->GetProcessSP()); + if (process_sp) { + const char *signal_cstr = nullptr; + if (signo) + signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo); + + process_sp->SetExitStatus(exit_status, signal_cstr); + } } - return false; -} - -void -Process::UpdateThreadListIfNeeded () -{ - const uint32_t stop_id = GetStopID(); - if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID()) - { - const StateType state = GetPrivateState(); - if (StateIsStoppedState (state, true)) - { - std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); - // m_thread_list does have its own mutex, but we need to - // hold onto the mutex between the call to UpdateThreadList(...) - // and the os->UpdateThreadList(...) so it doesn't change on us - ThreadList &old_thread_list = m_thread_list; - ThreadList real_thread_list(this); - ThreadList new_thread_list(this); - // Always update the thread list with the protocol specific - // thread list, but only update if "true" is returned - if (UpdateThreadList (m_thread_list_real, real_thread_list)) - { - // Don't call into the OperatingSystem to update the thread list if we are shutting down, since - // that may call back into the SBAPI's, requiring the API lock which is already held by whoever is - // shutting us down, causing a deadlock. - OperatingSystem *os = GetOperatingSystem (); - if (os && !m_destroy_in_process) - { - // Clear any old backing threads where memory threads might have been - // backed by actual threads from the lldb_private::Process subclass - size_t num_old_threads = old_thread_list.GetSize(false); - for (size_t i = 0; i < num_old_threads; ++i) - old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread(); - - // Turn off dynamic types to ensure we don't run any expressions. Objective C - // can run an expression to determine if a SBValue is a dynamic type or not - // and we need to avoid this. OperatingSystem plug-ins can't run expressions - // that require running code... - - Target &target = GetTarget(); - const lldb::DynamicValueType saved_prefer_dynamic = target.GetPreferDynamicValue (); - if (saved_prefer_dynamic != lldb::eNoDynamicValues) - target.SetPreferDynamicValue(lldb::eNoDynamicValues); - - // Now let the OperatingSystem plug-in update the thread list - - os->UpdateThreadList (old_thread_list, // Old list full of threads created by OS plug-in - real_thread_list, // The actual thread list full of threads created by each lldb_private::Process subclass - new_thread_list); // The new thread list that we will show to the user that gets filled in - - if (saved_prefer_dynamic != lldb::eNoDynamicValues) - target.SetPreferDynamicValue(saved_prefer_dynamic); - } - else - { - // No OS plug-in, the new thread list is the same as the real thread list - new_thread_list = real_thread_list; - } - - m_thread_list_real.Update(real_thread_list); - m_thread_list.Update (new_thread_list); - m_thread_list.SetStopID (stop_id); - - if (GetLastNaturalStopID () != m_extended_thread_stop_id) - { - // Clear any extended threads that we may have accumulated previously - m_extended_thread_list.Clear(); - m_extended_thread_stop_id = GetLastNaturalStopID (); - - m_queue_list.Clear(); - m_queue_list_stop_id = GetLastNaturalStopID (); - } - } - } - } -} - -void -Process::UpdateQueueListIfNeeded () -{ - if (m_system_runtime_ap) - { - if (m_queue_list.GetSize() == 0 || m_queue_list_stop_id != GetLastNaturalStopID()) - { - const StateType state = GetPrivateState(); - if (StateIsStoppedState (state, true)) - { - m_system_runtime_ap->PopulateQueueList (m_queue_list); - m_queue_list_stop_id = GetLastNaturalStopID(); - } + return true; + } + return false; +} + +void Process::UpdateThreadListIfNeeded() { + const uint32_t stop_id = GetStopID(); + if (m_thread_list.GetSize(false) == 0 || + stop_id != m_thread_list.GetStopID()) { + const StateType state = GetPrivateState(); + if (StateIsStoppedState(state, true)) { + std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex()); + // m_thread_list does have its own mutex, but we need to + // hold onto the mutex between the call to UpdateThreadList(...) + // and the os->UpdateThreadList(...) so it doesn't change on us + ThreadList &old_thread_list = m_thread_list; + ThreadList real_thread_list(this); + ThreadList new_thread_list(this); + // Always update the thread list with the protocol specific + // thread list, but only update if "true" is returned + if (UpdateThreadList(m_thread_list_real, real_thread_list)) { + // Don't call into the OperatingSystem to update the thread list if we + // are shutting down, since + // that may call back into the SBAPI's, requiring the API lock which is + // already held by whoever is + // shutting us down, causing a deadlock. + OperatingSystem *os = GetOperatingSystem(); + if (os && !m_destroy_in_process) { + // Clear any old backing threads where memory threads might have been + // backed by actual threads from the lldb_private::Process subclass + size_t num_old_threads = old_thread_list.GetSize(false); + for (size_t i = 0; i < num_old_threads; ++i) + old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread(); + + // Turn off dynamic types to ensure we don't run any expressions. + // Objective C + // can run an expression to determine if a SBValue is a dynamic type + // or not + // and we need to avoid this. OperatingSystem plug-ins can't run + // expressions + // that require running code... + + Target &target = GetTarget(); + const lldb::DynamicValueType saved_prefer_dynamic = + target.GetPreferDynamicValue(); + if (saved_prefer_dynamic != lldb::eNoDynamicValues) + target.SetPreferDynamicValue(lldb::eNoDynamicValues); + + // Now let the OperatingSystem plug-in update the thread list + + os->UpdateThreadList( + old_thread_list, // Old list full of threads created by OS plug-in + real_thread_list, // The actual thread list full of threads + // created by each lldb_private::Process + // subclass + new_thread_list); // The new thread list that we will show to the + // user that gets filled in + + if (saved_prefer_dynamic != lldb::eNoDynamicValues) + target.SetPreferDynamicValue(saved_prefer_dynamic); + } else { + // No OS plug-in, the new thread list is the same as the real thread + // list + new_thread_list = real_thread_list; } - } -} - -ThreadSP -Process::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context) -{ - OperatingSystem *os = GetOperatingSystem (); - if (os) - return os->CreateThread(tid, context); - return ThreadSP(); -} - -uint32_t -Process::GetNextThreadIndexID (uint64_t thread_id) -{ - return AssignIndexIDToThread(thread_id); -} -bool -Process::HasAssignedIndexIDToThread(uint64_t thread_id) -{ - return (m_thread_id_to_index_id_map.find(thread_id) != m_thread_id_to_index_id_map.end()); -} - -uint32_t -Process::AssignIndexIDToThread(uint64_t thread_id) -{ - uint32_t result = 0; - std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_index_id_map.find(thread_id); - if (iterator == m_thread_id_to_index_id_map.end()) - { - result = ++m_thread_index_id; - m_thread_id_to_index_id_map[thread_id] = result; - } - else - { - result = iterator->second; - } - - return result; -} + m_thread_list_real.Update(real_thread_list); + m_thread_list.Update(new_thread_list); + m_thread_list.SetStopID(stop_id); -StateType -Process::GetState() -{ - // If any other threads access this we will need a mutex for it - return m_public_state.GetValue (); -} + if (GetLastNaturalStopID() != m_extended_thread_stop_id) { + // Clear any extended threads that we may have accumulated previously + m_extended_thread_list.Clear(); + m_extended_thread_stop_id = GetLastNaturalStopID(); -bool -Process::StateChangedIsExternallyHijacked() -{ - if (IsHijackedForEvent(eBroadcastBitStateChanged)) - { - const char *hijacking_name = GetHijackingListenerName(); - if (hijacking_name && strcmp(hijacking_name, "lldb.Process.ResumeSynchronous.hijack")) - return true; - } - return false; -} - -void -Process::SetPublicState (StateType new_state, bool restarted) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::SetPublicState (state = %s, restarted = %i)", StateAsCString(new_state), restarted); - const StateType old_state = m_public_state.GetValue(); - m_public_state.SetValue (new_state); - - // On the transition from Run to Stopped, we unlock the writer end of the - // run lock. The lock gets locked in Resume, which is the public API - // to tell the program to run. - if (!StateChangedIsExternallyHijacked()) - { - if (new_state == eStateDetached) - { - if (log) - log->Printf("Process::SetPublicState (%s) -- unlocking run lock for detach", StateAsCString(new_state)); - m_public_run_lock.SetStopped(); + m_queue_list.Clear(); + m_queue_list_stop_id = GetLastNaturalStopID(); } - else - { - const bool old_state_is_stopped = StateIsStoppedState(old_state, false); - const bool new_state_is_stopped = StateIsStoppedState(new_state, false); - if ((old_state_is_stopped != new_state_is_stopped)) - { - if (new_state_is_stopped && !restarted) - { - if (log) - log->Printf("Process::SetPublicState (%s) -- unlocking run lock", StateAsCString(new_state)); - m_public_run_lock.SetStopped(); - } - } + } + } + } +} + +void Process::UpdateQueueListIfNeeded() { + if (m_system_runtime_ap) { + if (m_queue_list.GetSize() == 0 || + m_queue_list_stop_id != GetLastNaturalStopID()) { + const StateType state = GetPrivateState(); + if (StateIsStoppedState(state, true)) { + m_system_runtime_ap->PopulateQueueList(m_queue_list); + m_queue_list_stop_id = GetLastNaturalStopID(); + } + } + } +} + +ThreadSP Process::CreateOSPluginThread(lldb::tid_t tid, lldb::addr_t context) { + OperatingSystem *os = GetOperatingSystem(); + if (os) + return os->CreateThread(tid, context); + return ThreadSP(); +} + +uint32_t Process::GetNextThreadIndexID(uint64_t thread_id) { + return AssignIndexIDToThread(thread_id); +} + +bool Process::HasAssignedIndexIDToThread(uint64_t thread_id) { + return (m_thread_id_to_index_id_map.find(thread_id) != + m_thread_id_to_index_id_map.end()); +} + +uint32_t Process::AssignIndexIDToThread(uint64_t thread_id) { + uint32_t result = 0; + std::map<uint64_t, uint32_t>::iterator iterator = + m_thread_id_to_index_id_map.find(thread_id); + if (iterator == m_thread_id_to_index_id_map.end()) { + result = ++m_thread_index_id; + m_thread_id_to_index_id_map[thread_id] = result; + } else { + result = iterator->second; + } + + return result; +} + +StateType Process::GetState() { + // If any other threads access this we will need a mutex for it + return m_public_state.GetValue(); +} + +bool Process::StateChangedIsExternallyHijacked() { + if (IsHijackedForEvent(eBroadcastBitStateChanged)) { + const char *hijacking_name = GetHijackingListenerName(); + if (hijacking_name && + strcmp(hijacking_name, "lldb.Process.ResumeSynchronous.hijack")) + return true; + } + return false; +} + +void Process::SetPublicState(StateType new_state, bool restarted) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::SetPublicState (state = %s, restarted = %i)", + StateAsCString(new_state), restarted); + const StateType old_state = m_public_state.GetValue(); + m_public_state.SetValue(new_state); + + // On the transition from Run to Stopped, we unlock the writer end of the + // run lock. The lock gets locked in Resume, which is the public API + // to tell the program to run. + if (!StateChangedIsExternallyHijacked()) { + if (new_state == eStateDetached) { + if (log) + log->Printf( + "Process::SetPublicState (%s) -- unlocking run lock for detach", + StateAsCString(new_state)); + m_public_run_lock.SetStopped(); + } else { + const bool old_state_is_stopped = StateIsStoppedState(old_state, false); + const bool new_state_is_stopped = StateIsStoppedState(new_state, false); + if ((old_state_is_stopped != new_state_is_stopped)) { + if (new_state_is_stopped && !restarted) { + if (log) + log->Printf("Process::SetPublicState (%s) -- unlocking run lock", + StateAsCString(new_state)); + m_public_run_lock.SetStopped(); } + } } + } } -Error -Process::Resume () -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); +Error Process::Resume() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::Resume -- locking run lock"); + if (!m_public_run_lock.TrySetRunning()) { + Error error("Resume request failed - process still running."); if (log) - log->Printf("Process::Resume -- locking run lock"); - if (!m_public_run_lock.TrySetRunning()) - { - Error error("Resume request failed - process still running."); - if (log) - log->Printf ("Process::Resume: -- TrySetRunning failed, not resuming."); - return error; - } - return PrivateResume(); + log->Printf("Process::Resume: -- TrySetRunning failed, not resuming."); + return error; + } + return PrivateResume(); } -Error -Process::ResumeSynchronous (Stream *stream) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); +Error Process::ResumeSynchronous(Stream *stream) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::ResumeSynchronous -- locking run lock"); + if (!m_public_run_lock.TrySetRunning()) { + Error error("Resume request failed - process still running."); if (log) - log->Printf("Process::ResumeSynchronous -- locking run lock"); - if (!m_public_run_lock.TrySetRunning()) - { - Error error("Resume request failed - process still running."); - if (log) - log->Printf ("Process::Resume: -- TrySetRunning failed, not resuming."); - return error; - } + log->Printf("Process::Resume: -- TrySetRunning failed, not resuming."); + return error; + } - ListenerSP listener_sp (Listener::MakeListener("lldb.Process.ResumeSynchronous.hijack")); - HijackProcessEvents(listener_sp); + ListenerSP listener_sp( + Listener::MakeListener("lldb.Process.ResumeSynchronous.hijack")); + HijackProcessEvents(listener_sp); - Error error = PrivateResume(); - if (error.Success()) - { - StateType state = WaitForProcessToStop(std::chrono::microseconds(0), NULL, true, listener_sp, stream); - const bool must_be_alive = false; // eStateExited is ok, so this must be false - if (!StateIsStoppedState(state, must_be_alive)) - error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state)); - } + Error error = PrivateResume(); + if (error.Success()) { + StateType state = WaitForProcessToStop(std::chrono::microseconds(0), NULL, + true, listener_sp, stream); + const bool must_be_alive = + false; // eStateExited is ok, so this must be false + if (!StateIsStoppedState(state, must_be_alive)) + error.SetErrorStringWithFormat( + "process not in stopped state after synchronous resume: %s", + StateAsCString(state)); + } - // Undo the hijacking of process events... - RestoreProcessEvents(); + // Undo the hijacking of process events... + RestoreProcessEvents(); - return error; + return error; } -StateType -Process::GetPrivateState () -{ - return m_private_state.GetValue(); -} +StateType Process::GetPrivateState() { return m_private_state.GetValue(); } -void -Process::SetPrivateState (StateType new_state) -{ - if (m_finalize_called) - return; +void Process::SetPrivateState(StateType new_state) { + if (m_finalize_called) + return; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS)); - bool state_changed = false; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE | + LIBLLDB_LOG_PROCESS)); + bool state_changed = false; - if (log) - log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state)); + if (log) + log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state)); - std::lock_guard<std::recursive_mutex> thread_guard(m_thread_list.GetMutex()); - std::lock_guard<std::recursive_mutex> guard(m_private_state.GetMutex()); + std::lock_guard<std::recursive_mutex> thread_guard(m_thread_list.GetMutex()); + std::lock_guard<std::recursive_mutex> guard(m_private_state.GetMutex()); - const StateType old_state = m_private_state.GetValueNoLock (); - state_changed = old_state != new_state; + const StateType old_state = m_private_state.GetValueNoLock(); + state_changed = old_state != new_state; - const bool old_state_is_stopped = StateIsStoppedState(old_state, false); - const bool new_state_is_stopped = StateIsStoppedState(new_state, false); - if (old_state_is_stopped != new_state_is_stopped) - { - if (new_state_is_stopped) - m_private_run_lock.SetStopped(); - else - m_private_run_lock.SetRunning(); - } - - if (state_changed) - { - m_private_state.SetValueNoLock (new_state); - EventSP event_sp (new Event (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state))); - if (StateIsStoppedState(new_state, false)) - { - // Note, this currently assumes that all threads in the list - // stop when the process stops. In the future we will want to - // support a debugging model where some threads continue to run - // while others are stopped. When that happens we will either need - // a way for the thread list to identify which threads are stopping - // or create a special thread list containing only threads which - // actually stopped. - // - // The process plugin is responsible for managing the actual - // behavior of the threads and should have stopped any threads - // that are going to stop before we get here. - m_thread_list.DidStop(); - - m_mod_id.BumpStopID(); - if (!m_mod_id.IsLastResumeForUserExpression()) - m_mod_id.SetStopEventForLastNaturalStopID(event_sp); - m_memory_cache.Clear(); - if (log) - log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_mod_id.GetStopID()); - } - - // Use our target to get a shared pointer to ourselves... - if (m_finalize_called && !PrivateStateThreadIsValid()) - BroadcastEvent (event_sp); - else - m_private_state_broadcaster.BroadcastEvent (event_sp); - } + const bool old_state_is_stopped = StateIsStoppedState(old_state, false); + const bool new_state_is_stopped = StateIsStoppedState(new_state, false); + if (old_state_is_stopped != new_state_is_stopped) { + if (new_state_is_stopped) + m_private_run_lock.SetStopped(); else - { - if (log) - log->Printf("Process::SetPrivateState (%s) state didn't change. Ignoring...", StateAsCString(new_state)); - } -} - -void -Process::SetRunningUserExpression (bool on) -{ - m_mod_id.SetRunningUserExpression (on); + m_private_run_lock.SetRunning(); + } + + if (state_changed) { + m_private_state.SetValueNoLock(new_state); + EventSP event_sp( + new Event(eBroadcastBitStateChanged, + new ProcessEventData(shared_from_this(), new_state))); + if (StateIsStoppedState(new_state, false)) { + // Note, this currently assumes that all threads in the list + // stop when the process stops. In the future we will want to + // support a debugging model where some threads continue to run + // while others are stopped. When that happens we will either need + // a way for the thread list to identify which threads are stopping + // or create a special thread list containing only threads which + // actually stopped. + // + // The process plugin is responsible for managing the actual + // behavior of the threads and should have stopped any threads + // that are going to stop before we get here. + m_thread_list.DidStop(); + + m_mod_id.BumpStopID(); + if (!m_mod_id.IsLastResumeForUserExpression()) + m_mod_id.SetStopEventForLastNaturalStopID(event_sp); + m_memory_cache.Clear(); + if (log) + log->Printf("Process::SetPrivateState (%s) stop_id = %u", + StateAsCString(new_state), m_mod_id.GetStopID()); + } + + // Use our target to get a shared pointer to ourselves... + if (m_finalize_called && !PrivateStateThreadIsValid()) + BroadcastEvent(event_sp); + else + m_private_state_broadcaster.BroadcastEvent(event_sp); + } else { + if (log) + log->Printf( + "Process::SetPrivateState (%s) state didn't change. Ignoring...", + StateAsCString(new_state)); + } } -addr_t -Process::GetImageInfoAddress() -{ - return LLDB_INVALID_ADDRESS; +void Process::SetRunningUserExpression(bool on) { + m_mod_id.SetRunningUserExpression(on); } -const lldb::ABISP & -Process::GetABI() -{ - if (!m_abi_sp) - m_abi_sp = ABI::FindPlugin(GetTarget().GetArchitecture()); - return m_abi_sp; -} +addr_t Process::GetImageInfoAddress() { return LLDB_INVALID_ADDRESS; } -LanguageRuntime * -Process::GetLanguageRuntime(lldb::LanguageType language, bool retry_if_null) -{ - if (m_finalizing) - return nullptr; - - LanguageRuntimeCollection::iterator pos; - pos = m_language_runtimes.find (language); - if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second)) - { - lldb::LanguageRuntimeSP runtime_sp(LanguageRuntime::FindPlugin(this, language)); - - m_language_runtimes[language] = runtime_sp; - return runtime_sp.get(); - } - else - return (*pos).second.get(); +const lldb::ABISP &Process::GetABI() { + if (!m_abi_sp) + m_abi_sp = ABI::FindPlugin(GetTarget().GetArchitecture()); + return m_abi_sp; } -CPPLanguageRuntime * -Process::GetCPPLanguageRuntime (bool retry_if_null) -{ - LanguageRuntime *runtime = GetLanguageRuntime(eLanguageTypeC_plus_plus, retry_if_null); - if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeC_plus_plus) - return static_cast<CPPLanguageRuntime *> (runtime); +LanguageRuntime *Process::GetLanguageRuntime(lldb::LanguageType language, + bool retry_if_null) { + if (m_finalizing) return nullptr; + + LanguageRuntimeCollection::iterator pos; + pos = m_language_runtimes.find(language); + if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second)) { + lldb::LanguageRuntimeSP runtime_sp( + LanguageRuntime::FindPlugin(this, language)); + + m_language_runtimes[language] = runtime_sp; + return runtime_sp.get(); + } else + return (*pos).second.get(); } -ObjCLanguageRuntime * -Process::GetObjCLanguageRuntime (bool retry_if_null) -{ - LanguageRuntime *runtime = GetLanguageRuntime(eLanguageTypeObjC, retry_if_null); - if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeObjC) - return static_cast<ObjCLanguageRuntime *> (runtime); - return nullptr; +CPPLanguageRuntime *Process::GetCPPLanguageRuntime(bool retry_if_null) { + LanguageRuntime *runtime = + GetLanguageRuntime(eLanguageTypeC_plus_plus, retry_if_null); + if (runtime != nullptr && + runtime->GetLanguageType() == eLanguageTypeC_plus_plus) + return static_cast<CPPLanguageRuntime *>(runtime); + return nullptr; } -bool -Process::IsPossibleDynamicValue (ValueObject& in_value) -{ - if (m_finalizing) - return false; +ObjCLanguageRuntime *Process::GetObjCLanguageRuntime(bool retry_if_null) { + LanguageRuntime *runtime = + GetLanguageRuntime(eLanguageTypeObjC, retry_if_null); + if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeObjC) + return static_cast<ObjCLanguageRuntime *>(runtime); + return nullptr; +} - if (in_value.IsDynamic()) - return false; - LanguageType known_type = in_value.GetObjectRuntimeLanguage(); +bool Process::IsPossibleDynamicValue(ValueObject &in_value) { + if (m_finalizing) + return false; - if (known_type != eLanguageTypeUnknown && known_type != eLanguageTypeC) - { - LanguageRuntime *runtime = GetLanguageRuntime (known_type); - return runtime ? runtime->CouldHaveDynamicValue(in_value) : false; - } + if (in_value.IsDynamic()) + return false; + LanguageType known_type = in_value.GetObjectRuntimeLanguage(); - LanguageRuntime *cpp_runtime = GetLanguageRuntime (eLanguageTypeC_plus_plus); - if (cpp_runtime && cpp_runtime->CouldHaveDynamicValue(in_value)) - return true; - - LanguageRuntime *objc_runtime = GetLanguageRuntime (eLanguageTypeObjC); - return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false; -} + if (known_type != eLanguageTypeUnknown && known_type != eLanguageTypeC) { + LanguageRuntime *runtime = GetLanguageRuntime(known_type); + return runtime ? runtime->CouldHaveDynamicValue(in_value) : false; + } -void -Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) -{ - m_dynamic_checkers_ap.reset(dynamic_checkers); -} + LanguageRuntime *cpp_runtime = GetLanguageRuntime(eLanguageTypeC_plus_plus); + if (cpp_runtime && cpp_runtime->CouldHaveDynamicValue(in_value)) + return true; -BreakpointSiteList & -Process::GetBreakpointSiteList() -{ - return m_breakpoint_site_list; + LanguageRuntime *objc_runtime = GetLanguageRuntime(eLanguageTypeObjC); + return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false; } -const BreakpointSiteList & -Process::GetBreakpointSiteList() const -{ - return m_breakpoint_site_list; +void Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) { + m_dynamic_checkers_ap.reset(dynamic_checkers); } -void -Process::DisableAllBreakpointSites () -{ - m_breakpoint_site_list.ForEach([this](BreakpointSite *bp_site) -> void { -// bp_site->SetEnabled(true); - DisableBreakpointSite(bp_site); - }); +BreakpointSiteList &Process::GetBreakpointSiteList() { + return m_breakpoint_site_list; } -Error -Process::ClearBreakpointSiteByID (lldb::user_id_t break_id) -{ - Error error (DisableBreakpointSiteByID (break_id)); - - if (error.Success()) - m_breakpoint_site_list.Remove(break_id); - - return error; +const BreakpointSiteList &Process::GetBreakpointSiteList() const { + return m_breakpoint_site_list; } -Error -Process::DisableBreakpointSiteByID (lldb::user_id_t break_id) -{ - Error error; - BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id); - if (bp_site_sp) - { - if (bp_site_sp->IsEnabled()) - error = DisableBreakpointSite (bp_site_sp.get()); - } - else - { - error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, break_id); - } - - return error; +void Process::DisableAllBreakpointSites() { + m_breakpoint_site_list.ForEach([this](BreakpointSite *bp_site) -> void { + // bp_site->SetEnabled(true); + DisableBreakpointSite(bp_site); + }); } -Error -Process::EnableBreakpointSiteByID (lldb::user_id_t break_id) -{ - Error error; - BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id); - if (bp_site_sp) - { - if (!bp_site_sp->IsEnabled()) - error = EnableBreakpointSite (bp_site_sp.get()); - } - else - { - error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, break_id); - } - return error; -} +Error Process::ClearBreakpointSiteByID(lldb::user_id_t break_id) { + Error error(DisableBreakpointSiteByID(break_id)); -lldb::break_id_t -Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware) -{ - addr_t load_addr = LLDB_INVALID_ADDRESS; - - bool show_error = true; - switch (GetState()) - { - case eStateInvalid: - case eStateUnloaded: - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - case eStateDetached: - case eStateExited: - show_error = false; - break; - - case eStateStopped: - case eStateRunning: - case eStateStepping: - case eStateCrashed: - case eStateSuspended: - show_error = IsAlive(); - break; - } + if (error.Success()) + m_breakpoint_site_list.Remove(break_id); - // Reset the IsIndirect flag here, in case the location changes from - // pointing to a indirect symbol to a regular symbol. - owner->SetIsIndirect (false); - - if (owner->ShouldResolveIndirectFunctions()) - { - Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol(); - if (symbol && symbol->IsIndirect()) - { - Error error; - Address symbol_address = symbol->GetAddress(); - load_addr = ResolveIndirectFunction (&symbol_address, error); - if (!error.Success() && show_error) - { - GetTarget().GetDebugger().GetErrorFile()->Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", - symbol->GetLoadAddress(&GetTarget()), - owner->GetBreakpoint().GetID(), - owner->GetID(), - error.AsCString() ? error.AsCString() : "unknown error"); - return LLDB_INVALID_BREAK_ID; - } - Address resolved_address(load_addr); - load_addr = resolved_address.GetOpcodeLoadAddress (&GetTarget()); - owner->SetIsIndirect(true); - } - else - load_addr = owner->GetAddress().GetOpcodeLoadAddress (&GetTarget()); - } - else - load_addr = owner->GetAddress().GetOpcodeLoadAddress (&GetTarget()); - - if (load_addr != LLDB_INVALID_ADDRESS) - { - BreakpointSiteSP bp_site_sp; - - // Look up this breakpoint site. If it exists, then add this new owner, otherwise - // create a new breakpoint site and add it. - - bp_site_sp = m_breakpoint_site_list.FindByAddress (load_addr); - - if (bp_site_sp) - { - bp_site_sp->AddOwner (owner); - owner->SetBreakpointSite (bp_site_sp); - return bp_site_sp->GetID(); - } - else - { - bp_site_sp.reset (new BreakpointSite (&m_breakpoint_site_list, owner, load_addr, use_hardware)); - if (bp_site_sp) - { - Error error = EnableBreakpointSite (bp_site_sp.get()); - if (error.Success()) - { - owner->SetBreakpointSite (bp_site_sp); - return m_breakpoint_site_list.Add (bp_site_sp); - } - else - { - if (show_error) - { - // Report error for setting breakpoint... - GetTarget().GetDebugger().GetErrorFile()->Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n", - load_addr, - owner->GetBreakpoint().GetID(), - owner->GetID(), - error.AsCString() ? error.AsCString() : "unknown error"); - } - } - } - } - } - // We failed to enable the breakpoint - return LLDB_INVALID_BREAK_ID; + return error; } -void -Process::RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id, lldb::user_id_t owner_loc_id, BreakpointSiteSP &bp_site_sp) -{ - uint32_t num_owners = bp_site_sp->RemoveOwner (owner_id, owner_loc_id); - if (num_owners == 0) - { - // Don't try to disable the site if we don't have a live process anymore. - if (IsAlive()) - DisableBreakpointSite (bp_site_sp.get()); - m_breakpoint_site_list.RemoveByAddress(bp_site_sp->GetLoadAddress()); - } -} +Error Process::DisableBreakpointSiteByID(lldb::user_id_t break_id) { + Error error; + BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID(break_id); + if (bp_site_sp) { + if (bp_site_sp->IsEnabled()) + error = DisableBreakpointSite(bp_site_sp.get()); + } else { + error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, + break_id); + } -size_t -Process::RemoveBreakpointOpcodesFromBuffer (addr_t bp_addr, size_t size, uint8_t *buf) const -{ - size_t bytes_removed = 0; - BreakpointSiteList bp_sites_in_range; - - if (m_breakpoint_site_list.FindInRange (bp_addr, bp_addr + size, bp_sites_in_range)) - { - bp_sites_in_range.ForEach([bp_addr, size, buf, &bytes_removed](BreakpointSite *bp_site) -> void { - if (bp_site->GetType() == BreakpointSite::eSoftware) - { - addr_t intersect_addr; - size_t intersect_size; - size_t opcode_offset; - if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr, &intersect_size, &opcode_offset)) - { - assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size); - assert(bp_addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= bp_addr + size); - assert(opcode_offset + intersect_size <= bp_site->GetByteSize()); - size_t buf_offset = intersect_addr - bp_addr; - ::memcpy(buf + buf_offset, bp_site->GetSavedOpcodeBytes() + opcode_offset, intersect_size); - } - } - }); - } - return bytes_removed; + return error; } -size_t -Process::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site) -{ - PlatformSP platform_sp (GetTarget().GetPlatform()); - if (platform_sp) - return platform_sp->GetSoftwareBreakpointTrapOpcode (GetTarget(), bp_site); - return 0; +Error Process::EnableBreakpointSiteByID(lldb::user_id_t break_id) { + Error error; + BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID(break_id); + if (bp_site_sp) { + if (!bp_site_sp->IsEnabled()) + error = EnableBreakpointSite(bp_site_sp.get()); + } else { + error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, + break_id); + } + return error; } -Error -Process::EnableSoftwareBreakpoint (BreakpointSite *bp_site) -{ - Error error; - assert(bp_site != nullptr); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - const addr_t bp_addr = bp_site->GetLoadAddress(); - if (log) - log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64, bp_site->GetID(), (uint64_t)bp_addr); - if (bp_site->IsEnabled()) - { - if (log) - log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- already enabled", bp_site->GetID(), (uint64_t)bp_addr); - return error; - } - - if (bp_addr == LLDB_INVALID_ADDRESS) - { - error.SetErrorString("BreakpointSite contains an invalid load address."); - return error; - } - // Ask the lldb::Process subclass to fill in the correct software breakpoint - // trap for the breakpoint site - const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode(bp_site); - - if (bp_opcode_size == 0) - { - error.SetErrorStringWithFormat ("Process::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, bp_addr); - } - else - { - const uint8_t * const bp_opcode_bytes = bp_site->GetTrapOpcodeBytes(); - - if (bp_opcode_bytes == nullptr) - { - error.SetErrorString ("BreakpointSite doesn't contain a valid breakpoint trap opcode."); - return error; +lldb::break_id_t +Process::CreateBreakpointSite(const BreakpointLocationSP &owner, + bool use_hardware) { + addr_t load_addr = LLDB_INVALID_ADDRESS; + + bool show_error = true; + switch (GetState()) { + case eStateInvalid: + case eStateUnloaded: + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + case eStateDetached: + case eStateExited: + show_error = false; + break; + + case eStateStopped: + case eStateRunning: + case eStateStepping: + case eStateCrashed: + case eStateSuspended: + show_error = IsAlive(); + break; + } + + // Reset the IsIndirect flag here, in case the location changes from + // pointing to a indirect symbol to a regular symbol. + owner->SetIsIndirect(false); + + if (owner->ShouldResolveIndirectFunctions()) { + Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol(); + if (symbol && symbol->IsIndirect()) { + Error error; + Address symbol_address = symbol->GetAddress(); + load_addr = ResolveIndirectFunction(&symbol_address, error); + if (!error.Success() && show_error) { + GetTarget().GetDebugger().GetErrorFile()->Printf( + "warning: failed to resolve indirect function at 0x%" PRIx64 + " for breakpoint %i.%i: %s\n", + symbol->GetLoadAddress(&GetTarget()), + owner->GetBreakpoint().GetID(), owner->GetID(), + error.AsCString() ? error.AsCString() : "unknown error"); + return LLDB_INVALID_BREAK_ID; + } + Address resolved_address(load_addr); + load_addr = resolved_address.GetOpcodeLoadAddress(&GetTarget()); + owner->SetIsIndirect(true); + } else + load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget()); + } else + load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget()); + + if (load_addr != LLDB_INVALID_ADDRESS) { + BreakpointSiteSP bp_site_sp; + + // Look up this breakpoint site. If it exists, then add this new owner, + // otherwise + // create a new breakpoint site and add it. + + bp_site_sp = m_breakpoint_site_list.FindByAddress(load_addr); + + if (bp_site_sp) { + bp_site_sp->AddOwner(owner); + owner->SetBreakpointSite(bp_site_sp); + return bp_site_sp->GetID(); + } else { + bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner, + load_addr, use_hardware)); + if (bp_site_sp) { + Error error = EnableBreakpointSite(bp_site_sp.get()); + if (error.Success()) { + owner->SetBreakpointSite(bp_site_sp); + return m_breakpoint_site_list.Add(bp_site_sp); + } else { + if (show_error) { + // Report error for setting breakpoint... + GetTarget().GetDebugger().GetErrorFile()->Printf( + "warning: failed to set breakpoint site at 0x%" PRIx64 + " for breakpoint %i.%i: %s\n", + load_addr, owner->GetBreakpoint().GetID(), owner->GetID(), + error.AsCString() ? error.AsCString() : "unknown error"); + } } - - // Save the original opcode by reading it - if (DoReadMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), bp_opcode_size, error) == bp_opcode_size) - { - // Write a software breakpoint in place of the original opcode - if (DoWriteMemory(bp_addr, bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size) - { - uint8_t verify_bp_opcode_bytes[64]; - if (DoReadMemory(bp_addr, verify_bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size) - { - if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) == 0) - { - bp_site->SetEnabled(true); - bp_site->SetType (BreakpointSite::eSoftware); - if (log) - log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- SUCCESS", - bp_site->GetID(), - (uint64_t)bp_addr); - } - else - error.SetErrorString("failed to verify the breakpoint trap in memory."); - } - else - error.SetErrorString("Unable to read memory to verify breakpoint trap."); - } - else - error.SetErrorString("Unable to write breakpoint trap to memory."); + } + } + } + // We failed to enable the breakpoint + return LLDB_INVALID_BREAK_ID; +} + +void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id, + lldb::user_id_t owner_loc_id, + BreakpointSiteSP &bp_site_sp) { + uint32_t num_owners = bp_site_sp->RemoveOwner(owner_id, owner_loc_id); + if (num_owners == 0) { + // Don't try to disable the site if we don't have a live process anymore. + if (IsAlive()) + DisableBreakpointSite(bp_site_sp.get()); + m_breakpoint_site_list.RemoveByAddress(bp_site_sp->GetLoadAddress()); + } +} + +size_t Process::RemoveBreakpointOpcodesFromBuffer(addr_t bp_addr, size_t size, + uint8_t *buf) const { + size_t bytes_removed = 0; + BreakpointSiteList bp_sites_in_range; + + if (m_breakpoint_site_list.FindInRange(bp_addr, bp_addr + size, + bp_sites_in_range)) { + bp_sites_in_range.ForEach([bp_addr, size, buf, &bytes_removed]( + BreakpointSite *bp_site) -> void { + if (bp_site->GetType() == BreakpointSite::eSoftware) { + addr_t intersect_addr; + size_t intersect_size; + size_t opcode_offset; + if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr, + &intersect_size, &opcode_offset)) { + assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size); + assert(bp_addr < intersect_addr + intersect_size && + intersect_addr + intersect_size <= bp_addr + size); + assert(opcode_offset + intersect_size <= bp_site->GetByteSize()); + size_t buf_offset = intersect_addr - bp_addr; + ::memcpy(buf + buf_offset, + bp_site->GetSavedOpcodeBytes() + opcode_offset, + intersect_size); } - else - error.SetErrorString("Unable to read memory at breakpoint address."); - } - if (log && error.Fail()) - log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- FAILED: %s", - bp_site->GetID(), - (uint64_t)bp_addr, - error.AsCString()); - return error; -} - -Error -Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site) -{ - Error error; - assert(bp_site != nullptr); - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - addr_t bp_addr = bp_site->GetLoadAddress(); - lldb::user_id_t breakID = bp_site->GetID(); + } + }); + } + return bytes_removed; +} + +size_t Process::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) { + PlatformSP platform_sp(GetTarget().GetPlatform()); + if (platform_sp) + return platform_sp->GetSoftwareBreakpointTrapOpcode(GetTarget(), bp_site); + return 0; +} + +Error Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) { + Error error; + assert(bp_site != nullptr); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + const addr_t bp_addr = bp_site->GetLoadAddress(); + if (log) + log->Printf( + "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64, + bp_site->GetID(), (uint64_t)bp_addr); + if (bp_site->IsEnabled()) { if (log) - log->Printf ("Process::DisableSoftwareBreakpoint (breakID = %" PRIu64 ") addr = 0x%" PRIx64, breakID, (uint64_t)bp_addr); + log->Printf( + "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 + " -- already enabled", + bp_site->GetID(), (uint64_t)bp_addr); + return error; + } - if (bp_site->IsHardware()) - { - error.SetErrorString("Breakpoint site is a hardware breakpoint."); - } - else if (bp_site->IsEnabled()) - { - const size_t break_op_size = bp_site->GetByteSize(); - const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes(); - if (break_op_size > 0) - { - // Clear a software breakpoint instruction - uint8_t curr_break_op[8]; - assert (break_op_size <= sizeof(curr_break_op)); - bool break_op_found = false; - - // Read the breakpoint opcode - if (DoReadMemory (bp_addr, curr_break_op, break_op_size, error) == break_op_size) - { - bool verify = false; - // Make sure the breakpoint opcode exists at this address - if (::memcmp (curr_break_op, break_op, break_op_size) == 0) - { - break_op_found = true; - // We found a valid breakpoint opcode at this address, now restore - // the saved opcode. - if (DoWriteMemory (bp_addr, bp_site->GetSavedOpcodeBytes(), break_op_size, error) == break_op_size) - { - verify = true; - } - else - error.SetErrorString("Memory write failed when restoring original opcode."); - } - else - { - error.SetErrorString("Original breakpoint trap is no longer in memory."); - // Set verify to true and so we can check if the original opcode has already been restored - verify = true; - } + if (bp_addr == LLDB_INVALID_ADDRESS) { + error.SetErrorString("BreakpointSite contains an invalid load address."); + return error; + } + // Ask the lldb::Process subclass to fill in the correct software breakpoint + // trap for the breakpoint site + const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode(bp_site); + + if (bp_opcode_size == 0) { + error.SetErrorStringWithFormat("Process::GetSoftwareBreakpointTrapOpcode() " + "returned zero, unable to get breakpoint " + "trap for address 0x%" PRIx64, + bp_addr); + } else { + const uint8_t *const bp_opcode_bytes = bp_site->GetTrapOpcodeBytes(); + + if (bp_opcode_bytes == nullptr) { + error.SetErrorString( + "BreakpointSite doesn't contain a valid breakpoint trap opcode."); + return error; + } + + // Save the original opcode by reading it + if (DoReadMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), bp_opcode_size, + error) == bp_opcode_size) { + // Write a software breakpoint in place of the original opcode + if (DoWriteMemory(bp_addr, bp_opcode_bytes, bp_opcode_size, error) == + bp_opcode_size) { + uint8_t verify_bp_opcode_bytes[64]; + if (DoReadMemory(bp_addr, verify_bp_opcode_bytes, bp_opcode_size, + error) == bp_opcode_size) { + if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, + bp_opcode_size) == 0) { + bp_site->SetEnabled(true); + bp_site->SetType(BreakpointSite::eSoftware); + if (log) + log->Printf("Process::EnableSoftwareBreakpoint (site_id = %d) " + "addr = 0x%" PRIx64 " -- SUCCESS", + bp_site->GetID(), (uint64_t)bp_addr); + } else + error.SetErrorString( + "failed to verify the breakpoint trap in memory."); + } else + error.SetErrorString( + "Unable to read memory to verify breakpoint trap."); + } else + error.SetErrorString("Unable to write breakpoint trap to memory."); + } else + error.SetErrorString("Unable to read memory at breakpoint address."); + } + if (log && error.Fail()) + log->Printf( + "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 + " -- FAILED: %s", + bp_site->GetID(), (uint64_t)bp_addr, error.AsCString()); + return error; +} + +Error Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) { + Error error; + assert(bp_site != nullptr); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + addr_t bp_addr = bp_site->GetLoadAddress(); + lldb::user_id_t breakID = bp_site->GetID(); + if (log) + log->Printf("Process::DisableSoftwareBreakpoint (breakID = %" PRIu64 + ") addr = 0x%" PRIx64, + breakID, (uint64_t)bp_addr); + + if (bp_site->IsHardware()) { + error.SetErrorString("Breakpoint site is a hardware breakpoint."); + } else if (bp_site->IsEnabled()) { + const size_t break_op_size = bp_site->GetByteSize(); + const uint8_t *const break_op = bp_site->GetTrapOpcodeBytes(); + if (break_op_size > 0) { + // Clear a software breakpoint instruction + uint8_t curr_break_op[8]; + assert(break_op_size <= sizeof(curr_break_op)); + bool break_op_found = false; + + // Read the breakpoint opcode + if (DoReadMemory(bp_addr, curr_break_op, break_op_size, error) == + break_op_size) { + bool verify = false; + // Make sure the breakpoint opcode exists at this address + if (::memcmp(curr_break_op, break_op, break_op_size) == 0) { + break_op_found = true; + // We found a valid breakpoint opcode at this address, now restore + // the saved opcode. + if (DoWriteMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), + break_op_size, error) == break_op_size) { + verify = true; + } else + error.SetErrorString( + "Memory write failed when restoring original opcode."); + } else { + error.SetErrorString( + "Original breakpoint trap is no longer in memory."); + // Set verify to true and so we can check if the original opcode has + // already been restored + verify = true; + } - if (verify) - { - uint8_t verify_opcode[8]; - assert (break_op_size < sizeof(verify_opcode)); - // Verify that our original opcode made it back to the inferior - if (DoReadMemory (bp_addr, verify_opcode, break_op_size, error) == break_op_size) - { - // compare the memory we just read with the original opcode - if (::memcmp (bp_site->GetSavedOpcodeBytes(), verify_opcode, break_op_size) == 0) - { - // SUCCESS - bp_site->SetEnabled(false); - if (log) - log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- SUCCESS", bp_site->GetID(), (uint64_t)bp_addr); - return error; - } - else - { - if (break_op_found) - error.SetErrorString("Failed to restore original opcode."); - } - } - else - error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored."); - } + if (verify) { + uint8_t verify_opcode[8]; + assert(break_op_size < sizeof(verify_opcode)); + // Verify that our original opcode made it back to the inferior + if (DoReadMemory(bp_addr, verify_opcode, break_op_size, error) == + break_op_size) { + // compare the memory we just read with the original opcode + if (::memcmp(bp_site->GetSavedOpcodeBytes(), verify_opcode, + break_op_size) == 0) { + // SUCCESS + bp_site->SetEnabled(false); + if (log) + log->Printf("Process::DisableSoftwareBreakpoint (site_id = %d) " + "addr = 0x%" PRIx64 " -- SUCCESS", + bp_site->GetID(), (uint64_t)bp_addr); + return error; + } else { + if (break_op_found) + error.SetErrorString("Failed to restore original opcode."); } - else - error.SetErrorString("Unable to read memory that should contain the breakpoint trap."); + } else + error.SetErrorString("Failed to read memory to verify that " + "breakpoint trap was restored."); } + } else + error.SetErrorString( + "Unable to read memory that should contain the breakpoint trap."); } - else - { - if (log) - log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- already disabled", bp_site->GetID(), (uint64_t)bp_addr); - return error; - } - + } else { if (log) - log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- FAILED: %s", - bp_site->GetID(), - (uint64_t)bp_addr, - error.AsCString()); + log->Printf( + "Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 + " -- already disabled", + bp_site->GetID(), (uint64_t)bp_addr); return error; + } + + if (log) + log->Printf( + "Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 + " -- FAILED: %s", + bp_site->GetID(), (uint64_t)bp_addr, error.AsCString()); + return error; } // Uncomment to verify memory caching works after making changes to caching code //#define VERIFY_MEMORY_READS -size_t -Process::ReadMemory (addr_t addr, void *buf, size_t size, Error &error) -{ - error.Clear(); - if (!GetDisableMemoryCache()) - { -#if defined (VERIFY_MEMORY_READS) - // Memory caching is enabled, with debug verification - - if (buf && size) - { - // Uncomment the line below to make sure memory caching is working. - // I ran this through the test suite and got no assertions, so I am - // pretty confident this is working well. If any changes are made to - // memory caching, uncomment the line below and test your changes! - - // Verify all memory reads by using the cache first, then redundantly - // reading the same memory from the inferior and comparing to make sure - // everything is exactly the same. - std::string verify_buf (size, '\0'); - assert (verify_buf.size() == size); - const size_t cache_bytes_read = m_memory_cache.Read (this, addr, buf, size, error); - Error verify_error; - const size_t verify_bytes_read = ReadMemoryFromInferior (addr, const_cast<char *>(verify_buf.data()), verify_buf.size(), verify_error); - assert (cache_bytes_read == verify_bytes_read); - assert (memcmp(buf, verify_buf.data(), verify_buf.size()) == 0); - assert (verify_error.Success() == error.Success()); - return cache_bytes_read; - } - return 0; -#else // !defined(VERIFY_MEMORY_READS) - // Memory caching is enabled, without debug verification - - return m_memory_cache.Read (addr, buf, size, error); -#endif // defined (VERIFY_MEMORY_READS) - } - else - { - // Memory caching is disabled - - return ReadMemoryFromInferior (addr, buf, size, error); - } -} - -size_t -Process::ReadCStringFromMemory (addr_t addr, std::string &out_str, Error &error) -{ - char buf[256]; - out_str.clear(); - addr_t curr_addr = addr; - while (true) - { - size_t length = ReadCStringFromMemory (curr_addr, buf, sizeof(buf), error); - if (length == 0) - break; - out_str.append(buf, length); - // If we got "length - 1" bytes, we didn't get the whole C string, we - // need to read some more characters - if (length == sizeof(buf) - 1) - curr_addr += length; - else - break; +size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Error &error) { + error.Clear(); + if (!GetDisableMemoryCache()) { +#if defined(VERIFY_MEMORY_READS) + // Memory caching is enabled, with debug verification + + if (buf && size) { + // Uncomment the line below to make sure memory caching is working. + // I ran this through the test suite and got no assertions, so I am + // pretty confident this is working well. If any changes are made to + // memory caching, uncomment the line below and test your changes! + + // Verify all memory reads by using the cache first, then redundantly + // reading the same memory from the inferior and comparing to make sure + // everything is exactly the same. + std::string verify_buf(size, '\0'); + assert(verify_buf.size() == size); + const size_t cache_bytes_read = + m_memory_cache.Read(this, addr, buf, size, error); + Error verify_error; + const size_t verify_bytes_read = + ReadMemoryFromInferior(addr, const_cast<char *>(verify_buf.data()), + verify_buf.size(), verify_error); + assert(cache_bytes_read == verify_bytes_read); + assert(memcmp(buf, verify_buf.data(), verify_buf.size()) == 0); + assert(verify_error.Success() == error.Success()); + return cache_bytes_read; } - return out_str.size(); -} - -size_t -Process::ReadStringFromMemory (addr_t addr, char *dst, size_t max_bytes, Error &error, - size_t type_width) -{ - size_t total_bytes_read = 0; - if (dst && max_bytes && type_width && max_bytes >= type_width) - { - // Ensure a null terminator independent of the number of bytes that is read. - memset (dst, 0, max_bytes); - size_t bytes_left = max_bytes - type_width; - - const char terminator[4] = {'\0', '\0', '\0', '\0'}; - assert(sizeof(terminator) >= type_width && - "Attempting to validate a string with more than 4 bytes per character!"); - - addr_t curr_addr = addr; - const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); - char *curr_dst = dst; - - error.Clear(); - while (bytes_left > 0 && error.Success()) - { - addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size); - addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left); - size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error); - - if (bytes_read == 0) - break; - - // Search for a null terminator of correct size and alignment in bytes_read - size_t aligned_start = total_bytes_read - total_bytes_read % type_width; - for (size_t i = aligned_start; i + type_width <= total_bytes_read + bytes_read; i += type_width) - if (::memcmp(&dst[i], terminator, type_width) == 0) - { - error.Clear(); - return i; - } + return 0; +#else // !defined(VERIFY_MEMORY_READS) + // Memory caching is enabled, without debug verification - total_bytes_read += bytes_read; - curr_dst += bytes_read; - curr_addr += bytes_read; - bytes_left -= bytes_read; - } - } + return m_memory_cache.Read(addr, buf, size, error); +#endif // defined (VERIFY_MEMORY_READS) + } else { + // Memory caching is disabled + + return ReadMemoryFromInferior(addr, buf, size, error); + } +} + +size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str, + Error &error) { + char buf[256]; + out_str.clear(); + addr_t curr_addr = addr; + while (true) { + size_t length = ReadCStringFromMemory(curr_addr, buf, sizeof(buf), error); + if (length == 0) + break; + out_str.append(buf, length); + // If we got "length - 1" bytes, we didn't get the whole C string, we + // need to read some more characters + if (length == sizeof(buf) - 1) + curr_addr += length; else - { - if (max_bytes) - error.SetErrorString("invalid arguments"); - } - return total_bytes_read; + break; + } + return out_str.size(); } -// Deprecated in favor of ReadStringFromMemory which has wchar support and correct code to find -// null terminators. -size_t -Process::ReadCStringFromMemory (addr_t addr, char *dst, size_t dst_max_len, Error &result_error) -{ - size_t total_cstr_len = 0; - if (dst && dst_max_len) - { - result_error.Clear(); - // NULL out everything just to be safe - memset (dst, 0, dst_max_len); - Error error; - addr_t curr_addr = addr; - const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); - size_t bytes_left = dst_max_len - 1; - char *curr_dst = dst; - - while (bytes_left > 0) - { - addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size); - addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left); - size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error); - - if (bytes_read == 0) - { - result_error = error; - dst[total_cstr_len] = '\0'; - break; - } - const size_t len = strlen(curr_dst); +size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes, + Error &error, size_t type_width) { + size_t total_bytes_read = 0; + if (dst && max_bytes && type_width && max_bytes >= type_width) { + // Ensure a null terminator independent of the number of bytes that is read. + memset(dst, 0, max_bytes); + size_t bytes_left = max_bytes - type_width; - total_cstr_len += len; + const char terminator[4] = {'\0', '\0', '\0', '\0'}; + assert(sizeof(terminator) >= type_width && "Attempting to validate a " + "string with more than 4 bytes " + "per character!"); - if (len < bytes_to_read) - break; + addr_t curr_addr = addr; + const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); + char *curr_dst = dst; - curr_dst += bytes_read; - curr_addr += bytes_read; - bytes_left -= bytes_read; + error.Clear(); + while (bytes_left > 0 && error.Success()) { + addr_t cache_line_bytes_left = + cache_line_size - (curr_addr % cache_line_size); + addr_t bytes_to_read = + std::min<addr_t>(bytes_left, cache_line_bytes_left); + size_t bytes_read = ReadMemory(curr_addr, curr_dst, bytes_to_read, error); + + if (bytes_read == 0) + break; + + // Search for a null terminator of correct size and alignment in + // bytes_read + size_t aligned_start = total_bytes_read - total_bytes_read % type_width; + for (size_t i = aligned_start; + i + type_width <= total_bytes_read + bytes_read; i += type_width) + if (::memcmp(&dst[i], terminator, type_width) == 0) { + error.Clear(); + return i; } - } - else - { - if (dst == nullptr) - result_error.SetErrorString("invalid arguments"); - else - result_error.Clear(); - } - return total_cstr_len; -} -size_t -Process::ReadMemoryFromInferior (addr_t addr, void *buf, size_t size, Error &error) -{ - if (buf == nullptr || size == 0) - return 0; - - size_t bytes_read = 0; - uint8_t *bytes = (uint8_t *)buf; - - while (bytes_read < size) - { - const size_t curr_size = size - bytes_read; - const size_t curr_bytes_read = DoReadMemory (addr + bytes_read, - bytes + bytes_read, - curr_size, - error); - bytes_read += curr_bytes_read; - if (curr_bytes_read == curr_size || curr_bytes_read == 0) - break; + total_bytes_read += bytes_read; + curr_dst += bytes_read; + curr_addr += bytes_read; + bytes_left -= bytes_read; } - - // Replace any software breakpoint opcodes that fall into this range back - // into "buf" before we return - if (bytes_read > 0) - RemoveBreakpointOpcodesFromBuffer (addr, bytes_read, (uint8_t *)buf); - return bytes_read; -} - -uint64_t -Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr, size_t integer_byte_size, uint64_t fail_value, - Error &error) -{ - Scalar scalar; - if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar, error)) - return scalar.ULongLong(fail_value); - return fail_value; + } else { + if (max_bytes) + error.SetErrorString("invalid arguments"); + } + return total_bytes_read; } -int64_t -Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr, size_t integer_byte_size, int64_t fail_value, Error &error) -{ - Scalar scalar; - if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, true, scalar, error)) - return scalar.SLongLong(fail_value); - return fail_value; -} - -addr_t -Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error) -{ - Scalar scalar; - if (ReadScalarIntegerFromMemory(vm_addr, GetAddressByteSize(), false, scalar, error)) - return scalar.ULongLong(LLDB_INVALID_ADDRESS); - return LLDB_INVALID_ADDRESS; -} - -bool -Process::WritePointerToMemory (lldb::addr_t vm_addr, - lldb::addr_t ptr_value, - Error &error) -{ - Scalar scalar; - const uint32_t addr_byte_size = GetAddressByteSize(); - if (addr_byte_size <= 4) - scalar = (uint32_t)ptr_value; +// Deprecated in favor of ReadStringFromMemory which has wchar support and +// correct code to find +// null terminators. +size_t Process::ReadCStringFromMemory(addr_t addr, char *dst, + size_t dst_max_len, Error &result_error) { + size_t total_cstr_len = 0; + if (dst && dst_max_len) { + result_error.Clear(); + // NULL out everything just to be safe + memset(dst, 0, dst_max_len); + Error error; + addr_t curr_addr = addr; + const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize(); + size_t bytes_left = dst_max_len - 1; + char *curr_dst = dst; + + while (bytes_left > 0) { + addr_t cache_line_bytes_left = + cache_line_size - (curr_addr % cache_line_size); + addr_t bytes_to_read = + std::min<addr_t>(bytes_left, cache_line_bytes_left); + size_t bytes_read = ReadMemory(curr_addr, curr_dst, bytes_to_read, error); + + if (bytes_read == 0) { + result_error = error; + dst[total_cstr_len] = '\0'; + break; + } + const size_t len = strlen(curr_dst); + + total_cstr_len += len; + + if (len < bytes_to_read) + break; + + curr_dst += bytes_read; + curr_addr += bytes_read; + bytes_left -= bytes_read; + } + } else { + if (dst == nullptr) + result_error.SetErrorString("invalid arguments"); else - scalar = ptr_value; - return WriteScalarToMemory(vm_addr, scalar, addr_byte_size, error) == addr_byte_size; + result_error.Clear(); + } + return total_cstr_len; } -size_t -Process::WriteMemoryPrivate (addr_t addr, const void *buf, size_t size, Error &error) -{ - size_t bytes_written = 0; - const uint8_t *bytes = (const uint8_t *)buf; - - while (bytes_written < size) - { - const size_t curr_size = size - bytes_written; - const size_t curr_bytes_written = DoWriteMemory (addr + bytes_written, - bytes + bytes_written, - curr_size, - error); - bytes_written += curr_bytes_written; - if (curr_bytes_written == curr_size || curr_bytes_written == 0) - break; - } - return bytes_written; -} +size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size, + Error &error) { + if (buf == nullptr || size == 0) + return 0; -size_t -Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error) -{ -#if defined (ENABLE_MEMORY_CACHING) - m_memory_cache.Flush (addr, size); + size_t bytes_read = 0; + uint8_t *bytes = (uint8_t *)buf; + + while (bytes_read < size) { + const size_t curr_size = size - bytes_read; + const size_t curr_bytes_read = + DoReadMemory(addr + bytes_read, bytes + bytes_read, curr_size, error); + bytes_read += curr_bytes_read; + if (curr_bytes_read == curr_size || curr_bytes_read == 0) + break; + } + + // Replace any software breakpoint opcodes that fall into this range back + // into "buf" before we return + if (bytes_read > 0) + RemoveBreakpointOpcodesFromBuffer(addr, bytes_read, (uint8_t *)buf); + return bytes_read; +} + +uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr, + size_t integer_byte_size, + uint64_t fail_value, + Error &error) { + Scalar scalar; + if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar, + error)) + return scalar.ULongLong(fail_value); + return fail_value; +} + +int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr, + size_t integer_byte_size, + int64_t fail_value, Error &error) { + Scalar scalar; + if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, true, scalar, + error)) + return scalar.SLongLong(fail_value); + return fail_value; +} + +addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Error &error) { + Scalar scalar; + if (ReadScalarIntegerFromMemory(vm_addr, GetAddressByteSize(), false, scalar, + error)) + return scalar.ULongLong(LLDB_INVALID_ADDRESS); + return LLDB_INVALID_ADDRESS; +} + +bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value, + Error &error) { + Scalar scalar; + const uint32_t addr_byte_size = GetAddressByteSize(); + if (addr_byte_size <= 4) + scalar = (uint32_t)ptr_value; + else + scalar = ptr_value; + return WriteScalarToMemory(vm_addr, scalar, addr_byte_size, error) == + addr_byte_size; +} + +size_t Process::WriteMemoryPrivate(addr_t addr, const void *buf, size_t size, + Error &error) { + size_t bytes_written = 0; + const uint8_t *bytes = (const uint8_t *)buf; + + while (bytes_written < size) { + const size_t curr_size = size - bytes_written; + const size_t curr_bytes_written = DoWriteMemory( + addr + bytes_written, bytes + bytes_written, curr_size, error); + bytes_written += curr_bytes_written; + if (curr_bytes_written == curr_size || curr_bytes_written == 0) + break; + } + return bytes_written; +} + +size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size, + Error &error) { +#if defined(ENABLE_MEMORY_CACHING) + m_memory_cache.Flush(addr, size); #endif - if (buf == nullptr || size == 0) - return 0; - - m_mod_id.BumpMemoryID(); - - // We need to write any data that would go where any current software traps - // (enabled software breakpoints) any software traps (breakpoints) that we - // may have placed in our tasks memory. - - BreakpointSiteList bp_sites_in_range; - - if (m_breakpoint_site_list.FindInRange (addr, addr + size, bp_sites_in_range)) - { - // No breakpoint sites overlap - if (bp_sites_in_range.IsEmpty()) - return WriteMemoryPrivate (addr, buf, size, error); - else - { - const uint8_t *ubuf = (const uint8_t *)buf; - uint64_t bytes_written = 0; - - bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf, &error](BreakpointSite *bp) -> void { - - if (error.Success()) - { - addr_t intersect_addr; - size_t intersect_size; - size_t opcode_offset; - const bool intersects = bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset); - UNUSED_IF_ASSERT_DISABLED(intersects); - assert(intersects); - assert(addr <= intersect_addr && intersect_addr < addr + size); - assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size); - assert(opcode_offset + intersect_size <= bp->GetByteSize()); - - // Check for bytes before this breakpoint - const addr_t curr_addr = addr + bytes_written; - if (intersect_addr > curr_addr) - { - // There are some bytes before this breakpoint that we need to - // just write to memory - size_t curr_size = intersect_addr - curr_addr; - size_t curr_bytes_written = WriteMemoryPrivate (curr_addr, - ubuf + bytes_written, - curr_size, - error); - bytes_written += curr_bytes_written; - if (curr_bytes_written != curr_size) - { - // We weren't able to write all of the requested bytes, we - // are done looping and will return the number of bytes that - // we have written so far. - if (error.Success()) - error.SetErrorToGenericError(); - } - } - // Now write any bytes that would cover up any software breakpoints - // directly into the breakpoint opcode buffer - ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size); - bytes_written += intersect_size; - } - }); - - if (bytes_written < size) - WriteMemoryPrivate (addr + bytes_written, - ubuf + bytes_written, - size - bytes_written, - error); - } - } - else - { - return WriteMemoryPrivate (addr, buf, size, error); - } - - // Write any remaining bytes after the last breakpoint if we have any left - return 0; //bytes_written; -} - -size_t -Process::WriteScalarToMemory (addr_t addr, const Scalar &scalar, size_t byte_size, Error &error) -{ - if (byte_size == UINT32_MAX) - byte_size = scalar.GetByteSize(); - if (byte_size > 0) - { - uint8_t buf[32]; - const size_t mem_size = scalar.GetAsMemoryData (buf, byte_size, GetByteOrder(), error); - if (mem_size > 0) - return WriteMemory(addr, buf, mem_size, error); - else - error.SetErrorString ("failed to get scalar as memory data"); - } - else - { - error.SetErrorString ("invalid scalar value"); - } + if (buf == nullptr || size == 0) return 0; -} -size_t -Process::ReadScalarIntegerFromMemory (addr_t addr, - uint32_t byte_size, - bool is_signed, - Scalar &scalar, - Error &error) -{ - uint64_t uval = 0; - if (byte_size == 0) - { - error.SetErrorString ("byte size is zero"); - } - else if (byte_size & (byte_size - 1)) - { - error.SetErrorStringWithFormat ("byte size %u is not a power of 2", byte_size); - } - else if (byte_size <= sizeof(uval)) - { - const size_t bytes_read = ReadMemory (addr, &uval, byte_size, error); - if (bytes_read == byte_size) - { - DataExtractor data (&uval, sizeof(uval), GetByteOrder(), GetAddressByteSize()); - lldb::offset_t offset = 0; - if (byte_size <= 4) - scalar = data.GetMaxU32 (&offset, byte_size); - else - scalar = data.GetMaxU64 (&offset, byte_size); - if (is_signed) - scalar.SignExtend(byte_size * 8); - return bytes_read; + m_mod_id.BumpMemoryID(); + + // We need to write any data that would go where any current software traps + // (enabled software breakpoints) any software traps (breakpoints) that we + // may have placed in our tasks memory. + + BreakpointSiteList bp_sites_in_range; + + if (m_breakpoint_site_list.FindInRange(addr, addr + size, + bp_sites_in_range)) { + // No breakpoint sites overlap + if (bp_sites_in_range.IsEmpty()) + return WriteMemoryPrivate(addr, buf, size, error); + else { + const uint8_t *ubuf = (const uint8_t *)buf; + uint64_t bytes_written = 0; + + bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf, + &error](BreakpointSite *bp) -> void { + + if (error.Success()) { + addr_t intersect_addr; + size_t intersect_size; + size_t opcode_offset; + const bool intersects = bp->IntersectsRange( + addr, size, &intersect_addr, &intersect_size, &opcode_offset); + UNUSED_IF_ASSERT_DISABLED(intersects); + assert(intersects); + assert(addr <= intersect_addr && intersect_addr < addr + size); + assert(addr < intersect_addr + intersect_size && + intersect_addr + intersect_size <= addr + size); + assert(opcode_offset + intersect_size <= bp->GetByteSize()); + + // Check for bytes before this breakpoint + const addr_t curr_addr = addr + bytes_written; + if (intersect_addr > curr_addr) { + // There are some bytes before this breakpoint that we need to + // just write to memory + size_t curr_size = intersect_addr - curr_addr; + size_t curr_bytes_written = WriteMemoryPrivate( + curr_addr, ubuf + bytes_written, curr_size, error); + bytes_written += curr_bytes_written; + if (curr_bytes_written != curr_size) { + // We weren't able to write all of the requested bytes, we + // are done looping and will return the number of bytes that + // we have written so far. + if (error.Success()) + error.SetErrorToGenericError(); + } + } + // Now write any bytes that would cover up any software breakpoints + // directly into the breakpoint opcode buffer + ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, + ubuf + bytes_written, intersect_size); + bytes_written += intersect_size; } - } + }); + + if (bytes_written < size) + WriteMemoryPrivate(addr + bytes_written, ubuf + bytes_written, + size - bytes_written, error); + } + } else { + return WriteMemoryPrivate(addr, buf, size, error); + } + + // Write any remaining bytes after the last breakpoint if we have any left + return 0; // bytes_written; +} + +size_t Process::WriteScalarToMemory(addr_t addr, const Scalar &scalar, + size_t byte_size, Error &error) { + if (byte_size == UINT32_MAX) + byte_size = scalar.GetByteSize(); + if (byte_size > 0) { + uint8_t buf[32]; + const size_t mem_size = + scalar.GetAsMemoryData(buf, byte_size, GetByteOrder(), error); + if (mem_size > 0) + return WriteMemory(addr, buf, mem_size, error); else - { - error.SetErrorStringWithFormat ("byte size of %u is too large for integer scalar type", byte_size); - } - return 0; + error.SetErrorString("failed to get scalar as memory data"); + } else { + error.SetErrorString("invalid scalar value"); + } + return 0; +} + +size_t Process::ReadScalarIntegerFromMemory(addr_t addr, uint32_t byte_size, + bool is_signed, Scalar &scalar, + Error &error) { + uint64_t uval = 0; + if (byte_size == 0) { + error.SetErrorString("byte size is zero"); + } else if (byte_size & (byte_size - 1)) { + error.SetErrorStringWithFormat("byte size %u is not a power of 2", + byte_size); + } else if (byte_size <= sizeof(uval)) { + const size_t bytes_read = ReadMemory(addr, &uval, byte_size, error); + if (bytes_read == byte_size) { + DataExtractor data(&uval, sizeof(uval), GetByteOrder(), + GetAddressByteSize()); + lldb::offset_t offset = 0; + if (byte_size <= 4) + scalar = data.GetMaxU32(&offset, byte_size); + else + scalar = data.GetMaxU64(&offset, byte_size); + if (is_signed) + scalar.SignExtend(byte_size * 8); + return bytes_read; + } + } else { + error.SetErrorStringWithFormat( + "byte size of %u is too large for integer scalar type", byte_size); + } + return 0; } #define USE_ALLOCATE_MEMORY_CACHE 1 -addr_t -Process::AllocateMemory(size_t size, uint32_t permissions, Error &error) -{ - if (GetPrivateState() != eStateStopped) - return LLDB_INVALID_ADDRESS; - -#if defined (USE_ALLOCATE_MEMORY_CACHE) - return m_allocated_memory_cache.AllocateMemory(size, permissions, error); +addr_t Process::AllocateMemory(size_t size, uint32_t permissions, + Error &error) { + if (GetPrivateState() != eStateStopped) + return LLDB_INVALID_ADDRESS; + +#if defined(USE_ALLOCATE_MEMORY_CACHE) + return m_allocated_memory_cache.AllocateMemory(size, permissions, error); #else - addr_t allocated_addr = DoAllocateMemory (size, permissions, error); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::AllocateMemory(size=%" PRIu64 ", permissions=%s) => 0x%16.16" PRIx64 " (m_stop_id = %u m_memory_id = %u)", - (uint64_t)size, - GetPermissionsAsCString (permissions), - (uint64_t)allocated_addr, - m_mod_id.GetStopID(), - m_mod_id.GetMemoryID()); - return allocated_addr; + addr_t allocated_addr = DoAllocateMemory(size, permissions, error); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::AllocateMemory(size=%" PRIu64 + ", permissions=%s) => 0x%16.16" PRIx64 + " (m_stop_id = %u m_memory_id = %u)", + (uint64_t)size, GetPermissionsAsCString(permissions), + (uint64_t)allocated_addr, m_mod_id.GetStopID(), + m_mod_id.GetMemoryID()); + return allocated_addr; #endif } -addr_t -Process::CallocateMemory(size_t size, uint32_t permissions, Error &error) -{ - addr_t return_addr = AllocateMemory(size, permissions, error); - if (error.Success()) - { - std::string buffer(size, 0); - WriteMemory(return_addr, buffer.c_str(), size, error); - } - return return_addr; +addr_t Process::CallocateMemory(size_t size, uint32_t permissions, + Error &error) { + addr_t return_addr = AllocateMemory(size, permissions, error); + if (error.Success()) { + std::string buffer(size, 0); + WriteMemory(return_addr, buffer.c_str(), size, error); + } + return return_addr; } -bool -Process::CanJIT () -{ - if (m_can_jit == eCanJITDontKnow) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - Error err; - - uint64_t allocated_memory = AllocateMemory(8, - ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable, - err); - - if (err.Success()) - { - m_can_jit = eCanJITYes; - if (log) - log->Printf ("Process::%s pid %" PRIu64 " allocation test passed, CanJIT () is true", __FUNCTION__, GetID ()); - } - else - { - m_can_jit = eCanJITNo; - if (log) - log->Printf ("Process::%s pid %" PRIu64 " allocation test failed, CanJIT () is false: %s", __FUNCTION__, GetID (), err.AsCString ()); - } - - DeallocateMemory (allocated_memory); +bool Process::CanJIT() { + if (m_can_jit == eCanJITDontKnow) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + Error err; + + uint64_t allocated_memory = AllocateMemory( + 8, ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable, + err); + + if (err.Success()) { + m_can_jit = eCanJITYes; + if (log) + log->Printf("Process::%s pid %" PRIu64 + " allocation test passed, CanJIT () is true", + __FUNCTION__, GetID()); + } else { + m_can_jit = eCanJITNo; + if (log) + log->Printf("Process::%s pid %" PRIu64 + " allocation test failed, CanJIT () is false: %s", + __FUNCTION__, GetID(), err.AsCString()); } - - return m_can_jit == eCanJITYes; -} -void -Process::SetCanJIT (bool can_jit) -{ - m_can_jit = (can_jit ? eCanJITYes : eCanJITNo); -} + DeallocateMemory(allocated_memory); + } -void -Process::SetCanRunCode (bool can_run_code) -{ - SetCanJIT(can_run_code); - m_can_interpret_function_calls = can_run_code; + return m_can_jit == eCanJITYes; } -Error -Process::DeallocateMemory (addr_t ptr) -{ - Error error; -#if defined (USE_ALLOCATE_MEMORY_CACHE) - if (!m_allocated_memory_cache.DeallocateMemory(ptr)) - { - error.SetErrorStringWithFormat ("deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr); - } -#else - error = DoDeallocateMemory (ptr); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::DeallocateMemory(addr=0x%16.16" PRIx64 ") => err = %s (m_stop_id = %u, m_memory_id = %u)", - ptr, - error.AsCString("SUCCESS"), - m_mod_id.GetStopID(), - m_mod_id.GetMemoryID()); -#endif - return error; +void Process::SetCanJIT(bool can_jit) { + m_can_jit = (can_jit ? eCanJITYes : eCanJITNo); } -ModuleSP -Process::ReadModuleFromMemory (const FileSpec& file_spec, - lldb::addr_t header_addr, - size_t size_to_read) -{ - Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); - if (log) - { - log->Printf ("Process::ReadModuleFromMemory reading %s binary from memory", file_spec.GetPath().c_str()); - } - ModuleSP module_sp (new Module (file_spec, ArchSpec())); - if (module_sp) - { - Error error; - ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error, size_to_read); - if (objfile) - return module_sp; - } - return ModuleSP(); +void Process::SetCanRunCode(bool can_run_code) { + SetCanJIT(can_run_code); + m_can_interpret_function_calls = can_run_code; } -bool -Process::GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions) -{ - MemoryRegionInfo range_info; - permissions = 0; - Error error (GetMemoryRegionInfo (load_addr, range_info)); - if (!error.Success()) - return false; - if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow - || range_info.GetWritable() == MemoryRegionInfo::eDontKnow - || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow) - { - return false; - } +Error Process::DeallocateMemory(addr_t ptr) { + Error error; +#if defined(USE_ALLOCATE_MEMORY_CACHE) + if (!m_allocated_memory_cache.DeallocateMemory(ptr)) { + error.SetErrorStringWithFormat( + "deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr); + } +#else + error = DoDeallocateMemory(ptr); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::DeallocateMemory(addr=0x%16.16" PRIx64 + ") => err = %s (m_stop_id = %u, m_memory_id = %u)", + ptr, error.AsCString("SUCCESS"), m_mod_id.GetStopID(), + m_mod_id.GetMemoryID()); +#endif + return error; +} + +ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec, + lldb::addr_t header_addr, + size_t size_to_read) { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST); + if (log) { + log->Printf("Process::ReadModuleFromMemory reading %s binary from memory", + file_spec.GetPath().c_str()); + } + ModuleSP module_sp(new Module(file_spec, ArchSpec())); + if (module_sp) { + Error error; + ObjectFile *objfile = module_sp->GetMemoryObjectFile( + shared_from_this(), header_addr, error, size_to_read); + if (objfile) + return module_sp; + } + return ModuleSP(); +} + +bool Process::GetLoadAddressPermissions(lldb::addr_t load_addr, + uint32_t &permissions) { + MemoryRegionInfo range_info; + permissions = 0; + Error error(GetMemoryRegionInfo(load_addr, range_info)); + if (!error.Success()) + return false; + if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow || + range_info.GetWritable() == MemoryRegionInfo::eDontKnow || + range_info.GetExecutable() == MemoryRegionInfo::eDontKnow) { + return false; + } - if (range_info.GetReadable() == MemoryRegionInfo::eYes) - permissions |= lldb::ePermissionsReadable; + if (range_info.GetReadable() == MemoryRegionInfo::eYes) + permissions |= lldb::ePermissionsReadable; - if (range_info.GetWritable() == MemoryRegionInfo::eYes) - permissions |= lldb::ePermissionsWritable; + if (range_info.GetWritable() == MemoryRegionInfo::eYes) + permissions |= lldb::ePermissionsWritable; - if (range_info.GetExecutable() == MemoryRegionInfo::eYes) - permissions |= lldb::ePermissionsExecutable; + if (range_info.GetExecutable() == MemoryRegionInfo::eYes) + permissions |= lldb::ePermissionsExecutable; - return true; + return true; } -Error -Process::EnableWatchpoint (Watchpoint *watchpoint, bool notify) -{ - Error error; - error.SetErrorString("watchpoints are not supported"); - return error; +Error Process::EnableWatchpoint(Watchpoint *watchpoint, bool notify) { + Error error; + error.SetErrorString("watchpoints are not supported"); + return error; } -Error -Process::DisableWatchpoint (Watchpoint *watchpoint, bool notify) -{ - Error error; - error.SetErrorString("watchpoints are not supported"); - return error; +Error Process::DisableWatchpoint(Watchpoint *watchpoint, bool notify) { + Error error; + error.SetErrorString("watchpoints are not supported"); + return error; } StateType -Process::WaitForProcessStopPrivate(const std::chrono::microseconds &timeout, EventSP &event_sp) -{ - StateType state; - // Now wait for the process to launch and return control to us, and then - // call DidLaunch: - while (true) - { - event_sp.reset(); - state = WaitForStateChangedEventsPrivate (timeout, event_sp); - - if (StateIsStoppedState(state, false)) - break; +Process::WaitForProcessStopPrivate(const std::chrono::microseconds &timeout, + EventSP &event_sp) { + StateType state; + // Now wait for the process to launch and return control to us, and then + // call DidLaunch: + while (true) { + event_sp.reset(); + state = WaitForStateChangedEventsPrivate(timeout, event_sp); - // If state is invalid, then we timed out - if (state == eStateInvalid) - break; + if (StateIsStoppedState(state, false)) + break; - if (event_sp) - HandlePrivateEvent (event_sp); - } - return state; + // If state is invalid, then we timed out + if (state == eStateInvalid) + break; + + if (event_sp) + HandlePrivateEvent(event_sp); + } + return state; } -void -Process::LoadOperatingSystemPlugin(bool flush) -{ - if (flush) - m_thread_list.Clear(); - m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); - if (flush) - Flush(); +void Process::LoadOperatingSystemPlugin(bool flush) { + if (flush) + m_thread_list.Clear(); + m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); + if (flush) + Flush(); } -Error -Process::Launch (ProcessLaunchInfo &launch_info) -{ - Error error; - m_abi_sp.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); - m_system_runtime_ap.reset(); - m_os_ap.reset(); - m_process_input_reader.reset(); - m_stop_info_override_callback = nullptr; - - Module *exe_module = GetTarget().GetExecutableModulePointer(); - if (exe_module) - { - char local_exec_file_path[PATH_MAX]; - char platform_exec_file_path[PATH_MAX]; - exe_module->GetFileSpec().GetPath(local_exec_file_path, sizeof(local_exec_file_path)); - exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, sizeof(platform_exec_file_path)); - if (exe_module->GetFileSpec().Exists()) - { - // Install anything that might need to be installed prior to launching. - // For host systems, this will do nothing, but if we are connected to a - // remote platform it will install any needed binaries - error = GetTarget().Install(&launch_info); - if (error.Fail()) - return error; - - if (PrivateStateThreadIsValid ()) - PausePrivateStateThread (); - - error = WillLaunch (exe_module); - if (error.Success()) - { - const bool restarted = false; - SetPublicState (eStateLaunching, restarted); - m_should_detach = false; - - if (m_public_run_lock.TrySetRunning()) - { - // Now launch using these arguments. - error = DoLaunch (exe_module, launch_info); - } - else - { - // This shouldn't happen - error.SetErrorString("failed to acquire process run lock"); - } +Error Process::Launch(ProcessLaunchInfo &launch_info) { + Error error; + m_abi_sp.reset(); + m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); + m_system_runtime_ap.reset(); + m_os_ap.reset(); + m_process_input_reader.reset(); + m_stop_info_override_callback = nullptr; + + Module *exe_module = GetTarget().GetExecutableModulePointer(); + if (exe_module) { + char local_exec_file_path[PATH_MAX]; + char platform_exec_file_path[PATH_MAX]; + exe_module->GetFileSpec().GetPath(local_exec_file_path, + sizeof(local_exec_file_path)); + exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, + sizeof(platform_exec_file_path)); + if (exe_module->GetFileSpec().Exists()) { + // Install anything that might need to be installed prior to launching. + // For host systems, this will do nothing, but if we are connected to a + // remote platform it will install any needed binaries + error = GetTarget().Install(&launch_info); + if (error.Fail()) + return error; - if (error.Fail()) - { - if (GetID() != LLDB_INVALID_PROCESS_ID) - { - SetID (LLDB_INVALID_PROCESS_ID); - const char *error_string = error.AsCString(); - if (error_string == nullptr) - error_string = "launch failed"; - SetExitStatus (-1, error_string); - } - } - else - { - EventSP event_sp; - StateType state = WaitForProcessStopPrivate(std::chrono::seconds(10), event_sp); - - if (state == eStateInvalid || !event_sp) - { - // We were able to launch the process, but we failed to - // catch the initial stop. - error.SetErrorString ("failed to catch stop after launch"); - SetExitStatus (0, "failed to catch stop after launch"); - Destroy(false); - } - else if (state == eStateStopped || state == eStateCrashed) - { - DidLaunch (); + if (PrivateStateThreadIsValid()) + PausePrivateStateThread(); - DynamicLoader *dyld = GetDynamicLoader (); - if (dyld) - dyld->DidLaunch(); + error = WillLaunch(exe_module); + if (error.Success()) { + const bool restarted = false; + SetPublicState(eStateLaunching, restarted); + m_should_detach = false; - GetJITLoaders().DidLaunch(); + if (m_public_run_lock.TrySetRunning()) { + // Now launch using these arguments. + error = DoLaunch(exe_module, launch_info); + } else { + // This shouldn't happen + error.SetErrorString("failed to acquire process run lock"); + } - SystemRuntime *system_runtime = GetSystemRuntime (); - if (system_runtime) - system_runtime->DidLaunch(); + if (error.Fail()) { + if (GetID() != LLDB_INVALID_PROCESS_ID) { + SetID(LLDB_INVALID_PROCESS_ID); + const char *error_string = error.AsCString(); + if (error_string == nullptr) + error_string = "launch failed"; + SetExitStatus(-1, error_string); + } + } else { + EventSP event_sp; + StateType state = + WaitForProcessStopPrivate(std::chrono::seconds(10), event_sp); + + if (state == eStateInvalid || !event_sp) { + // We were able to launch the process, but we failed to + // catch the initial stop. + error.SetErrorString("failed to catch stop after launch"); + SetExitStatus(0, "failed to catch stop after launch"); + Destroy(false); + } else if (state == eStateStopped || state == eStateCrashed) { + DidLaunch(); - LoadOperatingSystemPlugin(false); + DynamicLoader *dyld = GetDynamicLoader(); + if (dyld) + dyld->DidLaunch(); - // Note, the stop event was consumed above, but not handled. This was done - // to give DidLaunch a chance to run. The target is either stopped or crashed. - // Directly set the state. This is done to prevent a stop message with a bunch - // of spurious output on thread status, as well as not pop a ProcessIOHandler. - SetPublicState(state, false); + GetJITLoaders().DidLaunch(); - if (PrivateStateThreadIsValid ()) - ResumePrivateStateThread (); - else - StartPrivateStateThread (); + SystemRuntime *system_runtime = GetSystemRuntime(); + if (system_runtime) + system_runtime->DidLaunch(); - m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback(); + LoadOperatingSystemPlugin(false); - // Target was stopped at entry as was intended. Need to notify the listeners - // about it. - if (state == eStateStopped && launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - HandlePrivateEvent(event_sp); - } - else if (state == eStateExited) - { - // We exited while trying to launch somehow. Don't call DidLaunch as that's - // not likely to work, and return an invalid pid. - HandlePrivateEvent (event_sp); - } - } - } - } - else - { - error.SetErrorStringWithFormat("file doesn't exist: '%s'", local_exec_file_path); + // Note, the stop event was consumed above, but not handled. This + // was done + // to give DidLaunch a chance to run. The target is either stopped + // or crashed. + // Directly set the state. This is done to prevent a stop message + // with a bunch + // of spurious output on thread status, as well as not pop a + // ProcessIOHandler. + SetPublicState(state, false); + + if (PrivateStateThreadIsValid()) + ResumePrivateStateThread(); + else + StartPrivateStateThread(); + + m_stop_info_override_callback = + GetTarget().GetArchitecture().GetStopInfoOverrideCallback(); + + // Target was stopped at entry as was intended. Need to notify the + // listeners + // about it. + if (state == eStateStopped && + launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) + HandlePrivateEvent(event_sp); + } else if (state == eStateExited) { + // We exited while trying to launch somehow. Don't call DidLaunch + // as that's + // not likely to work, and return an invalid pid. + HandlePrivateEvent(event_sp); + } } + } + } else { + error.SetErrorStringWithFormat("file doesn't exist: '%s'", + local_exec_file_path); } - return error; + } + return error; } -Error -Process::LoadCore () -{ - Error error = DoLoadCore(); - if (error.Success()) - { - ListenerSP listener_sp (Listener::MakeListener("lldb.process.load_core_listener")); - HijackProcessEvents(listener_sp); +Error Process::LoadCore() { + Error error = DoLoadCore(); + if (error.Success()) { + ListenerSP listener_sp( + Listener::MakeListener("lldb.process.load_core_listener")); + HijackProcessEvents(listener_sp); - if (PrivateStateThreadIsValid ()) - ResumePrivateStateThread (); - else - StartPrivateStateThread (); - - DynamicLoader *dyld = GetDynamicLoader (); - if (dyld) - dyld->DidAttach(); - - GetJITLoaders().DidAttach(); - - SystemRuntime *system_runtime = GetSystemRuntime (); - if (system_runtime) - system_runtime->DidAttach(); - - m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); - // We successfully loaded a core file, now pretend we stopped so we can - // show all of the threads in the core file and explore the crashed - // state. - SetPrivateState (eStateStopped); - - // Wait indefinitely for a stopped event since we just posted one above... - lldb::EventSP event_sp; - listener_sp->WaitForEvent(std::chrono::microseconds(0), event_sp); - StateType state = ProcessEventData::GetStateFromEvent(event_sp.get()); - - if (!StateIsStoppedState (state, false)) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::Halt() failed to stop, state is: %s", StateAsCString(state)); - error.SetErrorString ("Did not get stopped event after loading the core file."); - } - RestoreProcessEvents (); + if (PrivateStateThreadIsValid()) + ResumePrivateStateThread(); + else + StartPrivateStateThread(); + + DynamicLoader *dyld = GetDynamicLoader(); + if (dyld) + dyld->DidAttach(); + + GetJITLoaders().DidAttach(); + + SystemRuntime *system_runtime = GetSystemRuntime(); + if (system_runtime) + system_runtime->DidAttach(); + + m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); + // We successfully loaded a core file, now pretend we stopped so we can + // show all of the threads in the core file and explore the crashed + // state. + SetPrivateState(eStateStopped); + + // Wait indefinitely for a stopped event since we just posted one above... + lldb::EventSP event_sp; + listener_sp->WaitForEvent(std::chrono::microseconds(0), event_sp); + StateType state = ProcessEventData::GetStateFromEvent(event_sp.get()); + + if (!StateIsStoppedState(state, false)) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::Halt() failed to stop, state is: %s", + StateAsCString(state)); + error.SetErrorString( + "Did not get stopped event after loading the core file."); } - return error; + RestoreProcessEvents(); + } + return error; } -DynamicLoader * -Process::GetDynamicLoader () -{ - if (!m_dyld_ap) - m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr)); - return m_dyld_ap.get(); +DynamicLoader *Process::GetDynamicLoader() { + if (!m_dyld_ap) + m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr)); + return m_dyld_ap.get(); } -const lldb::DataBufferSP -Process::GetAuxvData() -{ - return DataBufferSP (); -} +const lldb::DataBufferSP Process::GetAuxvData() { return DataBufferSP(); } -JITLoaderList & -Process::GetJITLoaders () -{ - if (!m_jit_loaders_ap) - { - m_jit_loaders_ap.reset(new JITLoaderList()); - JITLoader::LoadPlugins(this, *m_jit_loaders_ap); - } - return *m_jit_loaders_ap; +JITLoaderList &Process::GetJITLoaders() { + if (!m_jit_loaders_ap) { + m_jit_loaders_ap.reset(new JITLoaderList()); + JITLoader::LoadPlugins(this, *m_jit_loaders_ap); + } + return *m_jit_loaders_ap; } -SystemRuntime * -Process::GetSystemRuntime () -{ - if (!m_system_runtime_ap) - m_system_runtime_ap.reset(SystemRuntime::FindPlugin(this)); - return m_system_runtime_ap.get(); +SystemRuntime *Process::GetSystemRuntime() { + if (!m_system_runtime_ap) + m_system_runtime_ap.reset(SystemRuntime::FindPlugin(this)); + return m_system_runtime_ap.get(); } -Process::AttachCompletionHandler::AttachCompletionHandler (Process *process, uint32_t exec_count) : - NextEventAction (process), - m_exec_count (exec_count) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32, __FUNCTION__, static_cast<void*>(process), exec_count); +Process::AttachCompletionHandler::AttachCompletionHandler(Process *process, + uint32_t exec_count) + : NextEventAction(process), m_exec_count(exec_count) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32, + __FUNCTION__, static_cast<void *>(process), exec_count); } Process::NextEventAction::EventActionResult -Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - - StateType state = ProcessEventData::GetStateFromEvent (event_sp.get()); - if (log) - log->Printf ("Process::AttachCompletionHandler::%s called with state %s (%d)", __FUNCTION__, StateAsCString(state), static_cast<int> (state)); - - switch (state) - { - case eStateAttaching: - return eEventActionSuccess; - - case eStateRunning: - case eStateConnected: - return eEventActionRetry; - - case eStateStopped: - case eStateCrashed: - // During attach, prior to sending the eStateStopped event, - // lldb_private::Process subclasses must set the new process ID. - assert (m_process->GetID() != LLDB_INVALID_PROCESS_ID); - // We don't want these events to be reported, so go set the ShouldReportStop here: - m_process->GetThreadList().SetShouldReportStop (eVoteNo); - - if (m_exec_count > 0) - { - --m_exec_count; - - if (log) - log->Printf ("Process::AttachCompletionHandler::%s state %s: reduced remaining exec count to %" PRIu32 ", requesting resume", __FUNCTION__, StateAsCString(state), m_exec_count); +Process::AttachCompletionHandler::PerformAction(lldb::EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - RequestResume(); - return eEventActionRetry; - } - else - { - if (log) - log->Printf ("Process::AttachCompletionHandler::%s state %s: no more execs expected to start, continuing with attach", __FUNCTION__, StateAsCString(state)); + StateType state = ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) + log->Printf( + "Process::AttachCompletionHandler::%s called with state %s (%d)", + __FUNCTION__, StateAsCString(state), static_cast<int>(state)); - m_process->CompleteAttach (); - return eEventActionSuccess; - } - break; + switch (state) { + case eStateAttaching: + return eEventActionSuccess; - default: - case eStateExited: - case eStateInvalid: - break; - } + case eStateRunning: + case eStateConnected: + return eEventActionRetry; - m_exit_string.assign ("No valid Process"); - return eEventActionExit; -} + case eStateStopped: + case eStateCrashed: + // During attach, prior to sending the eStateStopped event, + // lldb_private::Process subclasses must set the new process ID. + assert(m_process->GetID() != LLDB_INVALID_PROCESS_ID); + // We don't want these events to be reported, so go set the ShouldReportStop + // here: + m_process->GetThreadList().SetShouldReportStop(eVoteNo); -Process::NextEventAction::EventActionResult -Process::AttachCompletionHandler::HandleBeingInterrupted() -{ - return eEventActionSuccess; -} - -const char * -Process::AttachCompletionHandler::GetExitString () -{ - return m_exit_string.c_str(); -} + if (m_exec_count > 0) { + --m_exec_count; -ListenerSP -ProcessAttachInfo::GetListenerForProcess (Debugger &debugger) -{ - if (m_listener_sp) - return m_listener_sp; - else - return debugger.GetListener(); -} + if (log) + log->Printf("Process::AttachCompletionHandler::%s state %s: reduced " + "remaining exec count to %" PRIu32 ", requesting resume", + __FUNCTION__, StateAsCString(state), m_exec_count); -Error -Process::Attach (ProcessAttachInfo &attach_info) -{ - m_abi_sp.reset(); - m_process_input_reader.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); - m_system_runtime_ap.reset(); - m_os_ap.reset(); - m_stop_info_override_callback = nullptr; - - lldb::pid_t attach_pid = attach_info.GetProcessID(); - Error error; - if (attach_pid == LLDB_INVALID_PROCESS_ID) - { - char process_name[PATH_MAX]; - - if (attach_info.GetExecutableFile().GetPath (process_name, sizeof(process_name))) - { - const bool wait_for_launch = attach_info.GetWaitForLaunch(); - - if (wait_for_launch) - { - error = WillAttachToProcessWithName(process_name, wait_for_launch); - if (error.Success()) - { - if (m_public_run_lock.TrySetRunning()) - { - m_should_detach = true; - const bool restarted = false; - SetPublicState (eStateAttaching, restarted); - // Now attach using these arguments. - error = DoAttachToProcessWithName (process_name, attach_info); - } - else - { - // This shouldn't happen - error.SetErrorString("failed to acquire process run lock"); - } + RequestResume(); + return eEventActionRetry; + } else { + if (log) + log->Printf("Process::AttachCompletionHandler::%s state %s: no more " + "execs expected to start, continuing with attach", + __FUNCTION__, StateAsCString(state)); - if (error.Fail()) - { - if (GetID() != LLDB_INVALID_PROCESS_ID) - { - SetID (LLDB_INVALID_PROCESS_ID); - if (error.AsCString() == nullptr) - error.SetErrorString("attach failed"); - - SetExitStatus(-1, error.AsCString()); - } - } - else - { - SetNextEventAction(new Process::AttachCompletionHandler(this, attach_info.GetResumeCount())); - StartPrivateStateThread(); - } - return error; - } - } - else - { - ProcessInstanceInfoList process_infos; - PlatformSP platform_sp (GetTarget().GetPlatform ()); - - if (platform_sp) - { - ProcessInstanceInfoMatch match_info; - match_info.GetProcessInfo() = attach_info; - match_info.SetNameMatchType (eNameMatchEquals); - platform_sp->FindProcesses (match_info, process_infos); - const uint32_t num_matches = process_infos.GetSize(); - if (num_matches == 1) - { - attach_pid = process_infos.GetProcessIDAtIndex(0); - // Fall through and attach using the above process ID - } - else - { - match_info.GetProcessInfo().GetExecutableFile().GetPath (process_name, sizeof(process_name)); - if (num_matches > 1) - { - StreamString s; - ProcessInstanceInfo::DumpTableHeader (s, platform_sp.get(), true, false); - for (size_t i = 0; i < num_matches; i++) - { - process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(s, platform_sp.get(), true, false); - } - error.SetErrorStringWithFormat ("more than one process named %s:\n%s", - process_name, - s.GetData()); - } - else - error.SetErrorStringWithFormat ("could not find a process named %s", process_name); - } - } - else - { - error.SetErrorString ("invalid platform, can't find processes by name"); - return error; - } - } - } - else - { - error.SetErrorString ("invalid process name"); - } + m_process->CompleteAttach(); + return eEventActionSuccess; } - - if (attach_pid != LLDB_INVALID_PROCESS_ID) - { - error = WillAttachToProcessWithID(attach_pid); - if (error.Success()) - { - - if (m_public_run_lock.TrySetRunning()) - { - // Now attach using these arguments. - m_should_detach = true; - const bool restarted = false; - SetPublicState (eStateAttaching, restarted); - error = DoAttachToProcessWithID (attach_pid, attach_info); - } - else - { - // This shouldn't happen - error.SetErrorString("failed to acquire process run lock"); - } - - if (error.Success()) - { - SetNextEventAction(new Process::AttachCompletionHandler(this, attach_info.GetResumeCount())); - StartPrivateStateThread(); - } - else - { - if (GetID() != LLDB_INVALID_PROCESS_ID) - SetID (LLDB_INVALID_PROCESS_ID); + break; - const char *error_string = error.AsCString(); - if (error_string == nullptr) - error_string = "attach failed"; + default: + case eStateExited: + case eStateInvalid: + break; + } - SetExitStatus(-1, error_string); - } - } - } - return error; + m_exit_string.assign("No valid Process"); + return eEventActionExit; } -void -Process::CompleteAttach () -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TARGET)); - if (log) - log->Printf ("Process::%s()", __FUNCTION__); - - // Let the process subclass figure out at much as it can about the process - // before we go looking for a dynamic loader plug-in. - ArchSpec process_arch; - DidAttach(process_arch); - - if (process_arch.IsValid()) - { - GetTarget().SetArchitecture(process_arch); - if (log) - { - const char *triple_str = process_arch.GetTriple().getTriple().c_str (); - log->Printf ("Process::%s replacing process architecture with DidAttach() architecture: %s", - __FUNCTION__, - triple_str ? triple_str : "<null>"); - } - } - - // We just attached. If we have a platform, ask it for the process architecture, and if it isn't - // the same as the one we've already set, switch architectures. - PlatformSP platform_sp (GetTarget().GetPlatform ()); - assert(platform_sp); - if (platform_sp) - { - const ArchSpec &target_arch = GetTarget().GetArchitecture(); - if (target_arch.IsValid() && !platform_sp->IsCompatibleArchitecture(target_arch, false, nullptr)) - { - ArchSpec platform_arch; - platform_sp = platform_sp->GetPlatformForArchitecture (target_arch, &platform_arch); - if (platform_sp) - { - GetTarget().SetPlatform (platform_sp); - GetTarget().SetArchitecture(platform_arch); - if (log) - log->Printf ("Process::%s switching platform to %s and architecture to %s based on info from attach", __FUNCTION__, platform_sp->GetName().AsCString (""), platform_arch.GetTriple().getTriple().c_str ()); +Process::NextEventAction::EventActionResult +Process::AttachCompletionHandler::HandleBeingInterrupted() { + return eEventActionSuccess; +} + +const char *Process::AttachCompletionHandler::GetExitString() { + return m_exit_string.c_str(); +} + +ListenerSP ProcessAttachInfo::GetListenerForProcess(Debugger &debugger) { + if (m_listener_sp) + return m_listener_sp; + else + return debugger.GetListener(); +} + +Error Process::Attach(ProcessAttachInfo &attach_info) { + m_abi_sp.reset(); + m_process_input_reader.reset(); + m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); + m_system_runtime_ap.reset(); + m_os_ap.reset(); + m_stop_info_override_callback = nullptr; + + lldb::pid_t attach_pid = attach_info.GetProcessID(); + Error error; + if (attach_pid == LLDB_INVALID_PROCESS_ID) { + char process_name[PATH_MAX]; + + if (attach_info.GetExecutableFile().GetPath(process_name, + sizeof(process_name))) { + const bool wait_for_launch = attach_info.GetWaitForLaunch(); + + if (wait_for_launch) { + error = WillAttachToProcessWithName(process_name, wait_for_launch); + if (error.Success()) { + if (m_public_run_lock.TrySetRunning()) { + m_should_detach = true; + const bool restarted = false; + SetPublicState(eStateAttaching, restarted); + // Now attach using these arguments. + error = DoAttachToProcessWithName(process_name, attach_info); + } else { + // This shouldn't happen + error.SetErrorString("failed to acquire process run lock"); + } + + if (error.Fail()) { + if (GetID() != LLDB_INVALID_PROCESS_ID) { + SetID(LLDB_INVALID_PROCESS_ID); + if (error.AsCString() == nullptr) + error.SetErrorString("attach failed"); + + SetExitStatus(-1, error.AsCString()); } + } else { + SetNextEventAction(new Process::AttachCompletionHandler( + this, attach_info.GetResumeCount())); + StartPrivateStateThread(); + } + return error; } - else if (!process_arch.IsValid()) - { - ProcessInstanceInfo process_info; - GetProcessInfo(process_info); - const ArchSpec &process_arch = process_info.GetArchitecture(); - if (process_arch.IsValid() && !GetTarget().GetArchitecture().IsExactMatch(process_arch)) - { - GetTarget().SetArchitecture (process_arch); - if (log) - log->Printf ("Process::%s switching architecture to %s based on info the platform retrieved for pid %" PRIu64, __FUNCTION__, process_arch.GetTriple().getTriple().c_str (), GetID ()); - } + } else { + ProcessInstanceInfoList process_infos; + PlatformSP platform_sp(GetTarget().GetPlatform()); + + if (platform_sp) { + ProcessInstanceInfoMatch match_info; + match_info.GetProcessInfo() = attach_info; + match_info.SetNameMatchType(eNameMatchEquals); + platform_sp->FindProcesses(match_info, process_infos); + const uint32_t num_matches = process_infos.GetSize(); + if (num_matches == 1) { + attach_pid = process_infos.GetProcessIDAtIndex(0); + // Fall through and attach using the above process ID + } else { + match_info.GetProcessInfo().GetExecutableFile().GetPath( + process_name, sizeof(process_name)); + if (num_matches > 1) { + StreamString s; + ProcessInstanceInfo::DumpTableHeader(s, platform_sp.get(), true, + false); + for (size_t i = 0; i < num_matches; i++) { + process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow( + s, platform_sp.get(), true, false); + } + error.SetErrorStringWithFormat( + "more than one process named %s:\n%s", process_name, + s.GetData()); + } else + error.SetErrorStringWithFormat( + "could not find a process named %s", process_name); + } + } else { + error.SetErrorString( + "invalid platform, can't find processes by name"); + return error; } - } - - // We have completed the attach, now it is time to find the dynamic loader - // plug-in - DynamicLoader *dyld = GetDynamicLoader (); - if (dyld) - { - dyld->DidAttach(); + } + } else { + error.SetErrorString("invalid process name"); + } + } + + if (attach_pid != LLDB_INVALID_PROCESS_ID) { + error = WillAttachToProcessWithID(attach_pid); + if (error.Success()) { + + if (m_public_run_lock.TrySetRunning()) { + // Now attach using these arguments. + m_should_detach = true; + const bool restarted = false; + SetPublicState(eStateAttaching, restarted); + error = DoAttachToProcessWithID(attach_pid, attach_info); + } else { + // This shouldn't happen + error.SetErrorString("failed to acquire process run lock"); + } + + if (error.Success()) { + SetNextEventAction(new Process::AttachCompletionHandler( + this, attach_info.GetResumeCount())); + StartPrivateStateThread(); + } else { + if (GetID() != LLDB_INVALID_PROCESS_ID) + SetID(LLDB_INVALID_PROCESS_ID); + + const char *error_string = error.AsCString(); + if (error_string == nullptr) + error_string = "attach failed"; + + SetExitStatus(-1, error_string); + } + } + } + return error; +} + +void Process::CompleteAttach() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | + LIBLLDB_LOG_TARGET)); + if (log) + log->Printf("Process::%s()", __FUNCTION__); + + // Let the process subclass figure out at much as it can about the process + // before we go looking for a dynamic loader plug-in. + ArchSpec process_arch; + DidAttach(process_arch); + + if (process_arch.IsValid()) { + GetTarget().SetArchitecture(process_arch); + if (log) { + const char *triple_str = process_arch.GetTriple().getTriple().c_str(); + log->Printf("Process::%s replacing process architecture with DidAttach() " + "architecture: %s", + __FUNCTION__, triple_str ? triple_str : "<null>"); + } + } + + // We just attached. If we have a platform, ask it for the process + // architecture, and if it isn't + // the same as the one we've already set, switch architectures. + PlatformSP platform_sp(GetTarget().GetPlatform()); + assert(platform_sp); + if (platform_sp) { + const ArchSpec &target_arch = GetTarget().GetArchitecture(); + if (target_arch.IsValid() && + !platform_sp->IsCompatibleArchitecture(target_arch, false, nullptr)) { + ArchSpec platform_arch; + platform_sp = + platform_sp->GetPlatformForArchitecture(target_arch, &platform_arch); + if (platform_sp) { + GetTarget().SetPlatform(platform_sp); + GetTarget().SetArchitecture(platform_arch); if (log) - { - ModuleSP exe_module_sp = GetTarget().GetExecutableModule (); - log->Printf ("Process::%s after DynamicLoader::DidAttach(), target executable is %s (using %s plugin)", - __FUNCTION__, - exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>", - dyld->GetPluginName().AsCString ("<unnamed>")); - } - } - - GetJITLoaders().DidAttach(); - - SystemRuntime *system_runtime = GetSystemRuntime (); - if (system_runtime) - { - system_runtime->DidAttach(); + log->Printf("Process::%s switching platform to %s and architecture " + "to %s based on info from attach", + __FUNCTION__, platform_sp->GetName().AsCString(""), + platform_arch.GetTriple().getTriple().c_str()); + } + } else if (!process_arch.IsValid()) { + ProcessInstanceInfo process_info; + GetProcessInfo(process_info); + const ArchSpec &process_arch = process_info.GetArchitecture(); + if (process_arch.IsValid() && + !GetTarget().GetArchitecture().IsExactMatch(process_arch)) { + GetTarget().SetArchitecture(process_arch); if (log) - { - ModuleSP exe_module_sp = GetTarget().GetExecutableModule (); - log->Printf ("Process::%s after SystemRuntime::DidAttach(), target executable is %s (using %s plugin)", - __FUNCTION__, - exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>", - system_runtime->GetPluginName().AsCString("<unnamed>")); - } + log->Printf("Process::%s switching architecture to %s based on info " + "the platform retrieved for pid %" PRIu64, + __FUNCTION__, + process_arch.GetTriple().getTriple().c_str(), GetID()); + } + } + } + + // We have completed the attach, now it is time to find the dynamic loader + // plug-in + DynamicLoader *dyld = GetDynamicLoader(); + if (dyld) { + dyld->DidAttach(); + if (log) { + ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + log->Printf("Process::%s after DynamicLoader::DidAttach(), target " + "executable is %s (using %s plugin)", + __FUNCTION__, + exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() + : "<none>", + dyld->GetPluginName().AsCString("<unnamed>")); + } + } + + GetJITLoaders().DidAttach(); + + SystemRuntime *system_runtime = GetSystemRuntime(); + if (system_runtime) { + system_runtime->DidAttach(); + if (log) { + ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + log->Printf("Process::%s after SystemRuntime::DidAttach(), target " + "executable is %s (using %s plugin)", + __FUNCTION__, + exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() + : "<none>", + system_runtime->GetPluginName().AsCString("<unnamed>")); + } + } + + m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); + // Figure out which one is the executable, and set that in our target: + const ModuleList &target_modules = GetTarget().GetImages(); + std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); + size_t num_modules = target_modules.GetSize(); + ModuleSP new_executable_module_sp; + + for (size_t i = 0; i < num_modules; i++) { + ModuleSP module_sp(target_modules.GetModuleAtIndexUnlocked(i)); + if (module_sp && module_sp->IsExecutable()) { + if (GetTarget().GetExecutableModulePointer() != module_sp.get()) + new_executable_module_sp = module_sp; + break; + } + } + if (new_executable_module_sp) { + GetTarget().SetExecutableModule(new_executable_module_sp, false); + if (log) { + ModuleSP exe_module_sp = GetTarget().GetExecutableModule(); + log->Printf( + "Process::%s after looping through modules, target executable is %s", + __FUNCTION__, + exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str() + : "<none>"); + } + } + + m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback(); +} + +Error Process::ConnectRemote(Stream *strm, const char *remote_url) { + m_abi_sp.reset(); + m_process_input_reader.reset(); + + // Find the process and its architecture. Make sure it matches the + // architecture + // of the current Target, and if not adjust it. + + Error error(DoConnectRemote(strm, remote_url)); + if (error.Success()) { + if (GetID() != LLDB_INVALID_PROCESS_ID) { + EventSP event_sp; + StateType state = + WaitForProcessStopPrivate(std::chrono::microseconds(0), event_sp); + + if (state == eStateStopped || state == eStateCrashed) { + // If we attached and actually have a process on the other end, then + // this ended up being the equivalent of an attach. + CompleteAttach(); + + // This delays passing the stopped event to listeners till + // CompleteAttach gets a chance to complete... + HandlePrivateEvent(event_sp); + } } - m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr)); - // Figure out which one is the executable, and set that in our target: - const ModuleList &target_modules = GetTarget().GetImages(); - std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex()); - size_t num_modules = target_modules.GetSize(); - ModuleSP new_executable_module_sp; - - for (size_t i = 0; i < num_modules; i++) - { - ModuleSP module_sp (target_modules.GetModuleAtIndexUnlocked (i)); - if (module_sp && module_sp->IsExecutable()) - { - if (GetTarget().GetExecutableModulePointer() != module_sp.get()) - new_executable_module_sp = module_sp; - break; - } - } - if (new_executable_module_sp) - { - GetTarget().SetExecutableModule (new_executable_module_sp, false); - if (log) - { - ModuleSP exe_module_sp = GetTarget().GetExecutableModule (); - log->Printf ("Process::%s after looping through modules, target executable is %s", - __FUNCTION__, - exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>"); + if (PrivateStateThreadIsValid()) + ResumePrivateStateThread(); + else + StartPrivateStateThread(); + } + return error; +} + +Error Process::PrivateResume() { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS | + LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Process::PrivateResume() m_stop_id = %u, public state: %s " + "private state: %s", + m_mod_id.GetStopID(), StateAsCString(m_public_state.GetValue()), + StateAsCString(m_private_state.GetValue())); + + Error error(WillResume()); + // Tell the process it is about to resume before the thread list + if (error.Success()) { + // Now let the thread list know we are about to resume so it + // can let all of our threads know that they are about to be + // resumed. Threads will each be called with + // Thread::WillResume(StateType) where StateType contains the state + // that they are supposed to have when the process is resumed + // (suspended/running/stepping). Threads should also check + // their resume signal in lldb::Thread::GetResumeSignal() + // to see if they are supposed to start back up with a signal. + if (m_thread_list.WillResume()) { + // Last thing, do the PreResumeActions. + if (!RunPreResumeActions()) { + error.SetErrorStringWithFormat( + "Process::PrivateResume PreResumeActions failed, not resuming."); + } else { + m_mod_id.BumpResumeID(); + error = DoResume(); + if (error.Success()) { + DidResume(); + m_thread_list.DidResume(); + if (log) + log->Printf("Process thinks the process has resumed."); } - } + } + } else { + // Somebody wanted to run without running (e.g. we were faking a step from + // one frame of a set of inlined + // frames that share the same PC to another.) So generate a continue & a + // stopped event, + // and let the world handle them. + if (log) + log->Printf( + "Process::PrivateResume() asked to simulate a start & stop."); + + SetPrivateState(eStateRunning); + SetPrivateState(eStateStopped); + } + } else if (log) + log->Printf("Process::PrivateResume() got an error \"%s\".", + error.AsCString("<unknown error>")); + return error; +} + +Error Process::Halt(bool clear_thread_plans, bool use_run_lock) { + if (!StateIsRunningState(m_public_state.GetValue())) + return Error("Process is not running."); + + // Don't clear the m_clear_thread_plans_on_stop, only set it to true if + // in case it was already set and some thread plan logic calls halt on its + // own. + m_clear_thread_plans_on_stop |= clear_thread_plans; + + ListenerSP halt_listener_sp( + Listener::MakeListener("lldb.process.halt_listener")); + HijackProcessEvents(halt_listener_sp); + + EventSP event_sp; + + SendAsyncInterrupt(); + + if (m_public_state.GetValue() == eStateAttaching) { + // Don't hijack and eat the eStateExited as the code that was doing + // the attach will be waiting for this event... + RestoreProcessEvents(); + SetExitStatus(SIGKILL, "Cancelled async attach."); + Destroy(false); + return Error(); + } - m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback(); -} + // Wait for 10 second for the process to stop. + StateType state = + WaitForProcessToStop(std::chrono::seconds(10), &event_sp, true, + halt_listener_sp, nullptr, use_run_lock); + RestoreProcessEvents(); -Error -Process::ConnectRemote (Stream *strm, const char *remote_url) -{ - m_abi_sp.reset(); - m_process_input_reader.reset(); - - // Find the process and its architecture. Make sure it matches the architecture - // of the current Target, and if not adjust it. - - Error error (DoConnectRemote (strm, remote_url)); - if (error.Success()) - { - if (GetID() != LLDB_INVALID_PROCESS_ID) - { - EventSP event_sp; - StateType state = WaitForProcessStopPrivate(std::chrono::microseconds(0), event_sp); - - if (state == eStateStopped || state == eStateCrashed) - { - // If we attached and actually have a process on the other end, then - // this ended up being the equivalent of an attach. - CompleteAttach (); - - // This delays passing the stopped event to listeners till - // CompleteAttach gets a chance to complete... - HandlePrivateEvent (event_sp); - } - } - - if (PrivateStateThreadIsValid ()) - ResumePrivateStateThread (); - else - StartPrivateStateThread (); - } - return error; -} + if (state == eStateInvalid || !event_sp) { + // We timed out and didn't get a stop event... + return Error("Halt timed out. State = %s", StateAsCString(GetState())); + } -Error -Process::PrivateResume () -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Process::PrivateResume() m_stop_id = %u, public state: %s private state: %s", - m_mod_id.GetStopID(), - StateAsCString(m_public_state.GetValue()), - StateAsCString(m_private_state.GetValue())); + BroadcastEvent(event_sp); - Error error (WillResume()); - // Tell the process it is about to resume before the thread list - if (error.Success()) - { - // Now let the thread list know we are about to resume so it - // can let all of our threads know that they are about to be - // resumed. Threads will each be called with - // Thread::WillResume(StateType) where StateType contains the state - // that they are supposed to have when the process is resumed - // (suspended/running/stepping). Threads should also check - // their resume signal in lldb::Thread::GetResumeSignal() - // to see if they are supposed to start back up with a signal. - if (m_thread_list.WillResume()) - { - // Last thing, do the PreResumeActions. - if (!RunPreResumeActions()) - { - error.SetErrorStringWithFormat ("Process::PrivateResume PreResumeActions failed, not resuming."); - } - else - { - m_mod_id.BumpResumeID(); - error = DoResume(); - if (error.Success()) - { - DidResume(); - m_thread_list.DidResume(); - if (log) - log->Printf ("Process thinks the process has resumed."); - } - } - } - else - { - // Somebody wanted to run without running (e.g. we were faking a step from one frame of a set of inlined - // frames that share the same PC to another.) So generate a continue & a stopped event, - // and let the world handle them. - if (log) - log->Printf ("Process::PrivateResume() asked to simulate a start & stop."); - - SetPrivateState(eStateRunning); - SetPrivateState(eStateStopped); - } - } - else if (log) - log->Printf ("Process::PrivateResume() got an error \"%s\".", error.AsCString("<unknown error>")); - return error; + return Error(); } -Error -Process::Halt (bool clear_thread_plans, bool use_run_lock) -{ - if (! StateIsRunningState(m_public_state.GetValue())) - return Error("Process is not running."); +Error Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) { + Error error; + + // Check both the public & private states here. If we're hung evaluating an + // expression, for instance, then + // the public state will be stopped, but we still need to interrupt. + if (m_public_state.GetValue() == eStateRunning || + m_private_state.GetValue() == eStateRunning) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::%s() About to stop.", __FUNCTION__); - // Don't clear the m_clear_thread_plans_on_stop, only set it to true if - // in case it was already set and some thread plan logic calls halt on its - // own. - m_clear_thread_plans_on_stop |= clear_thread_plans; - - ListenerSP halt_listener_sp (Listener::MakeListener("lldb.process.halt_listener")); - HijackProcessEvents(halt_listener_sp); + ListenerSP listener_sp( + Listener::MakeListener("lldb.Process.StopForDestroyOrDetach.hijack")); + HijackProcessEvents(listener_sp); - EventSP event_sp; - SendAsyncInterrupt(); - if (m_public_state.GetValue() == eStateAttaching) - { - // Don't hijack and eat the eStateExited as the code that was doing - // the attach will be waiting for this event... - RestoreProcessEvents(); - SetExitStatus(SIGKILL, "Cancelled async attach."); - Destroy (false); - return Error(); - } + // Consume the interrupt event. + StateType state = WaitForProcessToStop(std::chrono::seconds(10), + &exit_event_sp, true, listener_sp); - // Wait for 10 second for the process to stop. - StateType state = - WaitForProcessToStop(std::chrono::seconds(10), &event_sp, true, halt_listener_sp, nullptr, use_run_lock); RestoreProcessEvents(); - if (state == eStateInvalid || ! event_sp) - { - // We timed out and didn't get a stop event... - return Error("Halt timed out. State = %s", StateAsCString(GetState())); + // If the process exited while we were waiting for it to stop, put the + // exited event into + // the shared pointer passed in and return. Our caller doesn't need to do + // anything else, since + // they don't have a process anymore... + + if (state == eStateExited || m_private_state.GetValue() == eStateExited) { + if (log) + log->Printf("Process::%s() Process exited while waiting to stop.", + __FUNCTION__); + return error; + } else + exit_event_sp.reset(); // It is ok to consume any non-exit stop events + + if (state != eStateStopped) { + if (log) + log->Printf("Process::%s() failed to stop, state is: %s", __FUNCTION__, + StateAsCString(state)); + // If we really couldn't stop the process then we should just error out + // here, but if the + // lower levels just bobbled sending the event and we really are stopped, + // then continue on. + StateType private_state = m_private_state.GetValue(); + if (private_state != eStateStopped) { + return Error("Attempt to stop the target in order to detach timed out. " + "State = %s", + StateAsCString(GetState())); + } + } + } + return error; +} + +Error Process::Detach(bool keep_stopped) { + EventSP exit_event_sp; + Error error; + m_destroy_in_process = true; + + error = WillDetach(); + + if (error.Success()) { + if (DetachRequiresHalt()) { + error = StopForDestroyOrDetach(exit_event_sp); + if (!error.Success()) { + m_destroy_in_process = false; + return error; + } else if (exit_event_sp) { + // We shouldn't need to do anything else here. There's no process left + // to detach from... + StopPrivateStateThread(); + m_destroy_in_process = false; + return error; + } } - BroadcastEvent(event_sp); - - return Error(); -} - -Error -Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) -{ - Error error; - - // Check both the public & private states here. If we're hung evaluating an expression, for instance, then - // the public state will be stopped, but we still need to interrupt. - if (m_public_state.GetValue() == eStateRunning || m_private_state.GetValue() == eStateRunning) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::%s() About to stop.", __FUNCTION__); - - ListenerSP listener_sp (Listener::MakeListener("lldb.Process.StopForDestroyOrDetach.hijack")); - HijackProcessEvents(listener_sp); - - SendAsyncInterrupt(); - - // Consume the interrupt event. - StateType state = WaitForProcessToStop(std::chrono::seconds(10), &exit_event_sp, true, listener_sp); - - RestoreProcessEvents(); - - // If the process exited while we were waiting for it to stop, put the exited event into - // the shared pointer passed in and return. Our caller doesn't need to do anything else, since - // they don't have a process anymore... - - if (state == eStateExited || m_private_state.GetValue() == eStateExited) - { - if (log) - log->Printf("Process::%s() Process exited while waiting to stop.", __FUNCTION__); - return error; - } - else - exit_event_sp.reset(); // It is ok to consume any non-exit stop events - - if (state != eStateStopped) - { - if (log) - log->Printf("Process::%s() failed to stop, state is: %s", __FUNCTION__, StateAsCString(state)); - // If we really couldn't stop the process then we should just error out here, but if the - // lower levels just bobbled sending the event and we really are stopped, then continue on. - StateType private_state = m_private_state.GetValue(); - if (private_state != eStateStopped) - { - return Error("Attempt to stop the target in order to detach timed out. State = %s", StateAsCString(GetState())); - } - } + m_thread_list.DiscardThreadPlans(); + DisableAllBreakpointSites(); + + error = DoDetach(keep_stopped); + if (error.Success()) { + DidDetach(); + StopPrivateStateThread(); + } else { + return error; + } + } + m_destroy_in_process = false; + + // If we exited when we were waiting for a process to stop, then + // forward the event here so we don't lose the event + if (exit_event_sp) { + // Directly broadcast our exited event because we shut down our + // private state thread above + BroadcastEvent(exit_event_sp); + } + + // If we have been interrupted (to kill us) in the middle of running, we may + // not end up propagating + // the last events through the event system, in which case we might strand the + // write lock. Unlock + // it here so when we do to tear down the process we don't get an error + // destroying the lock. + + m_public_run_lock.SetStopped(); + return error; +} + +Error Process::Destroy(bool force_kill) { + + // Tell ourselves we are in the process of destroying the process, so that we + // don't do any unnecessary work + // that might hinder the destruction. Remember to set this back to false when + // we are done. That way if the attempt + // failed and the process stays around for some reason it won't be in a + // confused state. + + if (force_kill) + m_should_detach = false; + + if (GetShouldDetach()) { + // FIXME: This will have to be a process setting: + bool keep_stopped = false; + Detach(keep_stopped); + } + + m_destroy_in_process = true; + + Error error(WillDestroy()); + if (error.Success()) { + EventSP exit_event_sp; + if (DestroyRequiresHalt()) { + error = StopForDestroyOrDetach(exit_event_sp); } - return error; -} -Error -Process::Detach (bool keep_stopped) -{ - EventSP exit_event_sp; - Error error; - m_destroy_in_process = true; - - error = WillDetach(); + if (m_public_state.GetValue() != eStateRunning) { + // Ditch all thread plans, and remove all our breakpoints: in case we have + // to restart the target to + // kill it, we don't want it hitting a breakpoint... + // Only do this if we've stopped, however, since if we didn't manage to + // halt it above, then + // we're not going to have much luck doing this now. + m_thread_list.DiscardThreadPlans(); + DisableAllBreakpointSites(); + } - if (error.Success()) - { - if (DetachRequiresHalt()) - { - error = StopForDestroyOrDetach (exit_event_sp); - if (!error.Success()) - { - m_destroy_in_process = false; - return error; - } - else if (exit_event_sp) - { - // We shouldn't need to do anything else here. There's no process left to detach from... - StopPrivateStateThread(); - m_destroy_in_process = false; - return error; - } - } - - m_thread_list.DiscardThreadPlans(); - DisableAllBreakpointSites(); + error = DoDestroy(); + if (error.Success()) { + DidDestroy(); + StopPrivateStateThread(); + } + m_stdio_communication.Disconnect(); + m_stdio_communication.StopReadThread(); + m_stdin_forward = false; - error = DoDetach(keep_stopped); - if (error.Success()) - { - DidDetach(); - StopPrivateStateThread(); - } - else - { - return error; - } + if (m_process_input_reader) { + m_process_input_reader->SetIsDone(true); + m_process_input_reader->Cancel(); + m_process_input_reader.reset(); } - m_destroy_in_process = false; - + // If we exited when we were waiting for a process to stop, then // forward the event here so we don't lose the event - if (exit_event_sp) - { - // Directly broadcast our exited event because we shut down our - // private state thread above - BroadcastEvent(exit_event_sp); - } - - // If we have been interrupted (to kill us) in the middle of running, we may not end up propagating - // the last events through the event system, in which case we might strand the write lock. Unlock - // it here so when we do to tear down the process we don't get an error destroying the lock. - + if (exit_event_sp) { + // Directly broadcast our exited event because we shut down our + // private state thread above + BroadcastEvent(exit_event_sp); + } + + // If we have been interrupted (to kill us) in the middle of running, we may + // not end up propagating + // the last events through the event system, in which case we might strand + // the write lock. Unlock + // it here so when we do to tear down the process we don't get an error + // destroying the lock. m_public_run_lock.SetStopped(); - return error; -} - -Error -Process::Destroy (bool force_kill) -{ + } - // Tell ourselves we are in the process of destroying the process, so that we don't do any unnecessary work - // that might hinder the destruction. Remember to set this back to false when we are done. That way if the attempt - // failed and the process stays around for some reason it won't be in a confused state. + m_destroy_in_process = false; - if (force_kill) - m_should_detach = false; - - if (GetShouldDetach()) - { - // FIXME: This will have to be a process setting: - bool keep_stopped = false; - Detach(keep_stopped); - } - - m_destroy_in_process = true; + return error; +} - Error error (WillDestroy()); +Error Process::Signal(int signal) { + Error error(WillSignal()); + if (error.Success()) { + error = DoSignal(signal); if (error.Success()) - { - EventSP exit_event_sp; - if (DestroyRequiresHalt()) - { - error = StopForDestroyOrDetach(exit_event_sp); - } - - if (m_public_state.GetValue() != eStateRunning) - { - // Ditch all thread plans, and remove all our breakpoints: in case we have to restart the target to - // kill it, we don't want it hitting a breakpoint... - // Only do this if we've stopped, however, since if we didn't manage to halt it above, then - // we're not going to have much luck doing this now. - m_thread_list.DiscardThreadPlans(); - DisableAllBreakpointSites(); + DidSignal(); + } + return error; +} + +void Process::SetUnixSignals(UnixSignalsSP &&signals_sp) { + assert(signals_sp && "null signals_sp"); + m_unix_signals_sp = signals_sp; +} + +const lldb::UnixSignalsSP &Process::GetUnixSignals() { + assert(m_unix_signals_sp && "null m_unix_signals_sp"); + return m_unix_signals_sp; +} + +lldb::ByteOrder Process::GetByteOrder() const { + return GetTarget().GetArchitecture().GetByteOrder(); +} + +uint32_t Process::GetAddressByteSize() const { + return GetTarget().GetArchitecture().GetAddressByteSize(); +} + +bool Process::ShouldBroadcastEvent(Event *event_ptr) { + const StateType state = + Process::ProcessEventData::GetStateFromEvent(event_ptr); + bool return_value = true; + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS | + LIBLLDB_LOG_PROCESS)); + + switch (state) { + case eStateDetached: + case eStateExited: + case eStateUnloaded: + m_stdio_communication.SynchronizeWithReadThread(); + m_stdio_communication.Disconnect(); + m_stdio_communication.StopReadThread(); + m_stdin_forward = false; + + LLVM_FALLTHROUGH; + case eStateConnected: + case eStateAttaching: + case eStateLaunching: + // These events indicate changes in the state of the debugging session, + // always report them. + return_value = true; + break; + case eStateInvalid: + // We stopped for no apparent reason, don't report it. + return_value = false; + break; + case eStateRunning: + case eStateStepping: + // If we've started the target running, we handle the cases where we + // are already running and where there is a transition from stopped to + // running differently. + // running -> running: Automatically suppress extra running events + // stopped -> running: Report except when there is one or more no votes + // and no yes votes. + SynchronouslyNotifyStateChanged(state); + if (m_force_next_event_delivery) + return_value = true; + else { + switch (m_last_broadcast_state) { + case eStateRunning: + case eStateStepping: + // We always suppress multiple runnings with no PUBLIC stop in between. + return_value = false; + break; + default: + // TODO: make this work correctly. For now always report + // run if we aren't running so we don't miss any running + // events. If I run the lldb/test/thread/a.out file and + // break at main.cpp:58, run and hit the breakpoints on + // multiple threads, then somehow during the stepping over + // of all breakpoints no run gets reported. + + // This is a transition from stop to run. + switch (m_thread_list.ShouldReportRun(event_ptr)) { + case eVoteYes: + case eVoteNoOpinion: + return_value = true; + break; + case eVoteNo: + return_value = false; + break; } - - error = DoDestroy(); - if (error.Success()) - { - DidDestroy(); - StopPrivateStateThread(); - } - m_stdio_communication.Disconnect(); - m_stdio_communication.StopReadThread(); - m_stdin_forward = false; - - if (m_process_input_reader) - { - m_process_input_reader->SetIsDone(true); - m_process_input_reader->Cancel(); - m_process_input_reader.reset(); + break; + } + } + break; + case eStateStopped: + case eStateCrashed: + case eStateSuspended: + // We've stopped. First see if we're going to restart the target. + // If we are going to stop, then we always broadcast the event. + // If we aren't going to stop, let the thread plans decide if we're going to + // report this event. + // If no thread has an opinion, we don't report it. + + m_stdio_communication.SynchronizeWithReadThread(); + RefreshStateAfterStop(); + if (ProcessEventData::GetInterruptedFromEvent(event_ptr)) { + if (log) + log->Printf("Process::ShouldBroadcastEvent (%p) stopped due to an " + "interrupt, state: %s", + static_cast<void *>(event_ptr), StateAsCString(state)); + // Even though we know we are going to stop, we should let the threads + // have a look at the stop, + // so they can properly set their state. + m_thread_list.ShouldStop(event_ptr); + return_value = true; + } else { + bool was_restarted = ProcessEventData::GetRestartedFromEvent(event_ptr); + bool should_resume = false; + + // It makes no sense to ask "ShouldStop" if we've already been + // restarted... + // Asking the thread list is also not likely to go well, since we are + // running again. + // So in that case just report the event. + + if (!was_restarted) + should_resume = !m_thread_list.ShouldStop(event_ptr); + + if (was_restarted || should_resume || m_resume_requested) { + Vote stop_vote = m_thread_list.ShouldReportStop(event_ptr); + if (log) + log->Printf("Process::ShouldBroadcastEvent: should_resume: %i state: " + "%s was_restarted: %i stop_vote: %d.", + should_resume, StateAsCString(state), was_restarted, + stop_vote); + + switch (stop_vote) { + case eVoteYes: + return_value = true; + break; + case eVoteNoOpinion: + case eVoteNo: + return_value = false; + break; } - // If we exited when we were waiting for a process to stop, then - // forward the event here so we don't lose the event - if (exit_event_sp) - { - // Directly broadcast our exited event because we shut down our - // private state thread above - BroadcastEvent(exit_event_sp); + if (!was_restarted) { + if (log) + log->Printf("Process::ShouldBroadcastEvent (%p) Restarting process " + "from state: %s", + static_cast<void *>(event_ptr), StateAsCString(state)); + ProcessEventData::SetRestartedInEvent(event_ptr, true); + PrivateResume(); } + } else { + return_value = true; + SynchronouslyNotifyStateChanged(state); + } + } + break; + } + + // Forcing the next event delivery is a one shot deal. So reset it here. + m_force_next_event_delivery = false; + + // We do some coalescing of events (for instance two consecutive running + // events get coalesced.) + // But we only coalesce against events we actually broadcast. So we use + // m_last_broadcast_state + // to track that. NB - you can't use "m_public_state.GetValue()" for that + // purpose, as was originally done, + // because the PublicState reflects the last event pulled off the queue, and + // there may be several + // events stacked up on the queue unserviced. So the PublicState may not + // reflect the last broadcasted event + // yet. m_last_broadcast_state gets updated here. + + if (return_value) + m_last_broadcast_state = state; + + if (log) + log->Printf("Process::ShouldBroadcastEvent (%p) => new state: %s, last " + "broadcast state: %s - %s", + static_cast<void *>(event_ptr), StateAsCString(state), + StateAsCString(m_last_broadcast_state), + return_value ? "YES" : "NO"); + return return_value; +} + +bool Process::StartPrivateStateThread(bool is_secondary_thread) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); + + bool already_running = PrivateStateThreadIsValid(); + if (log) + log->Printf("Process::%s()%s ", __FUNCTION__, + already_running ? " already running" + : " starting private state thread"); + + if (!is_secondary_thread && already_running) + return true; - // If we have been interrupted (to kill us) in the middle of running, we may not end up propagating - // the last events through the event system, in which case we might strand the write lock. Unlock - // it here so when we do to tear down the process we don't get an error destroying the lock. - m_public_run_lock.SetStopped(); - } - - m_destroy_in_process = false; - - return error; -} - -Error -Process::Signal (int signal) -{ - Error error (WillSignal()); - if (error.Success()) - { - error = DoSignal(signal); - if (error.Success()) - DidSignal(); - } - return error; -} - -void -Process::SetUnixSignals(UnixSignalsSP &&signals_sp) -{ - assert (signals_sp && "null signals_sp"); - m_unix_signals_sp = signals_sp; -} + // Create a thread that watches our internal state and controls which + // events make it to clients (into the DCProcess event queue). + char thread_name[1024]; -const lldb::UnixSignalsSP & -Process::GetUnixSignals () -{ - assert (m_unix_signals_sp && "null m_unix_signals_sp"); - return m_unix_signals_sp; + if (HostInfo::GetMaxThreadNameLength() <= 30) { + // On platforms with abbreviated thread name lengths, choose thread names + // that fit within the limit. + if (already_running) + snprintf(thread_name, sizeof(thread_name), "intern-state-OV"); + else + snprintf(thread_name, sizeof(thread_name), "intern-state"); + } else { + if (already_running) + snprintf(thread_name, sizeof(thread_name), + "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", + GetID()); + else + snprintf(thread_name, sizeof(thread_name), + "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID()); + } + + // Create the private state thread, and start it running. + PrivateStateThreadArgs *args_ptr = + new PrivateStateThreadArgs(this, is_secondary_thread); + m_private_state_thread = + ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, + (void *)args_ptr, nullptr, 8 * 1024 * 1024); + if (m_private_state_thread.IsJoinable()) { + ResumePrivateStateThread(); + return true; + } else + return false; } -lldb::ByteOrder -Process::GetByteOrder () const -{ - return GetTarget().GetArchitecture().GetByteOrder(); +void Process::PausePrivateStateThread() { + ControlPrivateStateThread(eBroadcastInternalStateControlPause); } -uint32_t -Process::GetAddressByteSize () const -{ - return GetTarget().GetArchitecture().GetAddressByteSize(); +void Process::ResumePrivateStateThread() { + ControlPrivateStateThread(eBroadcastInternalStateControlResume); } -bool -Process::ShouldBroadcastEvent (Event *event_ptr) -{ - const StateType state = Process::ProcessEventData::GetStateFromEvent (event_ptr); - bool return_value = true; - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS | LIBLLDB_LOG_PROCESS)); - - switch (state) - { - case eStateDetached: - case eStateExited: - case eStateUnloaded: - m_stdio_communication.SynchronizeWithReadThread(); - m_stdio_communication.Disconnect(); - m_stdio_communication.StopReadThread(); - m_stdin_forward = false; - - LLVM_FALLTHROUGH; - case eStateConnected: - case eStateAttaching: - case eStateLaunching: - // These events indicate changes in the state of the debugging session, always report them. - return_value = true; - break; - case eStateInvalid: - // We stopped for no apparent reason, don't report it. - return_value = false; - break; - case eStateRunning: - case eStateStepping: - // If we've started the target running, we handle the cases where we - // are already running and where there is a transition from stopped to - // running differently. - // running -> running: Automatically suppress extra running events - // stopped -> running: Report except when there is one or more no votes - // and no yes votes. - SynchronouslyNotifyStateChanged (state); - if (m_force_next_event_delivery) - return_value = true; - else - { - switch (m_last_broadcast_state) - { - case eStateRunning: - case eStateStepping: - // We always suppress multiple runnings with no PUBLIC stop in between. - return_value = false; - break; - default: - // TODO: make this work correctly. For now always report - // run if we aren't running so we don't miss any running - // events. If I run the lldb/test/thread/a.out file and - // break at main.cpp:58, run and hit the breakpoints on - // multiple threads, then somehow during the stepping over - // of all breakpoints no run gets reported. - - // This is a transition from stop to run. - switch (m_thread_list.ShouldReportRun (event_ptr)) - { - case eVoteYes: - case eVoteNoOpinion: - return_value = true; - break; - case eVoteNo: - return_value = false; - break; - } - break; - } - } - break; - case eStateStopped: - case eStateCrashed: - case eStateSuspended: - // We've stopped. First see if we're going to restart the target. - // If we are going to stop, then we always broadcast the event. - // If we aren't going to stop, let the thread plans decide if we're going to report this event. - // If no thread has an opinion, we don't report it. - - m_stdio_communication.SynchronizeWithReadThread(); - RefreshStateAfterStop (); - if (ProcessEventData::GetInterruptedFromEvent (event_ptr)) - { - if (log) - log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s", - static_cast<void*>(event_ptr), - StateAsCString(state)); - // Even though we know we are going to stop, we should let the threads have a look at the stop, - // so they can properly set their state. - m_thread_list.ShouldStop (event_ptr); - return_value = true; - } - else - { - bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr); - bool should_resume = false; - - // It makes no sense to ask "ShouldStop" if we've already been restarted... - // Asking the thread list is also not likely to go well, since we are running again. - // So in that case just report the event. - - if (!was_restarted) - should_resume = !m_thread_list.ShouldStop(event_ptr); - - if (was_restarted || should_resume || m_resume_requested) - { - Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr); - if (log) - log->Printf ("Process::ShouldBroadcastEvent: should_resume: %i state: %s was_restarted: %i stop_vote: %d.", - should_resume, StateAsCString(state), - was_restarted, stop_vote); - - switch (stop_vote) - { - case eVoteYes: - return_value = true; - break; - case eVoteNoOpinion: - case eVoteNo: - return_value = false; - break; - } - - if (!was_restarted) - { - if (log) - log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", - static_cast<void*>(event_ptr), - StateAsCString(state)); - ProcessEventData::SetRestartedInEvent(event_ptr, true); - PrivateResume (); - } - } - else - { - return_value = true; - SynchronouslyNotifyStateChanged (state); - } - } - break; - } - - // Forcing the next event delivery is a one shot deal. So reset it here. - m_force_next_event_delivery = false; - - // We do some coalescing of events (for instance two consecutive running events get coalesced.) - // But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state - // to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done, - // because the PublicState reflects the last event pulled off the queue, and there may be several - // events stacked up on the queue unserviced. So the PublicState may not reflect the last broadcasted event - // yet. m_last_broadcast_state gets updated here. - - if (return_value) - m_last_broadcast_state = state; - +void Process::StopPrivateStateThread() { + if (m_private_state_thread.IsJoinable()) + ControlPrivateStateThread(eBroadcastInternalStateControlStop); + else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); if (log) - log->Printf ("Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s", - static_cast<void*>(event_ptr), StateAsCString(state), - StateAsCString(m_last_broadcast_state), - return_value ? "YES" : "NO"); - return return_value; + log->Printf( + "Went to stop the private state thread, but it was already invalid."); + } } -bool -Process::StartPrivateStateThread (bool is_secondary_thread) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS)); +void Process::ControlPrivateStateThread(uint32_t signal) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - bool already_running = PrivateStateThreadIsValid (); - if (log) - log->Printf ("Process::%s()%s ", __FUNCTION__, already_running ? " already running" : " starting private state thread"); + assert(signal == eBroadcastInternalStateControlStop || + signal == eBroadcastInternalStateControlPause || + signal == eBroadcastInternalStateControlResume); - if (!is_secondary_thread && already_running) - return true; - - // Create a thread that watches our internal state and controls which - // events make it to clients (into the DCProcess event queue). - char thread_name[1024]; + if (log) + log->Printf("Process::%s (signal = %d)", __FUNCTION__, signal); - if (HostInfo::GetMaxThreadNameLength() <= 30) - { - // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit. - if (already_running) - snprintf(thread_name, sizeof(thread_name), "intern-state-OV"); - else - snprintf(thread_name, sizeof(thread_name), "intern-state"); - } - else - { - if (already_running) - snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID()); - else - snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID()); + // Signal the private state thread + if (m_private_state_thread.IsJoinable()) { + // Broadcast the event. + // It is important to do this outside of the if below, because + // it's possible that the thread state is invalid but that the + // thread is waiting on a control event instead of simply being + // on its way out (this should not happen, but it apparently can). + if (log) + log->Printf("Sending control event of type: %d.", signal); + std::shared_ptr<EventDataReceipt> event_receipt_sp(new EventDataReceipt()); + m_private_state_control_broadcaster.BroadcastEvent(signal, + event_receipt_sp); + + // Wait for the event receipt or for the private state thread to exit + bool receipt_received = false; + if (PrivateStateThreadIsValid()) { + while (!receipt_received) { + bool timed_out = false; + // Check for a receipt for 2 seconds and then check if the private state + // thread is still around. + receipt_received = event_receipt_sp->WaitForEventReceived( + std::chrono::seconds(2), &timed_out); + if (!receipt_received) { + // Check if the private state thread is still around. If it isn't then + // we are done waiting + if (!PrivateStateThreadIsValid()) + break; // Private state thread exited or is exiting, we are done + } + } } - // Create the private state thread, and start it running. - PrivateStateThreadArgs *args_ptr = new PrivateStateThreadArgs(this, is_secondary_thread); - m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, (void *) args_ptr, nullptr, 8 * 1024 * 1024); - if (m_private_state_thread.IsJoinable()) - { - ResumePrivateStateThread(); - return true; + if (signal == eBroadcastInternalStateControlStop) { + thread_result_t result = NULL; + m_private_state_thread.Join(&result); + m_private_state_thread.Reset(); } - else - return false; + } else { + if (log) + log->Printf( + "Private state thread already dead, no need to signal it to stop."); + } } -void -Process::PausePrivateStateThread () -{ - ControlPrivateStateThread (eBroadcastInternalStateControlPause); +void Process::SendAsyncInterrupt() { + if (PrivateStateThreadIsValid()) + m_private_state_broadcaster.BroadcastEvent(Process::eBroadcastBitInterrupt, + nullptr); + else + BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr); } -void -Process::ResumePrivateStateThread () -{ - ControlPrivateStateThread (eBroadcastInternalStateControlResume); -} +void Process::HandlePrivateEvent(EventSP &event_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + m_resume_requested = false; -void -Process::StopPrivateStateThread () -{ - if (m_private_state_thread.IsJoinable ()) - ControlPrivateStateThread (eBroadcastInternalStateControlStop); - else - { - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Went to stop the private state thread, but it was already invalid."); - } -} - -void -Process::ControlPrivateStateThread (uint32_t signal) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - - assert (signal == eBroadcastInternalStateControlStop || - signal == eBroadcastInternalStateControlPause || - signal == eBroadcastInternalStateControlResume); + const StateType new_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + // First check to see if anybody wants a shot at this event: + if (m_next_event_action_ap) { + NextEventAction::EventActionResult action_result = + m_next_event_action_ap->PerformAction(event_sp); if (log) - log->Printf ("Process::%s (signal = %d)", __FUNCTION__, signal); - - // Signal the private state thread - if (m_private_state_thread.IsJoinable()) - { - // Broadcast the event. - // It is important to do this outside of the if below, because - // it's possible that the thread state is invalid but that the - // thread is waiting on a control event instead of simply being - // on its way out (this should not happen, but it apparently can). - if (log) - log->Printf ("Sending control event of type: %d.", signal); - std::shared_ptr<EventDataReceipt> event_receipt_sp(new EventDataReceipt()); - m_private_state_control_broadcaster.BroadcastEvent(signal, event_receipt_sp); - - // Wait for the event receipt or for the private state thread to exit - bool receipt_received = false; - if (PrivateStateThreadIsValid()) - { - while (!receipt_received) - { - bool timed_out = false; - // Check for a receipt for 2 seconds and then check if the private state - // thread is still around. - receipt_received = event_receipt_sp->WaitForEventReceived(std::chrono::seconds(2), &timed_out); - if (!receipt_received) - { - // Check if the private state thread is still around. If it isn't then we are done waiting - if (!PrivateStateThreadIsValid()) - break; // Private state thread exited or is exiting, we are done - } - } - } - - if (signal == eBroadcastInternalStateControlStop) - { - thread_result_t result = NULL; - m_private_state_thread.Join(&result); - m_private_state_thread.Reset(); - } - } - else - { + log->Printf("Ran next event action, result was %d.", action_result); + + switch (action_result) { + case NextEventAction::eEventActionSuccess: + SetNextEventAction(nullptr); + break; + + case NextEventAction::eEventActionRetry: + break; + + case NextEventAction::eEventActionExit: + // Handle Exiting Here. If we already got an exited event, + // we should just propagate it. Otherwise, swallow this event, + // and set our state to exit so the next event will kill us. + if (new_state != eStateExited) { + // FIXME: should cons up an exited event, and discard this one. + SetExitStatus(0, m_next_event_action_ap->GetExitString()); + SetNextEventAction(nullptr); + return; + } + SetNextEventAction(nullptr); + break; + } + } + + // See if we should broadcast this state to external clients? + const bool should_broadcast = ShouldBroadcastEvent(event_sp.get()); + + if (should_broadcast) { + const bool is_hijacked = IsHijackedForEvent(eBroadcastBitStateChanged); + if (log) { + log->Printf("Process::%s (pid = %" PRIu64 + ") broadcasting new state %s (old state %s) to %s", + __FUNCTION__, GetID(), StateAsCString(new_state), + StateAsCString(GetState()), + is_hijacked ? "hijacked" : "public"); + } + Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get()); + if (StateIsRunningState(new_state)) { + // Only push the input handler if we aren't fowarding events, + // as this means the curses GUI is in use... + // Or don't push it if we are launching since it will come up stopped. + if (!GetTarget().GetDebugger().IsForwardingEvents() && + new_state != eStateLaunching && new_state != eStateAttaching) { + PushProcessIOHandler(); + m_iohandler_sync.SetValue(m_iohandler_sync.GetValue() + 1, + eBroadcastAlways); if (log) - log->Printf("Private state thread already dead, no need to signal it to stop."); - } -} - -void -Process::SendAsyncInterrupt () -{ - if (PrivateStateThreadIsValid()) - m_private_state_broadcaster.BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr); - else - BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr); -} + log->Printf("Process::%s updated m_iohandler_sync to %d", + __FUNCTION__, m_iohandler_sync.GetValue()); + } + } else if (StateIsStoppedState(new_state, false)) { + if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) { + // If the lldb_private::Debugger is handling the events, we don't + // want to pop the process IOHandler here, we want to do it when + // we receive the stopped event so we can carefully control when + // the process IOHandler is popped because when we stop we want to + // display some text stating how and why we stopped, then maybe some + // process/thread/frame info, and then we want the "(lldb) " prompt + // to show up. If we pop the process IOHandler here, then we will + // cause the command interpreter to become the top IOHandler after + // the process pops off and it will update its prompt right away... + // See the Debugger.cpp file where it calls the function as + // "process_sp->PopProcessIOHandler()" to see where I am talking about. + // Otherwise we end up getting overlapping "(lldb) " prompts and + // garbled output. + // + // If we aren't handling the events in the debugger (which is indicated + // by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we + // are hijacked, then we always pop the process IO handler manually. + // Hijacking happens when the internal process state thread is running + // thread plans, or when commands want to run in synchronous mode + // and they call "process->WaitForProcessToStop()". An example of + // something + // that will hijack the events is a simple expression: + // + // (lldb) expr (int)puts("hello") + // + // This will cause the internal process state thread to resume and halt + // the process (and _it_ will hijack the eBroadcastBitStateChanged + // events) and we do need the IO handler to be pushed and popped + // correctly. -void -Process::HandlePrivateEvent (EventSP &event_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - m_resume_requested = false; - - const StateType new_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - - // First check to see if anybody wants a shot at this event: - if (m_next_event_action_ap) - { - NextEventAction::EventActionResult action_result = m_next_event_action_ap->PerformAction(event_sp); - if (log) - log->Printf ("Ran next event action, result was %d.", action_result); - - switch (action_result) - { - case NextEventAction::eEventActionSuccess: - SetNextEventAction(nullptr); - break; - - case NextEventAction::eEventActionRetry: - break; - - case NextEventAction::eEventActionExit: - // Handle Exiting Here. If we already got an exited event, - // we should just propagate it. Otherwise, swallow this event, - // and set our state to exit so the next event will kill us. - if (new_state != eStateExited) - { - // FIXME: should cons up an exited event, and discard this one. - SetExitStatus(0, m_next_event_action_ap->GetExitString()); - SetNextEventAction(nullptr); - return; - } - SetNextEventAction(nullptr); - break; - } + if (is_hijacked || !GetTarget().GetDebugger().IsHandlingEvents()) + PopProcessIOHandler(); + } } - - // See if we should broadcast this state to external clients? - const bool should_broadcast = ShouldBroadcastEvent (event_sp.get()); - - if (should_broadcast) - { - const bool is_hijacked = IsHijackedForEvent(eBroadcastBitStateChanged); - if (log) - { - log->Printf ("Process::%s (pid = %" PRIu64 ") broadcasting new state %s (old state %s) to %s", - __FUNCTION__, - GetID(), - StateAsCString(new_state), - StateAsCString (GetState ()), - is_hijacked ? "hijacked" : "public"); - } - Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get()); - if (StateIsRunningState (new_state)) - { - // Only push the input handler if we aren't fowarding events, - // as this means the curses GUI is in use... - // Or don't push it if we are launching since it will come up stopped. - if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching && - new_state != eStateAttaching) - { - PushProcessIOHandler (); - m_iohandler_sync.SetValue(m_iohandler_sync.GetValue()+1, eBroadcastAlways); - if (log) - log->Printf("Process::%s updated m_iohandler_sync to %d", __FUNCTION__, m_iohandler_sync.GetValue()); - } - } - else if (StateIsStoppedState(new_state, false)) - { - if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) - { - // If the lldb_private::Debugger is handling the events, we don't - // want to pop the process IOHandler here, we want to do it when - // we receive the stopped event so we can carefully control when - // the process IOHandler is popped because when we stop we want to - // display some text stating how and why we stopped, then maybe some - // process/thread/frame info, and then we want the "(lldb) " prompt - // to show up. If we pop the process IOHandler here, then we will - // cause the command interpreter to become the top IOHandler after - // the process pops off and it will update its prompt right away... - // See the Debugger.cpp file where it calls the function as - // "process_sp->PopProcessIOHandler()" to see where I am talking about. - // Otherwise we end up getting overlapping "(lldb) " prompts and - // garbled output. - // - // If we aren't handling the events in the debugger (which is indicated - // by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we - // are hijacked, then we always pop the process IO handler manually. - // Hijacking happens when the internal process state thread is running - // thread plans, or when commands want to run in synchronous mode - // and they call "process->WaitForProcessToStop()". An example of something - // that will hijack the events is a simple expression: - // - // (lldb) expr (int)puts("hello") - // - // This will cause the internal process state thread to resume and halt - // the process (and _it_ will hijack the eBroadcastBitStateChanged - // events) and we do need the IO handler to be pushed and popped - // correctly. - - if (is_hijacked || !GetTarget().GetDebugger().IsHandlingEvents()) - PopProcessIOHandler (); - } - } - BroadcastEvent (event_sp); - } - else - { - if (log) - { - log->Printf ("Process::%s (pid = %" PRIu64 ") suppressing state %s (old state %s): should_broadcast == false", - __FUNCTION__, - GetID(), - StateAsCString(new_state), - StateAsCString (GetState ())); - } + BroadcastEvent(event_sp); + } else { + if (log) { + log->Printf( + "Process::%s (pid = %" PRIu64 + ") suppressing state %s (old state %s): should_broadcast == false", + __FUNCTION__, GetID(), StateAsCString(new_state), + StateAsCString(GetState())); } + } } -Error -Process::HaltPrivate() -{ - EventSP event_sp; - Error error (WillHalt()); - if (error.Fail()) - return error; +Error Process::HaltPrivate() { + EventSP event_sp; + Error error(WillHalt()); + if (error.Fail()) + return error; - // Ask the process subclass to actually halt our process - bool caused_stop; - error = DoHalt(caused_stop); + // Ask the process subclass to actually halt our process + bool caused_stop; + error = DoHalt(caused_stop); - DidHalt(); - return error; + DidHalt(); + return error; } -thread_result_t -Process::PrivateStateThread (void *arg) -{ - std::unique_ptr<PrivateStateThreadArgs> args_up(static_cast<PrivateStateThreadArgs *>(arg)); - thread_result_t result = args_up->process->RunPrivateStateThread(args_up->is_secondary_thread); - return result; +thread_result_t Process::PrivateStateThread(void *arg) { + std::unique_ptr<PrivateStateThreadArgs> args_up( + static_cast<PrivateStateThreadArgs *>(arg)); + thread_result_t result = + args_up->process->RunPrivateStateThread(args_up->is_secondary_thread); + return result; } -thread_result_t -Process::RunPrivateStateThread (bool is_secondary_thread) -{ - bool control_only = true; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", - __FUNCTION__, static_cast<void*>(this), GetID()); - - bool exit_now = false; - bool interrupt_requested = false; - while (!exit_now) - { - EventSP event_sp; - WaitForEventsPrivate(std::chrono::microseconds(0), event_sp, control_only); - if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster)) - { - if (log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d", - __FUNCTION__, static_cast<void*>(this), GetID(), - event_sp->GetType()); - - switch (event_sp->GetType()) - { - case eBroadcastInternalStateControlStop: - exit_now = true; - break; // doing any internal state management below - - case eBroadcastInternalStateControlPause: - control_only = true; - break; - - case eBroadcastInternalStateControlResume: - control_only = false; - break; - } - - continue; - } - else if (event_sp->GetType() == eBroadcastBitInterrupt) - { - if (m_public_state.GetValue() == eStateAttaching) - { - if (log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.", - __FUNCTION__, static_cast<void*>(this), - GetID()); - BroadcastEvent(eBroadcastBitInterrupt, nullptr); - } - else if(StateIsRunningState(m_last_broadcast_state)) - { - if (log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.", - __FUNCTION__, static_cast<void*>(this), - GetID()); - Error error = HaltPrivate(); - if (error.Fail() && log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") failed to halt the process: %s", - __FUNCTION__, static_cast<void*>(this), - GetID(), error.AsCString()); - // Halt should generate a stopped event. Make a note of the fact that we were - // doing the interrupt, so we can set the interrupted flag after we receive the - // event. We deliberately set this to true even if HaltPrivate failed, so that we - // can interrupt on the next natural stop. - interrupt_requested = true; - } - else - { - // This can happen when someone (e.g. Process::Halt) sees that we are running and - // sends an interrupt request, but the process actually stops before we receive - // it. In that case, we can just ignore the request. We use - // m_last_broadcast_state, because the Stopped event may not have been popped of - // the event queue yet, which is when the public state gets updated. - if (log) - log->Printf("Process::%s ignoring interrupt as we have already stopped.", __FUNCTION__); - } - continue; - } +thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) { + bool control_only = true; - const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", + __FUNCTION__, static_cast<void *>(this), GetID()); - if (internal_state != eStateInvalid) - { - if (m_clear_thread_plans_on_stop && - StateIsStoppedState(internal_state, true)) - { - m_clear_thread_plans_on_stop = false; - m_thread_list.DiscardThreadPlans(); - } + bool exit_now = false; + bool interrupt_requested = false; + while (!exit_now) { + EventSP event_sp; + WaitForEventsPrivate(std::chrono::microseconds(0), event_sp, control_only); + if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster)) { + if (log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 + ") got a control event: %d", + __FUNCTION__, static_cast<void *>(this), GetID(), + event_sp->GetType()); + + switch (event_sp->GetType()) { + case eBroadcastInternalStateControlStop: + exit_now = true; + break; // doing any internal state management below + + case eBroadcastInternalStateControlPause: + control_only = true; + break; + + case eBroadcastInternalStateControlResume: + control_only = false; + break; + } + + continue; + } else if (event_sp->GetType() == eBroadcastBitInterrupt) { + if (m_public_state.GetValue() == eStateAttaching) { + if (log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 + ") woke up with an interrupt while attaching - " + "forwarding interrupt.", + __FUNCTION__, static_cast<void *>(this), GetID()); + BroadcastEvent(eBroadcastBitInterrupt, nullptr); + } else if (StateIsRunningState(m_last_broadcast_state)) { + if (log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 + ") woke up with an interrupt - Halting.", + __FUNCTION__, static_cast<void *>(this), GetID()); + Error error = HaltPrivate(); + if (error.Fail() && log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 + ") failed to halt the process: %s", + __FUNCTION__, static_cast<void *>(this), GetID(), + error.AsCString()); + // Halt should generate a stopped event. Make a note of the fact that we + // were + // doing the interrupt, so we can set the interrupted flag after we + // receive the + // event. We deliberately set this to true even if HaltPrivate failed, + // so that we + // can interrupt on the next natural stop. + interrupt_requested = true; + } else { + // This can happen when someone (e.g. Process::Halt) sees that we are + // running and + // sends an interrupt request, but the process actually stops before we + // receive + // it. In that case, we can just ignore the request. We use + // m_last_broadcast_state, because the Stopped event may not have been + // popped of + // the event queue yet, which is when the public state gets updated. + if (log) + log->Printf( + "Process::%s ignoring interrupt as we have already stopped.", + __FUNCTION__); + } + continue; + } - if (interrupt_requested) - { - if (StateIsStoppedState (internal_state, true)) - { - // We requested the interrupt, so mark this as such in the stop event so - // clients can tell an interrupted process from a natural stop - ProcessEventData::SetInterruptedInEvent (event_sp.get(), true); - interrupt_requested = false; - } - else if (log) - { - log->Printf("Process::%s interrupt_requested, but a non-stopped state '%s' received.", - __FUNCTION__, StateAsCString(internal_state)); - } - } + const StateType internal_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - HandlePrivateEvent (event_sp); + if (internal_state != eStateInvalid) { + if (m_clear_thread_plans_on_stop && + StateIsStoppedState(internal_state, true)) { + m_clear_thread_plans_on_stop = false; + m_thread_list.DiscardThreadPlans(); + } + + if (interrupt_requested) { + if (StateIsStoppedState(internal_state, true)) { + // We requested the interrupt, so mark this as such in the stop event + // so + // clients can tell an interrupted process from a natural stop + ProcessEventData::SetInterruptedInEvent(event_sp.get(), true); + interrupt_requested = false; + } else if (log) { + log->Printf("Process::%s interrupt_requested, but a non-stopped " + "state '%s' received.", + __FUNCTION__, StateAsCString(internal_state)); } + } - if (internal_state == eStateInvalid || - internal_state == eStateExited || - internal_state == eStateDetached ) - { - if (log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...", - __FUNCTION__, static_cast<void*>(this), GetID(), - StateAsCString(internal_state)); + HandlePrivateEvent(event_sp); + } - break; - } + if (internal_state == eStateInvalid || internal_state == eStateExited || + internal_state == eStateDetached) { + if (log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 + ") about to exit with internal state %s...", + __FUNCTION__, static_cast<void *>(this), GetID(), + StateAsCString(internal_state)); + + break; } + } - // Verify log is still enabled before attempting to write to it... - if (log) - log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", - __FUNCTION__, static_cast<void*>(this), GetID()); + // Verify log is still enabled before attempting to write to it... + if (log) + log->Printf("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", + __FUNCTION__, static_cast<void *>(this), GetID()); - // If we are a secondary thread, then the primary thread we are working for will have already - // acquired the public_run_lock, and isn't done with what it was doing yet, so don't - // try to change it on the way out. - if (!is_secondary_thread) - m_public_run_lock.SetStopped(); - return NULL; + // If we are a secondary thread, then the primary thread we are working for + // will have already + // acquired the public_run_lock, and isn't done with what it was doing yet, so + // don't + // try to change it on the way out. + if (!is_secondary_thread) + m_public_run_lock.SetStopped(); + return NULL; } //------------------------------------------------------------------ // Process Event Data //------------------------------------------------------------------ -Process::ProcessEventData::ProcessEventData () : - EventData (), - m_process_wp (), - m_state (eStateInvalid), - m_restarted (false), - m_update_state (0), - m_interrupted (false) -{ -} +Process::ProcessEventData::ProcessEventData() + : EventData(), m_process_wp(), m_state(eStateInvalid), m_restarted(false), + m_update_state(0), m_interrupted(false) {} -Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) : - EventData (), - m_process_wp (), - m_state (state), - m_restarted (false), - m_update_state (0), - m_interrupted (false) -{ - if (process_sp) - m_process_wp = process_sp; +Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp, + StateType state) + : EventData(), m_process_wp(), m_state(state), m_restarted(false), + m_update_state(0), m_interrupted(false) { + if (process_sp) + m_process_wp = process_sp; } Process::ProcessEventData::~ProcessEventData() = default; -const ConstString & -Process::ProcessEventData::GetFlavorString () -{ - static ConstString g_flavor ("Process::ProcessEventData"); - return g_flavor; -} +const ConstString &Process::ProcessEventData::GetFlavorString() { + static ConstString g_flavor("Process::ProcessEventData"); + return g_flavor; +} + +const ConstString &Process::ProcessEventData::GetFlavor() const { + return ProcessEventData::GetFlavorString(); +} + +void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) { + ProcessSP process_sp(m_process_wp.lock()); + + if (!process_sp) + return; + + // This function gets called twice for each event, once when the event gets + // pulled + // off of the private process event queue, and then any number of times, first + // when it gets pulled off of + // the public event queue, then other times when we're pretending that this is + // where we stopped at the + // end of expression evaluation. m_update_state is used to distinguish these + // three cases; it is 0 when we're just pulling it off for private handling, + // and > 1 for expression evaluation, and we don't want to do the breakpoint + // command handling then. + if (m_update_state != 1) + return; + + process_sp->SetPublicState( + m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr)); + + // If this is a halt event, even if the halt stopped with some reason other + // than a plain interrupt (e.g. we had + // already stopped for a breakpoint when the halt request came through) don't + // do the StopInfo actions, as they may + // end up restarting the process. + if (m_interrupted) + return; + + // If we're stopped and haven't restarted, then do the StopInfo actions here: + if (m_state == eStateStopped && !m_restarted) { + // Let process subclasses know we are about to do a public stop and + // do anything they might need to in order to speed up register and + // memory accesses. + process_sp->WillPublicStop(); + + ThreadList &curr_thread_list = process_sp->GetThreadList(); + uint32_t num_threads = curr_thread_list.GetSize(); + uint32_t idx; + + // The actions might change one of the thread's stop_info's opinions about + // whether we should + // stop the process, so we need to query that as we go. + + // One other complication here, is that we try to catch any case where the + // target has run (except for expressions) + // and immediately exit, but if we get that wrong (which is possible) then + // the thread list might have changed, and + // that would cause our iteration here to crash. We could make a copy of + // the thread list, but we'd really like + // to also know if it has changed at all, so we make up a vector of the + // thread ID's and check what we get back + // against this list & bag out if anything differs. + std::vector<uint32_t> thread_index_array(num_threads); + for (idx = 0; idx < num_threads; ++idx) + thread_index_array[idx] = + curr_thread_list.GetThreadAtIndex(idx)->GetIndexID(); + + // Use this to track whether we should continue from here. We will only + // continue the target running if + // no thread says we should stop. Of course if some thread's PerformAction + // actually sets the target running, + // then it doesn't matter what the other threads say... + + bool still_should_stop = false; + + // Sometimes - for instance if we have a bug in the stub we are talking to, + // we stop but no thread has a + // valid stop reason. In that case we should just stop, because we have no + // way of telling what the right + // thing to do is, and it's better to let the user decide than continue + // behind their backs. + + bool does_anybody_have_an_opinion = false; + + for (idx = 0; idx < num_threads; ++idx) { + curr_thread_list = process_sp->GetThreadList(); + if (curr_thread_list.GetSize() != num_threads) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf( + "Number of threads changed from %u to %u while processing event.", + num_threads, curr_thread_list.GetSize()); + break; + } -const ConstString & -Process::ProcessEventData::GetFlavor () const -{ - return ProcessEventData::GetFlavorString (); -} + lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx); -void -Process::ProcessEventData::DoOnRemoval (Event *event_ptr) -{ - ProcessSP process_sp(m_process_wp.lock()); - - if (!process_sp) - return; - - // This function gets called twice for each event, once when the event gets pulled - // off of the private process event queue, and then any number of times, first when it gets pulled off of - // the public event queue, then other times when we're pretending that this is where we stopped at the - // end of expression evaluation. m_update_state is used to distinguish these - // three cases; it is 0 when we're just pulling it off for private handling, - // and > 1 for expression evaluation, and we don't want to do the breakpoint command handling then. - if (m_update_state != 1) - return; - - process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr)); - - // If this is a halt event, even if the halt stopped with some reason other than a plain interrupt (e.g. we had - // already stopped for a breakpoint when the halt request came through) don't do the StopInfo actions, as they may - // end up restarting the process. - if (m_interrupted) - return; - - // If we're stopped and haven't restarted, then do the StopInfo actions here: - if (m_state == eStateStopped && ! m_restarted) - { - // Let process subclasses know we are about to do a public stop and - // do anything they might need to in order to speed up register and - // memory accesses. - process_sp->WillPublicStop(); - - ThreadList &curr_thread_list = process_sp->GetThreadList(); - uint32_t num_threads = curr_thread_list.GetSize(); - uint32_t idx; - - // The actions might change one of the thread's stop_info's opinions about whether we should - // stop the process, so we need to query that as we go. - - // One other complication here, is that we try to catch any case where the target has run (except for expressions) - // and immediately exit, but if we get that wrong (which is possible) then the thread list might have changed, and - // that would cause our iteration here to crash. We could make a copy of the thread list, but we'd really like - // to also know if it has changed at all, so we make up a vector of the thread ID's and check what we get back - // against this list & bag out if anything differs. - std::vector<uint32_t> thread_index_array(num_threads); - for (idx = 0; idx < num_threads; ++idx) - thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetIndexID(); - - // Use this to track whether we should continue from here. We will only continue the target running if - // no thread says we should stop. Of course if some thread's PerformAction actually sets the target running, - // then it doesn't matter what the other threads say... - - bool still_should_stop = false; - - // Sometimes - for instance if we have a bug in the stub we are talking to, we stop but no thread has a - // valid stop reason. In that case we should just stop, because we have no way of telling what the right - // thing to do is, and it's better to let the user decide than continue behind their backs. - - bool does_anybody_have_an_opinion = false; - - for (idx = 0; idx < num_threads; ++idx) - { - curr_thread_list = process_sp->GetThreadList(); - if (curr_thread_list.GetSize() != num_threads) - { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Number of threads changed from %u to %u while processing event.", num_threads, curr_thread_list.GetSize()); - break; - } - - lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx); - - if (thread_sp->GetIndexID() != thread_index_array[idx]) - { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("The thread at position %u changed from %u to %u while processing event.", - idx, - thread_index_array[idx], - thread_sp->GetIndexID()); - break; - } - - StopInfoSP stop_info_sp = thread_sp->GetStopInfo (); - if (stop_info_sp && stop_info_sp->IsValid()) - { - does_anybody_have_an_opinion = true; - bool this_thread_wants_to_stop; - if (stop_info_sp->GetOverrideShouldStop()) - { - this_thread_wants_to_stop = stop_info_sp->GetOverriddenShouldStopValue(); - } - else - { - stop_info_sp->PerformAction(event_ptr); - // The stop action might restart the target. If it does, then we want to mark that in the - // event so that whoever is receiving it will know to wait for the running event and reflect - // that state appropriately. - // We also need to stop processing actions, since they aren't expecting the target to be running. - - // FIXME: we might have run. - if (stop_info_sp->HasTargetRunSinceMe()) - { - SetRestarted (true); - break; - } - - this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr); - } - - if (!still_should_stop) - still_should_stop = this_thread_wants_to_stop; - } - } - - if (!GetRestarted()) - { - if (!still_should_stop && does_anybody_have_an_opinion) - { - // We've been asked to continue, so do that here. - SetRestarted(true); - // Use the public resume method here, since this is just - // extending a public resume. - process_sp->PrivateResume(); - } - else - { - // If we didn't restart, run the Stop Hooks here: - // They might also restart the target, so watch for that. - process_sp->GetTarget().RunStopHooks(); - if (process_sp->GetPrivateState() == eStateRunning) - SetRestarted(true); - } + if (thread_sp->GetIndexID() != thread_index_array[idx]) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | + LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("The thread at position %u changed from %u to %u while " + "processing event.", + idx, thread_index_array[idx], thread_sp->GetIndexID()); + break; + } + + StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); + if (stop_info_sp && stop_info_sp->IsValid()) { + does_anybody_have_an_opinion = true; + bool this_thread_wants_to_stop; + if (stop_info_sp->GetOverrideShouldStop()) { + this_thread_wants_to_stop = + stop_info_sp->GetOverriddenShouldStopValue(); + } else { + stop_info_sp->PerformAction(event_ptr); + // The stop action might restart the target. If it does, then we want + // to mark that in the + // event so that whoever is receiving it will know to wait for the + // running event and reflect + // that state appropriately. + // We also need to stop processing actions, since they aren't + // expecting the target to be running. + + // FIXME: we might have run. + if (stop_info_sp->HasTargetRunSinceMe()) { + SetRestarted(true); + break; + } + + this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr); } + + if (!still_should_stop) + still_should_stop = this_thread_wants_to_stop; + } + } + + if (!GetRestarted()) { + if (!still_should_stop && does_anybody_have_an_opinion) { + // We've been asked to continue, so do that here. + SetRestarted(true); + // Use the public resume method here, since this is just + // extending a public resume. + process_sp->PrivateResume(); + } else { + // If we didn't restart, run the Stop Hooks here: + // They might also restart the target, so watch for that. + process_sp->GetTarget().RunStopHooks(); + if (process_sp->GetPrivateState() == eStateRunning) + SetRestarted(true); + } } + } } -void -Process::ProcessEventData::Dump (Stream *s) const -{ - ProcessSP process_sp(m_process_wp.lock()); +void Process::ProcessEventData::Dump(Stream *s) const { + ProcessSP process_sp(m_process_wp.lock()); - if (process_sp) - s->Printf(" process = %p (pid = %" PRIu64 "), ", - static_cast<void*>(process_sp.get()), process_sp->GetID()); - else - s->PutCString(" process = NULL, "); + if (process_sp) + s->Printf(" process = %p (pid = %" PRIu64 "), ", + static_cast<void *>(process_sp.get()), process_sp->GetID()); + else + s->PutCString(" process = NULL, "); - s->Printf("state = %s", StateAsCString(GetState())); + s->Printf("state = %s", StateAsCString(GetState())); } const Process::ProcessEventData * -Process::ProcessEventData::GetEventDataFromEvent (const Event *event_ptr) -{ - if (event_ptr) - { - const EventData *event_data = event_ptr->GetData(); - if (event_data && event_data->GetFlavor() == ProcessEventData::GetFlavorString()) - return static_cast <const ProcessEventData *> (event_ptr->GetData()); - } - return nullptr; +Process::ProcessEventData::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr) { + const EventData *event_data = event_ptr->GetData(); + if (event_data && + event_data->GetFlavor() == ProcessEventData::GetFlavorString()) + return static_cast<const ProcessEventData *>(event_ptr->GetData()); + } + return nullptr; } ProcessSP -Process::ProcessEventData::GetProcessFromEvent (const Event *event_ptr) -{ - ProcessSP process_sp; - const ProcessEventData *data = GetEventDataFromEvent (event_ptr); - if (data) - process_sp = data->GetProcessSP(); - return process_sp; +Process::ProcessEventData::GetProcessFromEvent(const Event *event_ptr) { + ProcessSP process_sp; + const ProcessEventData *data = GetEventDataFromEvent(event_ptr); + if (data) + process_sp = data->GetProcessSP(); + return process_sp; } -StateType -Process::ProcessEventData::GetStateFromEvent (const Event *event_ptr) -{ - const ProcessEventData *data = GetEventDataFromEvent (event_ptr); - if (data == nullptr) - return eStateInvalid; - else - return data->GetState(); +StateType Process::ProcessEventData::GetStateFromEvent(const Event *event_ptr) { + const ProcessEventData *data = GetEventDataFromEvent(event_ptr); + if (data == nullptr) + return eStateInvalid; + else + return data->GetState(); } -bool -Process::ProcessEventData::GetRestartedFromEvent (const Event *event_ptr) -{ - const ProcessEventData *data = GetEventDataFromEvent (event_ptr); - if (data == nullptr) - return false; - else - return data->GetRestarted(); +bool Process::ProcessEventData::GetRestartedFromEvent(const Event *event_ptr) { + const ProcessEventData *data = GetEventDataFromEvent(event_ptr); + if (data == nullptr) + return false; + else + return data->GetRestarted(); } -void -Process::ProcessEventData::SetRestartedInEvent (Event *event_ptr, bool new_value) -{ - ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); - if (data != nullptr) - data->SetRestarted(new_value); +void Process::ProcessEventData::SetRestartedInEvent(Event *event_ptr, + bool new_value) { + ProcessEventData *data = + const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr)); + if (data != nullptr) + data->SetRestarted(new_value); } size_t -Process::ProcessEventData::GetNumRestartedReasons(const Event *event_ptr) -{ - ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); - if (data != nullptr) - return data->GetNumRestartedReasons(); - else - return 0; +Process::ProcessEventData::GetNumRestartedReasons(const Event *event_ptr) { + ProcessEventData *data = + const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr)); + if (data != nullptr) + return data->GetNumRestartedReasons(); + else + return 0; } const char * -Process::ProcessEventData::GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx) -{ - ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); - if (data != nullptr) - return data->GetRestartedReasonAtIndex(idx); - else - return nullptr; +Process::ProcessEventData::GetRestartedReasonAtIndex(const Event *event_ptr, + size_t idx) { + ProcessEventData *data = + const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr)); + if (data != nullptr) + return data->GetRestartedReasonAtIndex(idx); + else + return nullptr; } -void -Process::ProcessEventData::AddRestartedReason (Event *event_ptr, const char *reason) -{ - ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); - if (data != nullptr) - data->AddRestartedReason(reason); +void Process::ProcessEventData::AddRestartedReason(Event *event_ptr, + const char *reason) { + ProcessEventData *data = + const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr)); + if (data != nullptr) + data->AddRestartedReason(reason); } -bool -Process::ProcessEventData::GetInterruptedFromEvent (const Event *event_ptr) -{ - const ProcessEventData *data = GetEventDataFromEvent (event_ptr); - if (data == nullptr) - return false; - else - return data->GetInterrupted (); +bool Process::ProcessEventData::GetInterruptedFromEvent( + const Event *event_ptr) { + const ProcessEventData *data = GetEventDataFromEvent(event_ptr); + if (data == nullptr) + return false; + else + return data->GetInterrupted(); } -void -Process::ProcessEventData::SetInterruptedInEvent (Event *event_ptr, bool new_value) -{ - ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); - if (data != nullptr) - data->SetInterrupted(new_value); +void Process::ProcessEventData::SetInterruptedInEvent(Event *event_ptr, + bool new_value) { + ProcessEventData *data = + const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr)); + if (data != nullptr) + data->SetInterrupted(new_value); } -bool -Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr) -{ - ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr)); - if (data) - { - data->SetUpdateStateOnRemoval(); - return true; - } - return false; +bool Process::ProcessEventData::SetUpdateStateOnRemoval(Event *event_ptr) { + ProcessEventData *data = + const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr)); + if (data) { + data->SetUpdateStateOnRemoval(); + return true; + } + return false; } -lldb::TargetSP -Process::CalculateTarget () -{ - return m_target_sp.lock(); -} +lldb::TargetSP Process::CalculateTarget() { return m_target_sp.lock(); } -void -Process::CalculateExecutionContext (ExecutionContext &exe_ctx) -{ - exe_ctx.SetTargetPtr (&GetTarget()); - exe_ctx.SetProcessPtr (this); - exe_ctx.SetThreadPtr(nullptr); - exe_ctx.SetFramePtr(nullptr); +void Process::CalculateExecutionContext(ExecutionContext &exe_ctx) { + exe_ctx.SetTargetPtr(&GetTarget()); + exe_ctx.SetProcessPtr(this); + exe_ctx.SetThreadPtr(nullptr); + exe_ctx.SetFramePtr(nullptr); } -//uint32_t -//Process::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids) +// uint32_t +// Process::ListProcessesMatchingName (const char *name, StringList &matches, +// std::vector<lldb::pid_t> &pids) //{ // return 0; //} -// -//ArchSpec -//Process::GetArchSpecForExistingProcess (lldb::pid_t pid) +// +// ArchSpec +// Process::GetArchSpecForExistingProcess (lldb::pid_t pid) //{ // return Host::GetArchSpecForExistingProcess (pid); //} // -//ArchSpec -//Process::GetArchSpecForExistingProcess (const char *process_name) +// ArchSpec +// Process::GetArchSpecForExistingProcess (const char *process_name) //{ // return Host::GetArchSpecForExistingProcess (process_name); //} -void -Process::AppendSTDOUT (const char * s, size_t len) -{ - std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); - m_stdout_data.append (s, len); - BroadcastEventIfUnique (eBroadcastBitSTDOUT, new ProcessEventData (shared_from_this(), GetState())); +void Process::AppendSTDOUT(const char *s, size_t len) { + std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); + m_stdout_data.append(s, len); + BroadcastEventIfUnique(eBroadcastBitSTDOUT, + new ProcessEventData(shared_from_this(), GetState())); } -void -Process::AppendSTDERR (const char * s, size_t len) -{ - std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); - m_stderr_data.append (s, len); - BroadcastEventIfUnique (eBroadcastBitSTDERR, new ProcessEventData (shared_from_this(), GetState())); +void Process::AppendSTDERR(const char *s, size_t len) { + std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); + m_stderr_data.append(s, len); + BroadcastEventIfUnique(eBroadcastBitSTDERR, + new ProcessEventData(shared_from_this(), GetState())); } -void -Process::BroadcastAsyncProfileData(const std::string &one_profile_data) -{ - std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex); - m_profile_data.push_back(one_profile_data); - BroadcastEventIfUnique (eBroadcastBitProfileData, new ProcessEventData (shared_from_this(), GetState())); +void Process::BroadcastAsyncProfileData(const std::string &one_profile_data) { + std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex); + m_profile_data.push_back(one_profile_data); + BroadcastEventIfUnique(eBroadcastBitProfileData, + new ProcessEventData(shared_from_this(), GetState())); } -void -Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, - const StructuredDataPluginSP &plugin_sp) -{ - BroadcastEvent(eBroadcastBitStructuredData, - new EventDataStructuredData(shared_from_this(), - object_sp, plugin_sp)); +void Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp, + const StructuredDataPluginSP &plugin_sp) { + BroadcastEvent( + eBroadcastBitStructuredData, + new EventDataStructuredData(shared_from_this(), object_sp, plugin_sp)); } StructuredDataPluginSP -Process::GetStructuredDataPlugin(const ConstString &type_name) const -{ - auto find_it = m_structured_data_plugin_map.find(type_name); - if (find_it != m_structured_data_plugin_map.end()) - return find_it->second; - else - return StructuredDataPluginSP(); +Process::GetStructuredDataPlugin(const ConstString &type_name) const { + auto find_it = m_structured_data_plugin_map.find(type_name); + if (find_it != m_structured_data_plugin_map.end()) + return find_it->second; + else + return StructuredDataPluginSP(); } -size_t -Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error) -{ - std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex); - if (m_profile_data.empty()) - return 0; - - std::string &one_profile_data = m_profile_data.front(); - size_t bytes_available = one_profile_data.size(); - if (bytes_available > 0) - { - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", - static_cast<void*>(buf), - static_cast<uint64_t>(buf_size)); - if (bytes_available > buf_size) - { - memcpy(buf, one_profile_data.c_str(), buf_size); - one_profile_data.erase(0, buf_size); - bytes_available = buf_size; - } - else - { - memcpy(buf, one_profile_data.c_str(), bytes_available); - m_profile_data.erase(m_profile_data.begin()); - } +size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Error &error) { + std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex); + if (m_profile_data.empty()) + return 0; + + std::string &one_profile_data = m_profile_data.front(); + size_t bytes_available = one_profile_data.size(); + if (bytes_available > 0) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", + static_cast<void *>(buf), static_cast<uint64_t>(buf_size)); + if (bytes_available > buf_size) { + memcpy(buf, one_profile_data.c_str(), buf_size); + one_profile_data.erase(0, buf_size); + bytes_available = buf_size; + } else { + memcpy(buf, one_profile_data.c_str(), bytes_available); + m_profile_data.erase(m_profile_data.begin()); } - return bytes_available; + } + return bytes_available; } //------------------------------------------------------------------ // Process STDIO //------------------------------------------------------------------ -size_t -Process::GetSTDOUT (char *buf, size_t buf_size, Error &error) -{ - std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); - size_t bytes_available = m_stdout_data.size(); - if (bytes_available > 0) - { - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", - static_cast<void*>(buf), - static_cast<uint64_t>(buf_size)); - if (bytes_available > buf_size) - { - memcpy(buf, m_stdout_data.c_str(), buf_size); - m_stdout_data.erase(0, buf_size); - bytes_available = buf_size; - } - else - { - memcpy(buf, m_stdout_data.c_str(), bytes_available); - m_stdout_data.clear(); - } - } - return bytes_available; -} - -size_t -Process::GetSTDERR (char *buf, size_t buf_size, Error &error) -{ - std::lock_guard<std::recursive_mutex> gaurd(m_stdio_communication_mutex); - size_t bytes_available = m_stderr_data.size(); - if (bytes_available > 0) - { - Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", - static_cast<void*>(buf), - static_cast<uint64_t>(buf_size)); - if (bytes_available > buf_size) - { - memcpy(buf, m_stderr_data.c_str(), buf_size); - m_stderr_data.erase(0, buf_size); - bytes_available = buf_size; - } - else - { - memcpy(buf, m_stderr_data.c_str(), bytes_available); - m_stderr_data.clear(); - } +size_t Process::GetSTDOUT(char *buf, size_t buf_size, Error &error) { + std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex); + size_t bytes_available = m_stdout_data.size(); + if (bytes_available > 0) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", + static_cast<void *>(buf), static_cast<uint64_t>(buf_size)); + if (bytes_available > buf_size) { + memcpy(buf, m_stdout_data.c_str(), buf_size); + m_stdout_data.erase(0, buf_size); + bytes_available = buf_size; + } else { + memcpy(buf, m_stdout_data.c_str(), bytes_available); + m_stdout_data.clear(); + } + } + return bytes_available; +} + +size_t Process::GetSTDERR(char *buf, size_t buf_size, Error &error) { + std::lock_guard<std::recursive_mutex> gaurd(m_stdio_communication_mutex); + size_t bytes_available = m_stderr_data.size(); + if (bytes_available > 0) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", + static_cast<void *>(buf), static_cast<uint64_t>(buf_size)); + if (bytes_available > buf_size) { + memcpy(buf, m_stderr_data.c_str(), buf_size); + m_stderr_data.erase(0, buf_size); + bytes_available = buf_size; + } else { + memcpy(buf, m_stderr_data.c_str(), bytes_available); + m_stderr_data.clear(); } - return bytes_available; + } + return bytes_available; } -void -Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len) -{ - Process *process = (Process *) baton; - process->AppendSTDOUT (static_cast<const char *>(src), src_len); +void Process::STDIOReadThreadBytesReceived(void *baton, const void *src, + size_t src_len) { + Process *process = (Process *)baton; + process->AppendSTDOUT(static_cast<const char *>(src), src_len); } -class IOHandlerProcessSTDIO : - public IOHandler -{ +class IOHandlerProcessSTDIO : public IOHandler { public: - IOHandlerProcessSTDIO (Process *process, - int write_fd) : - IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO), - m_process (process), - m_read_file (), - m_write_file (write_fd, false), - m_pipe () - { - m_pipe.CreateNew(false); - m_read_file.SetDescriptor(GetInputFD(), false); - } - - ~IOHandlerProcessSTDIO() override = default; - - // Each IOHandler gets to run until it is done. It should read data - // from the "in" and place output into "out" and "err and return - // when done. - void - Run () override - { - if (!m_read_file.IsValid() || !m_write_file.IsValid() || !m_pipe.CanRead() || !m_pipe.CanWrite()) - { - SetIsDone(true); - return; - } - - SetIsDone(false); - const int read_fd = m_read_file.GetDescriptor(); - TerminalState terminal_state; - terminal_state.Save (read_fd, false); - Terminal terminal(read_fd); - terminal.SetCanonical(false); - terminal.SetEcho(false); + IOHandlerProcessSTDIO(Process *process, int write_fd) + : IOHandler(process->GetTarget().GetDebugger(), + IOHandler::Type::ProcessIO), + m_process(process), m_read_file(), m_write_file(write_fd, false), + m_pipe() { + m_pipe.CreateNew(false); + m_read_file.SetDescriptor(GetInputFD(), false); + } + + ~IOHandlerProcessSTDIO() override = default; + + // Each IOHandler gets to run until it is done. It should read data + // from the "in" and place output into "out" and "err and return + // when done. + void Run() override { + if (!m_read_file.IsValid() || !m_write_file.IsValid() || + !m_pipe.CanRead() || !m_pipe.CanWrite()) { + SetIsDone(true); + return; + } + + SetIsDone(false); + const int read_fd = m_read_file.GetDescriptor(); + TerminalState terminal_state; + terminal_state.Save(read_fd, false); + Terminal terminal(read_fd); + terminal.SetCanonical(false); + terminal.SetEcho(false); // FD_ZERO, FD_SET are not supported on windows #ifndef _WIN32 - const int pipe_read_fd = m_pipe.GetReadFileDescriptor(); - m_is_running = true; - while (!GetIsDone()) - { - SelectHelper select_helper; - select_helper.FDSetRead(read_fd); - select_helper.FDSetRead(pipe_read_fd); - Error error = select_helper.Select(); - - if (error.Fail()) - { - SetIsDone(true); - } - else - { - char ch = 0; - size_t n; - if (select_helper.FDIsSetRead(read_fd)) - { - n = 1; - if (m_read_file.Read(&ch, n).Success() && n == 1) - { - if (m_write_file.Write(&ch, n).Fail() || n != 1) - SetIsDone(true); - } - else - SetIsDone(true); - } - if (select_helper.FDIsSetRead(pipe_read_fd)) - { - size_t bytes_read; - // Consume the interrupt byte - Error error = m_pipe.Read(&ch, 1, bytes_read); - if (error.Success()) - { - switch (ch) - { - case 'q': - SetIsDone(true); - break; - case 'i': - if (StateIsRunningState(m_process->GetState())) - m_process->SendAsyncInterrupt(); - break; - } - } - } - } - } - m_is_running = false; -#endif - terminal_state.Restore(); - } - - void - Cancel () override - { + const int pipe_read_fd = m_pipe.GetReadFileDescriptor(); + m_is_running = true; + while (!GetIsDone()) { + SelectHelper select_helper; + select_helper.FDSetRead(read_fd); + select_helper.FDSetRead(pipe_read_fd); + Error error = select_helper.Select(); + + if (error.Fail()) { SetIsDone(true); - // Only write to our pipe to cancel if we are in IOHandlerProcessSTDIO::Run(). - // We can end up with a python command that is being run from the command - // interpreter: - // - // (lldb) step_process_thousands_of_times - // - // In this case the command interpreter will be in the middle of handling - // the command and if the process pushes and pops the IOHandler thousands - // of times, we can end up writing to m_pipe without ever consuming the - // bytes from the pipe in IOHandlerProcessSTDIO::Run() and end up - // deadlocking when the pipe gets fed up and blocks until data is consumed. - if (m_is_running) - { - char ch = 'q'; // Send 'q' for quit - size_t bytes_written = 0; - m_pipe.Write(&ch, 1, bytes_written); - } - } - - bool - Interrupt () override - { - // Do only things that are safe to do in an interrupt context (like in - // a SIGINT handler), like write 1 byte to a file descriptor. This will - // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte - // that was written to the pipe and then call m_process->SendAsyncInterrupt() - // from a much safer location in code. - if (m_active) - { - char ch = 'i'; // Send 'i' for interrupt - size_t bytes_written = 0; - Error result = m_pipe.Write(&ch, 1, bytes_written); - return result.Success(); + } else { + char ch = 0; + size_t n; + if (select_helper.FDIsSetRead(read_fd)) { + n = 1; + if (m_read_file.Read(&ch, n).Success() && n == 1) { + if (m_write_file.Write(&ch, n).Fail() || n != 1) + SetIsDone(true); + } else + SetIsDone(true); } - else - { - // This IOHandler might be pushed on the stack, but not being run currently - // so do the right thing if we aren't actively watching for STDIN by sending - // the interrupt to the process. Otherwise the write to the pipe above would - // do nothing. This can happen when the command interpreter is running and - // gets a "expression ...". It will be on the IOHandler thread and sending - // the input is complete to the delegate which will cause the expression to - // run, which will push the process IO handler, but not run it. - - if (StateIsRunningState(m_process->GetState())) - { + if (select_helper.FDIsSetRead(pipe_read_fd)) { + size_t bytes_read; + // Consume the interrupt byte + Error error = m_pipe.Read(&ch, 1, bytes_read); + if (error.Success()) { + switch (ch) { + case 'q': + SetIsDone(true); + break; + case 'i': + if (StateIsRunningState(m_process->GetState())) m_process->SendAsyncInterrupt(); - return true; + break; } + } } - return false; + } } - - void - GotEOF() override - { + m_is_running = false; +#endif + terminal_state.Restore(); + } + + void Cancel() override { + SetIsDone(true); + // Only write to our pipe to cancel if we are in + // IOHandlerProcessSTDIO::Run(). + // We can end up with a python command that is being run from the command + // interpreter: + // + // (lldb) step_process_thousands_of_times + // + // In this case the command interpreter will be in the middle of handling + // the command and if the process pushes and pops the IOHandler thousands + // of times, we can end up writing to m_pipe without ever consuming the + // bytes from the pipe in IOHandlerProcessSTDIO::Run() and end up + // deadlocking when the pipe gets fed up and blocks until data is consumed. + if (m_is_running) { + char ch = 'q'; // Send 'q' for quit + size_t bytes_written = 0; + m_pipe.Write(&ch, 1, bytes_written); + } + } + + bool Interrupt() override { + // Do only things that are safe to do in an interrupt context (like in + // a SIGINT handler), like write 1 byte to a file descriptor. This will + // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte + // that was written to the pipe and then call + // m_process->SendAsyncInterrupt() + // from a much safer location in code. + if (m_active) { + char ch = 'i'; // Send 'i' for interrupt + size_t bytes_written = 0; + Error result = m_pipe.Write(&ch, 1, bytes_written); + return result.Success(); + } else { + // This IOHandler might be pushed on the stack, but not being run + // currently + // so do the right thing if we aren't actively watching for STDIN by + // sending + // the interrupt to the process. Otherwise the write to the pipe above + // would + // do nothing. This can happen when the command interpreter is running and + // gets a "expression ...". It will be on the IOHandler thread and sending + // the input is complete to the delegate which will cause the expression + // to + // run, which will push the process IO handler, but not run it. + + if (StateIsRunningState(m_process->GetState())) { + m_process->SendAsyncInterrupt(); + return true; + } } - + return false; + } + + void GotEOF() override {} + protected: - Process *m_process; - File m_read_file; // Read from this file (usually actual STDIN for LLDB - File m_write_file; // Write to this file (usually the master pty for getting io to debuggee) - Pipe m_pipe; - std::atomic<bool> m_is_running; + Process *m_process; + File m_read_file; // Read from this file (usually actual STDIN for LLDB + File m_write_file; // Write to this file (usually the master pty for getting + // io to debuggee) + Pipe m_pipe; + std::atomic<bool> m_is_running; }; -void -Process::SetSTDIOFileDescriptor (int fd) -{ - // First set up the Read Thread for reading/handling process I/O - - std::unique_ptr<ConnectionFileDescriptor> conn_ap (new ConnectionFileDescriptor (fd, true)); - - if (conn_ap) - { - m_stdio_communication.SetConnection (conn_ap.release()); - if (m_stdio_communication.IsConnected()) - { - m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this); - m_stdio_communication.StartReadThread(); - - // Now read thread is set up, set up input reader. - - if (!m_process_input_reader) - m_process_input_reader.reset (new IOHandlerProcessSTDIO (this, fd)); - } +void Process::SetSTDIOFileDescriptor(int fd) { + // First set up the Read Thread for reading/handling process I/O + + std::unique_ptr<ConnectionFileDescriptor> conn_ap( + new ConnectionFileDescriptor(fd, true)); + + if (conn_ap) { + m_stdio_communication.SetConnection(conn_ap.release()); + if (m_stdio_communication.IsConnected()) { + m_stdio_communication.SetReadThreadBytesReceivedCallback( + STDIOReadThreadBytesReceived, this); + m_stdio_communication.StartReadThread(); + + // Now read thread is set up, set up input reader. + + if (!m_process_input_reader) + m_process_input_reader.reset(new IOHandlerProcessSTDIO(this, fd)); } + } } -bool -Process::ProcessIOHandlerIsActive () -{ - IOHandlerSP io_handler_sp (m_process_input_reader); - if (io_handler_sp) - return GetTarget().GetDebugger().IsTopIOHandler (io_handler_sp); - return false; +bool Process::ProcessIOHandlerIsActive() { + IOHandlerSP io_handler_sp(m_process_input_reader); + if (io_handler_sp) + return GetTarget().GetDebugger().IsTopIOHandler(io_handler_sp); + return false; } -bool -Process::PushProcessIOHandler () -{ - IOHandlerSP io_handler_sp (m_process_input_reader); - if (io_handler_sp) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::%s pushing IO handler", __FUNCTION__); +bool Process::PushProcessIOHandler() { + IOHandlerSP io_handler_sp(m_process_input_reader); + if (io_handler_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::%s pushing IO handler", __FUNCTION__); - io_handler_sp->SetIsDone(false); - GetTarget().GetDebugger().PushIOHandler (io_handler_sp); - return true; - } - return false; + io_handler_sp->SetIsDone(false); + GetTarget().GetDebugger().PushIOHandler(io_handler_sp); + return true; + } + return false; } -bool -Process::PopProcessIOHandler () -{ - IOHandlerSP io_handler_sp (m_process_input_reader); - if (io_handler_sp) - return GetTarget().GetDebugger().PopIOHandler (io_handler_sp); - return false; +bool Process::PopProcessIOHandler() { + IOHandlerSP io_handler_sp(m_process_input_reader); + if (io_handler_sp) + return GetTarget().GetDebugger().PopIOHandler(io_handler_sp); + return false; } // The process needs to know about installed plug-ins -void -Process::SettingsInitialize () -{ - Thread::SettingsInitialize (); -} +void Process::SettingsInitialize() { Thread::SettingsInitialize(); } -void -Process::SettingsTerminate () -{ - Thread::SettingsTerminate (); -} +void Process::SettingsTerminate() { Thread::SettingsTerminate(); } -namespace -{ - // RestorePlanState is used to record the "is private", "is master" and "okay to discard" fields of - // the plan we are running, and reset it on Clean or on destruction. - // It will only reset the state once, so you can call Clean and then monkey with the state and it - // won't get reset on you again. - - class RestorePlanState - { - public: - RestorePlanState (lldb::ThreadPlanSP thread_plan_sp) : - m_thread_plan_sp(thread_plan_sp), - m_already_reset(false) - { - if (m_thread_plan_sp) - { - m_private = m_thread_plan_sp->GetPrivate(); - m_is_master = m_thread_plan_sp->IsMasterPlan(); - m_okay_to_discard = m_thread_plan_sp->OkayToDiscard(); - } - } - - ~RestorePlanState() - { - Clean(); - } - - void - Clean () - { - if (!m_already_reset && m_thread_plan_sp) - { - m_already_reset = true; - m_thread_plan_sp->SetPrivate(m_private); - m_thread_plan_sp->SetIsMasterPlan (m_is_master); - m_thread_plan_sp->SetOkayToDiscard(m_okay_to_discard); - } - } +namespace { +// RestorePlanState is used to record the "is private", "is master" and "okay to +// discard" fields of +// the plan we are running, and reset it on Clean or on destruction. +// It will only reset the state once, so you can call Clean and then monkey with +// the state and it +// won't get reset on you again. - private: - lldb::ThreadPlanSP m_thread_plan_sp; - bool m_already_reset; - bool m_private; - bool m_is_master; - bool m_okay_to_discard; - }; +class RestorePlanState { +public: + RestorePlanState(lldb::ThreadPlanSP thread_plan_sp) + : m_thread_plan_sp(thread_plan_sp), m_already_reset(false) { + if (m_thread_plan_sp) { + m_private = m_thread_plan_sp->GetPrivate(); + m_is_master = m_thread_plan_sp->IsMasterPlan(); + m_okay_to_discard = m_thread_plan_sp->OkayToDiscard(); + } + } + + ~RestorePlanState() { Clean(); } + + void Clean() { + if (!m_already_reset && m_thread_plan_sp) { + m_already_reset = true; + m_thread_plan_sp->SetPrivate(m_private); + m_thread_plan_sp->SetIsMasterPlan(m_is_master); + m_thread_plan_sp->SetOkayToDiscard(m_okay_to_discard); + } + } + +private: + lldb::ThreadPlanSP m_thread_plan_sp; + bool m_already_reset; + bool m_private; + bool m_is_master; + bool m_okay_to_discard; +}; } // anonymous namespace ExpressionResults -Process::RunThreadPlan(ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp, - const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager) -{ - ExpressionResults return_value = eExpressionSetupError; - - std::lock_guard<std::mutex> run_thread_plan_locker(m_run_thread_plan_lock); - - if (!thread_plan_sp) - { - diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called with empty thread plan."); - return eExpressionSetupError; - } - - if (!thread_plan_sp->ValidatePlan(nullptr)) - { - diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called with an invalid thread plan."); - return eExpressionSetupError; - } - - if (exe_ctx.GetProcessPtr() != this) - { - diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called on wrong process."); - return eExpressionSetupError; - } - - Thread *thread = exe_ctx.GetThreadPtr(); - if (thread == nullptr) - { - diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called with invalid thread."); - return eExpressionSetupError; - } - - // We need to change some of the thread plan attributes for the thread plan runner. This will restore them - // when we are done: - - RestorePlanState thread_plan_restorer(thread_plan_sp); - - // We rely on the thread plan we are running returning "PlanCompleted" if when it successfully completes. - // For that to be true the plan can't be private - since private plans suppress themselves in the - // GetCompletedPlan call. - - thread_plan_sp->SetPrivate(false); - - // The plans run with RunThreadPlan also need to be terminal master plans or when they are done we will end - // up asking the plan above us whether we should stop, which may give the wrong answer. - - thread_plan_sp->SetIsMasterPlan (true); - thread_plan_sp->SetOkayToDiscard(false); - - if (m_private_state.GetValue() != eStateStopped) - { - diagnostic_manager.PutCString(eDiagnosticSeverityError, - "RunThreadPlan called while the private state was not stopped."); - return eExpressionSetupError; - } - - // Save the thread & frame from the exe_ctx for restoration after we run - const uint32_t thread_idx_id = thread->GetIndexID(); - StackFrameSP selected_frame_sp = thread->GetSelectedFrame(); - if (!selected_frame_sp) - { - thread->SetSelectedFrame(nullptr); - selected_frame_sp = thread->GetSelectedFrame(); - if (!selected_frame_sp) - { - diagnostic_manager.Printf(eDiagnosticSeverityError, - "RunThreadPlan called without a selected frame on thread %d", thread_idx_id); +Process::RunThreadPlan(ExecutionContext &exe_ctx, + lldb::ThreadPlanSP &thread_plan_sp, + const EvaluateExpressionOptions &options, + DiagnosticManager &diagnostic_manager) { + ExpressionResults return_value = eExpressionSetupError; + + std::lock_guard<std::mutex> run_thread_plan_locker(m_run_thread_plan_lock); + + if (!thread_plan_sp) { + diagnostic_manager.PutCString( + eDiagnosticSeverityError, + "RunThreadPlan called with empty thread plan."); + return eExpressionSetupError; + } + + if (!thread_plan_sp->ValidatePlan(nullptr)) { + diagnostic_manager.PutCString( + eDiagnosticSeverityError, + "RunThreadPlan called with an invalid thread plan."); + return eExpressionSetupError; + } + + if (exe_ctx.GetProcessPtr() != this) { + diagnostic_manager.PutCString(eDiagnosticSeverityError, + "RunThreadPlan called on wrong process."); + return eExpressionSetupError; + } + + Thread *thread = exe_ctx.GetThreadPtr(); + if (thread == nullptr) { + diagnostic_manager.PutCString(eDiagnosticSeverityError, + "RunThreadPlan called with invalid thread."); + return eExpressionSetupError; + } + + // We need to change some of the thread plan attributes for the thread plan + // runner. This will restore them + // when we are done: + + RestorePlanState thread_plan_restorer(thread_plan_sp); + + // We rely on the thread plan we are running returning "PlanCompleted" if when + // it successfully completes. + // For that to be true the plan can't be private - since private plans + // suppress themselves in the + // GetCompletedPlan call. + + thread_plan_sp->SetPrivate(false); + + // The plans run with RunThreadPlan also need to be terminal master plans or + // when they are done we will end + // up asking the plan above us whether we should stop, which may give the + // wrong answer. + + thread_plan_sp->SetIsMasterPlan(true); + thread_plan_sp->SetOkayToDiscard(false); + + if (m_private_state.GetValue() != eStateStopped) { + diagnostic_manager.PutCString( + eDiagnosticSeverityError, + "RunThreadPlan called while the private state was not stopped."); + return eExpressionSetupError; + } + + // Save the thread & frame from the exe_ctx for restoration after we run + const uint32_t thread_idx_id = thread->GetIndexID(); + StackFrameSP selected_frame_sp = thread->GetSelectedFrame(); + if (!selected_frame_sp) { + thread->SetSelectedFrame(nullptr); + selected_frame_sp = thread->GetSelectedFrame(); + if (!selected_frame_sp) { + diagnostic_manager.Printf( + eDiagnosticSeverityError, + "RunThreadPlan called without a selected frame on thread %d", + thread_idx_id); + return eExpressionSetupError; + } + } + + StackID ctx_frame_id = selected_frame_sp->GetStackID(); + + // N.B. Running the target may unset the currently selected thread and frame. + // We don't want to do that either, + // so we should arrange to reset them as well. + + lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread(); + + uint32_t selected_tid; + StackID selected_stack_id; + if (selected_thread_sp) { + selected_tid = selected_thread_sp->GetIndexID(); + selected_stack_id = selected_thread_sp->GetSelectedFrame()->GetStackID(); + } else { + selected_tid = LLDB_INVALID_THREAD_ID; + } + + HostThread backup_private_state_thread; + lldb::StateType old_state = eStateInvalid; + lldb::ThreadPlanSP stopper_base_plan_sp; + + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | + LIBLLDB_LOG_PROCESS)); + if (m_private_state_thread.EqualsThread(Host::GetCurrentThread())) { + // Yikes, we are running on the private state thread! So we can't wait for + // public events on this thread, since + // we are the thread that is generating public events. + // The simplest thing to do is to spin up a temporary thread to handle + // private state thread events while + // we are fielding public events here. + if (log) + log->Printf("Running thread plan on private state thread, spinning up " + "another state thread to handle the events."); + + backup_private_state_thread = m_private_state_thread; + + // One other bit of business: we want to run just this thread plan and + // anything it pushes, and then stop, + // returning control here. + // But in the normal course of things, the plan above us on the stack would + // be given a shot at the stop + // event before deciding to stop, and we don't want that. So we insert a + // "stopper" base plan on the stack + // before the plan we want to run. Since base plans always stop and return + // control to the user, that will + // do just what we want. + stopper_base_plan_sp.reset(new ThreadPlanBase(*thread)); + thread->QueueThreadPlan(stopper_base_plan_sp, false); + // Have to make sure our public state is stopped, since otherwise the + // reporting logic below doesn't work correctly. + old_state = m_public_state.GetValue(); + m_public_state.SetValueNoLock(eStateStopped); + + // Now spin up the private state thread: + StartPrivateStateThread(true); + } + + thread->QueueThreadPlan( + thread_plan_sp, false); // This used to pass "true" does that make sense? + + if (options.GetDebug()) { + // In this case, we aren't actually going to run, we just want to stop right + // away. + // Flush this thread so we will refetch the stacks and show the correct + // backtrace. + // FIXME: To make this prettier we should invent some stop reason for this, + // but that + // is only cosmetic, and this functionality is only of use to lldb + // developers who can + // live with not pretty... + thread->Flush(); + return eExpressionStoppedForDebug; + } + + ListenerSP listener_sp( + Listener::MakeListener("lldb.process.listener.run-thread-plan")); + + lldb::EventSP event_to_broadcast_sp; + + { + // This process event hijacker Hijacks the Public events and its destructor + // makes sure that the process events get + // restored on exit to the function. + // + // If the event needs to propagate beyond the hijacker (e.g., the process + // exits during execution), then the event + // is put into event_to_broadcast_sp for rebroadcasting. + + ProcessEventHijacker run_thread_plan_hijacker(*this, listener_sp); + + if (log) { + StreamString s; + thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); + log->Printf("Process::RunThreadPlan(): Resuming thread %u - 0x%4.4" PRIx64 + " to run thread plan \"%s\".", + thread->GetIndexID(), thread->GetID(), s.GetData()); + } + + bool got_event; + lldb::EventSP event_sp; + lldb::StateType stop_state = lldb::eStateInvalid; + + bool before_first_timeout = true; // This is set to false the first time + // that we have to halt the target. + bool do_resume = true; + bool handle_running_event = true; + const uint64_t default_one_thread_timeout_usec = 250000; + + // This is just for accounting: + uint32_t num_resumes = 0; + + uint32_t timeout_usec = options.GetTimeoutUsec(); + uint32_t one_thread_timeout_usec; + uint32_t all_threads_timeout_usec = 0; + + // If we are going to run all threads the whole time, or if we are only + // going to run one thread, + // then we don't need the first timeout. So we set the final timeout, and + // pretend we are after the + // first timeout already. + + if (!options.GetStopOthers() || !options.GetTryAllThreads()) { + before_first_timeout = false; + one_thread_timeout_usec = 0; + all_threads_timeout_usec = timeout_usec; + } else { + uint32_t option_one_thread_timeout = options.GetOneThreadTimeoutUsec(); + + // If the overall wait is forever, then we only need to set the one thread + // timeout: + if (timeout_usec == 0) { + if (option_one_thread_timeout != 0) + one_thread_timeout_usec = option_one_thread_timeout; + else + one_thread_timeout_usec = default_one_thread_timeout_usec; + } else { + // Otherwise, if the one thread timeout is set, make sure it isn't + // longer than the overall timeout, + // and use it, otherwise use half the total timeout, bounded by the + // default_one_thread_timeout_usec. + uint64_t computed_one_thread_timeout; + if (option_one_thread_timeout != 0) { + if (timeout_usec < option_one_thread_timeout) { + diagnostic_manager.PutCString(eDiagnosticSeverityError, + "RunThreadPlan called without one " + "thread timeout greater than total " + "timeout"); return eExpressionSetupError; + } + computed_one_thread_timeout = option_one_thread_timeout; + } else { + computed_one_thread_timeout = timeout_usec / 2; + if (computed_one_thread_timeout > default_one_thread_timeout_usec) + computed_one_thread_timeout = default_one_thread_timeout_usec; } + one_thread_timeout_usec = computed_one_thread_timeout; + all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec; + } } - StackID ctx_frame_id = selected_frame_sp->GetStackID(); - - // N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either, - // so we should arrange to reset them as well. - - lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread(); - - uint32_t selected_tid; - StackID selected_stack_id; - if (selected_thread_sp) - { - selected_tid = selected_thread_sp->GetIndexID(); - selected_stack_id = selected_thread_sp->GetSelectedFrame()->GetStackID(); - } - else - { - selected_tid = LLDB_INVALID_THREAD_ID; - } - - HostThread backup_private_state_thread; - lldb::StateType old_state = eStateInvalid; - lldb::ThreadPlanSP stopper_base_plan_sp; - - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS)); - if (m_private_state_thread.EqualsThread(Host::GetCurrentThread())) - { - // Yikes, we are running on the private state thread! So we can't wait for public events on this thread, since - // we are the thread that is generating public events. - // The simplest thing to do is to spin up a temporary thread to handle private state thread events while - // we are fielding public events here. - if (log) - log->Printf ("Running thread plan on private state thread, spinning up another state thread to handle the events."); - - backup_private_state_thread = m_private_state_thread; - - // One other bit of business: we want to run just this thread plan and anything it pushes, and then stop, - // returning control here. - // But in the normal course of things, the plan above us on the stack would be given a shot at the stop - // event before deciding to stop, and we don't want that. So we insert a "stopper" base plan on the stack - // before the plan we want to run. Since base plans always stop and return control to the user, that will - // do just what we want. - stopper_base_plan_sp.reset(new ThreadPlanBase (*thread)); - thread->QueueThreadPlan (stopper_base_plan_sp, false); - // Have to make sure our public state is stopped, since otherwise the reporting logic below doesn't work correctly. - old_state = m_public_state.GetValue(); - m_public_state.SetValueNoLock(eStateStopped); - - // Now spin up the private state thread: - StartPrivateStateThread(true); - } + if (log) + log->Printf( + "Stop others: %u, try all: %u, before_first: %u, one thread: %" PRIu32 + " - all threads: %" PRIu32 ".\n", + options.GetStopOthers(), options.GetTryAllThreads(), + before_first_timeout, one_thread_timeout_usec, + all_threads_timeout_usec); + + // This isn't going to work if there are unfetched events on the queue. + // Are there cases where we might want to run the remaining events here, and + // then try to + // call the function? That's probably being too tricky for our own good. + + Event *other_events = listener_sp->PeekAtNextEvent(); + if (other_events != nullptr) { + diagnostic_manager.PutCString( + eDiagnosticSeverityError, + "RunThreadPlan called with pending events on the queue."); + return eExpressionSetupError; + } + + // We also need to make sure that the next event is delivered. We might be + // calling a function as part of + // a thread plan, in which case the last delivered event could be the + // running event, and we don't want + // event coalescing to cause us to lose OUR running event... + ForceNextEventDelivery(); + +// This while loop must exit out the bottom, there's cleanup that we need to do +// when we are done. +// So don't call return anywhere within it. - thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense? - - if (options.GetDebug()) - { - // In this case, we aren't actually going to run, we just want to stop right away. - // Flush this thread so we will refetch the stacks and show the correct backtrace. - // FIXME: To make this prettier we should invent some stop reason for this, but that - // is only cosmetic, and this functionality is only of use to lldb developers who can - // live with not pretty... - thread->Flush(); - return eExpressionStoppedForDebug; - } +#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT + // It's pretty much impossible to write test cases for things like: + // One thread timeout expires, I go to halt, but the process already stopped + // on the function call stop breakpoint. Turning on this define will make + // us not + // fetch the first event till after the halt. So if you run a quick + // function, it will have + // completed, and the completion event will be waiting, when you interrupt + // for halt. + // The expression evaluation should still succeed. + bool miss_first_event = true; +#endif + TimeValue one_thread_timeout; + TimeValue final_timeout; + std::chrono::microseconds timeout = std::chrono::microseconds(0); + + while (true) { + // We usually want to resume the process if we get to the top of the loop. + // The only exception is if we get two running events with no intervening + // stop, which can happen, we will just wait for then next stop event. + if (log) + log->Printf("Top of while loop: do_resume: %i handle_running_event: %i " + "before_first_timeout: %i.", + do_resume, handle_running_event, before_first_timeout); + + if (do_resume || handle_running_event) { + // Do the initial resume and wait for the running event before going + // further. + + if (do_resume) { + num_resumes++; + Error resume_error = PrivateResume(); + if (!resume_error.Success()) { + diagnostic_manager.Printf( + eDiagnosticSeverityError, + "couldn't resume inferior the %d time: \"%s\".", num_resumes, + resume_error.AsCString()); + return_value = eExpressionSetupError; + break; + } + } - ListenerSP listener_sp(Listener::MakeListener("lldb.process.listener.run-thread-plan")); + got_event = listener_sp->WaitForEvent(std::chrono::microseconds(500000), + event_sp); + if (!got_event) { + if (log) + log->Printf("Process::RunThreadPlan(): didn't get any event after " + "resume %" PRIu32 ", exiting.", + num_resumes); + + diagnostic_manager.Printf(eDiagnosticSeverityError, + "didn't get any event after resume %" PRIu32 + ", exiting.", + num_resumes); + return_value = eExpressionSetupError; + break; + } - lldb::EventSP event_to_broadcast_sp; + stop_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - { - // This process event hijacker Hijacks the Public events and its destructor makes sure that the process events get - // restored on exit to the function. - // - // If the event needs to propagate beyond the hijacker (e.g., the process exits during execution), then the event - // is put into event_to_broadcast_sp for rebroadcasting. + if (stop_state != eStateRunning) { + bool restarted = false; - ProcessEventHijacker run_thread_plan_hijacker (*this, listener_sp); + if (stop_state == eStateStopped) { + restarted = Process::ProcessEventData::GetRestartedFromEvent( + event_sp.get()); + if (log) + log->Printf( + "Process::RunThreadPlan(): didn't get running event after " + "resume %d, got %s instead (restarted: %i, do_resume: %i, " + "handle_running_event: %i).", + num_resumes, StateAsCString(stop_state), restarted, do_resume, + handle_running_event); + } + + if (restarted) { + // This is probably an overabundance of caution, I don't think I + // should ever get a stopped & restarted + // event here. But if I do, the best thing is to Halt and then get + // out of here. + const bool clear_thread_plans = false; + const bool use_run_lock = false; + Halt(clear_thread_plans, use_run_lock); + } + + diagnostic_manager.Printf( + eDiagnosticSeverityError, + "didn't get running event after initial resume, got %s instead.", + StateAsCString(stop_state)); + return_value = eExpressionSetupError; + break; + } if (log) - { - StreamString s; - thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); - log->Printf ("Process::RunThreadPlan(): Resuming thread %u - 0x%4.4" PRIx64 " to run thread plan \"%s\".", - thread->GetIndexID(), - thread->GetID(), - s.GetData()); - } + log->PutCString("Process::RunThreadPlan(): resuming succeeded."); + // We need to call the function synchronously, so spin waiting for it to + // return. + // If we get interrupted while executing, we're going to lose our + // context, and + // won't be able to gather the result at this point. + // We set the timeout AFTER the resume, since the resume takes some time + // and we + // don't want to charge that to the timeout. + } else { + if (log) + log->PutCString("Process::RunThreadPlan(): waiting for next event."); + } - bool got_event; - lldb::EventSP event_sp; - lldb::StateType stop_state = lldb::eStateInvalid; - - bool before_first_timeout = true; // This is set to false the first time that we have to halt the target. - bool do_resume = true; - bool handle_running_event = true; - const uint64_t default_one_thread_timeout_usec = 250000; - - // This is just for accounting: - uint32_t num_resumes = 0; - - uint32_t timeout_usec = options.GetTimeoutUsec(); - uint32_t one_thread_timeout_usec; - uint32_t all_threads_timeout_usec = 0; - - // If we are going to run all threads the whole time, or if we are only going to run one thread, - // then we don't need the first timeout. So we set the final timeout, and pretend we are after the - // first timeout already. - - if (!options.GetStopOthers() || !options.GetTryAllThreads()) - { - before_first_timeout = false; - one_thread_timeout_usec = 0; - all_threads_timeout_usec = timeout_usec; - } + if (before_first_timeout) { + if (options.GetTryAllThreads()) + timeout = std::chrono::microseconds(one_thread_timeout_usec); else - { - uint32_t option_one_thread_timeout = options.GetOneThreadTimeoutUsec(); - - // If the overall wait is forever, then we only need to set the one thread timeout: - if (timeout_usec == 0) - { - if (option_one_thread_timeout != 0) - one_thread_timeout_usec = option_one_thread_timeout; - else - one_thread_timeout_usec = default_one_thread_timeout_usec; - } - else - { - // Otherwise, if the one thread timeout is set, make sure it isn't longer than the overall timeout, - // and use it, otherwise use half the total timeout, bounded by the default_one_thread_timeout_usec. - uint64_t computed_one_thread_timeout; - if (option_one_thread_timeout != 0) - { - if (timeout_usec < option_one_thread_timeout) - { - diagnostic_manager.PutCString( - eDiagnosticSeverityError, - "RunThreadPlan called without one thread timeout greater than total timeout"); - return eExpressionSetupError; - } - computed_one_thread_timeout = option_one_thread_timeout; - } - else - { - computed_one_thread_timeout = timeout_usec / 2; - if (computed_one_thread_timeout > default_one_thread_timeout_usec) - computed_one_thread_timeout = default_one_thread_timeout_usec; - } - one_thread_timeout_usec = computed_one_thread_timeout; - all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec; - } - } - - if (log) - log->Printf ("Stop others: %u, try all: %u, before_first: %u, one thread: %" PRIu32 " - all threads: %" PRIu32 ".\n", - options.GetStopOthers(), - options.GetTryAllThreads(), - before_first_timeout, - one_thread_timeout_usec, - all_threads_timeout_usec); - - // This isn't going to work if there are unfetched events on the queue. - // Are there cases where we might want to run the remaining events here, and then try to - // call the function? That's probably being too tricky for our own good. - - Event *other_events = listener_sp->PeekAtNextEvent(); - if (other_events != nullptr) - { - diagnostic_manager.PutCString(eDiagnosticSeverityError, - "RunThreadPlan called with pending events on the queue."); - return eExpressionSetupError; + timeout = std::chrono::microseconds(timeout_usec); + } else { + if (timeout_usec == 0) + timeout = std::chrono::microseconds(0); + else + timeout = std::chrono::microseconds(all_threads_timeout_usec); + } + + do_resume = true; + handle_running_event = true; + + // Now wait for the process to stop again: + event_sp.reset(); + + if (log) { + if (timeout.count()) { + log->Printf( + "Process::RunThreadPlan(): about to wait - now is %llu - " + "endpoint is %llu", + static_cast<unsigned long long>( + std::chrono::system_clock::now().time_since_epoch().count()), + static_cast<unsigned long long>( + std::chrono::time_point<std::chrono::system_clock, + std::chrono::microseconds>(timeout) + .time_since_epoch() + .count())); + } else { + log->Printf("Process::RunThreadPlan(): about to wait forever."); } + } - // We also need to make sure that the next event is delivered. We might be calling a function as part of - // a thread plan, in which case the last delivered event could be the running event, and we don't want - // event coalescing to cause us to lose OUR running event... - ForceNextEventDelivery(); - - // This while loop must exit out the bottom, there's cleanup that we need to do when we are done. - // So don't call return anywhere within it. - #ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT - // It's pretty much impossible to write test cases for things like: - // One thread timeout expires, I go to halt, but the process already stopped - // on the function call stop breakpoint. Turning on this define will make us not - // fetch the first event till after the halt. So if you run a quick function, it will have - // completed, and the completion event will be waiting, when you interrupt for halt. - // The expression evaluation should still succeed. - bool miss_first_event = true; + // See comment above... + if (miss_first_event) { + usleep(1000); + miss_first_event = false; + got_event = false; + } else #endif - TimeValue one_thread_timeout; - TimeValue final_timeout; - std::chrono::microseconds timeout = std::chrono::microseconds(0); - - while (true) - { - // We usually want to resume the process if we get to the top of the loop. - // The only exception is if we get two running events with no intervening - // stop, which can happen, we will just wait for then next stop event. + got_event = listener_sp->WaitForEvent(timeout, event_sp); + + if (got_event) { + if (event_sp) { + bool keep_going = false; + if (event_sp->GetType() == eBroadcastBitInterrupt) { + const bool clear_thread_plans = false; + const bool use_run_lock = false; + Halt(clear_thread_plans, use_run_lock); + return_value = eExpressionInterrupted; + diagnostic_manager.PutCString( + eDiagnosticSeverityRemark, + "execution halted by user interrupt."); if (log) - log->Printf ("Top of while loop: do_resume: %i handle_running_event: %i before_first_timeout: %i.", - do_resume, - handle_running_event, - before_first_timeout); - - if (do_resume || handle_running_event) - { - // Do the initial resume and wait for the running event before going further. - - if (do_resume) - { - num_resumes++; - Error resume_error = PrivateResume(); - if (!resume_error.Success()) - { - diagnostic_manager.Printf(eDiagnosticSeverityError, - "couldn't resume inferior the %d time: \"%s\".", num_resumes, - resume_error.AsCString()); - return_value = eExpressionSetupError; - break; - } - } - - got_event = listener_sp->WaitForEvent(std::chrono::microseconds(500000), event_sp); - if (!got_event) - { - if (log) - log->Printf("Process::RunThreadPlan(): didn't get any event after resume %" PRIu32 ", exiting.", - num_resumes); - - diagnostic_manager.Printf(eDiagnosticSeverityError, - "didn't get any event after resume %" PRIu32 ", exiting.", num_resumes); - return_value = eExpressionSetupError; - break; - } - - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - - if (stop_state != eStateRunning) - { - bool restarted = false; - - if (stop_state == eStateStopped) - { - restarted = Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()); - if (log) - log->Printf("Process::RunThreadPlan(): didn't get running event after " - "resume %d, got %s instead (restarted: %i, do_resume: %i, handle_running_event: %i).", - num_resumes, - StateAsCString(stop_state), - restarted, - do_resume, - handle_running_event); - } - - if (restarted) - { - // This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted - // event here. But if I do, the best thing is to Halt and then get out of here. - const bool clear_thread_plans = false; - const bool use_run_lock = false; - Halt(clear_thread_plans, use_run_lock); - } - - diagnostic_manager.Printf(eDiagnosticSeverityError, - "didn't get running event after initial resume, got %s instead.", - StateAsCString(stop_state)); - return_value = eExpressionSetupError; - break; - } - - if (log) - log->PutCString ("Process::RunThreadPlan(): resuming succeeded."); - // We need to call the function synchronously, so spin waiting for it to return. - // If we get interrupted while executing, we're going to lose our context, and - // won't be able to gather the result at this point. - // We set the timeout AFTER the resume, since the resume takes some time and we - // don't want to charge that to the timeout. - } - else - { - if (log) - log->PutCString ("Process::RunThreadPlan(): waiting for next event."); - } - - if (before_first_timeout) - { - if (options.GetTryAllThreads()) - timeout = std::chrono::microseconds(one_thread_timeout_usec); - else - timeout = std::chrono::microseconds(timeout_usec); - } - else - { - if (timeout_usec == 0) - timeout = std::chrono::microseconds(0); - else - timeout = std::chrono::microseconds(all_threads_timeout_usec); - } - - do_resume = true; - handle_running_event = true; - - // Now wait for the process to stop again: - event_sp.reset(); - + log->Printf("Process::RunThreadPlan(): Got interrupted by " + "eBroadcastBitInterrupted, exiting."); + break; + } else { + stop_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); if (log) - { - if (timeout.count()) - { - log->Printf( - "Process::RunThreadPlan(): about to wait - now is %llu - endpoint is %llu", - static_cast<unsigned long long>(std::chrono::system_clock::now().time_since_epoch().count()), - static_cast<unsigned long long>( - std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>(timeout) - .time_since_epoch() - .count())); - } - else - { - log->Printf ("Process::RunThreadPlan(): about to wait forever."); - } - } - -#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT - // See comment above... - if (miss_first_event) - { - usleep(1000); - miss_first_event = false; - got_event = false; - } - else -#endif - got_event = listener_sp->WaitForEvent(timeout, event_sp); - - if (got_event) - { - if (event_sp) - { - bool keep_going = false; - if (event_sp->GetType() == eBroadcastBitInterrupt) - { - const bool clear_thread_plans = false; - const bool use_run_lock = false; - Halt(clear_thread_plans, use_run_lock); - return_value = eExpressionInterrupted; - diagnostic_manager.PutCString(eDiagnosticSeverityRemark, "execution halted by user interrupt."); - if (log) - log->Printf( - "Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting."); - break; - } - else - { - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - if (log) - log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state)); - - switch (stop_state) - { - case lldb::eStateStopped: - { - // We stopped, figure out what we are going to do now. - ThreadSP thread_sp = GetThreadList().FindThreadByIndexID (thread_idx_id); - if (!thread_sp) - { - // Ooh, our thread has vanished. Unlikely that this was successful execution... - if (log) - log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id); - return_value = eExpressionInterrupted; - } - else - { - // If we were restarted, we just need to go back up to fetch another event. - if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) - { - if (log) - { - log->Printf ("Process::RunThreadPlan(): Got a stop and restart, so we'll continue waiting."); - } - keep_going = true; - do_resume = false; - handle_running_event = true; - } - else - { - StopInfoSP stop_info_sp (thread_sp->GetStopInfo ()); - StopReason stop_reason = eStopReasonInvalid; - if (stop_info_sp) - stop_reason = stop_info_sp->GetStopReason(); - - // FIXME: We only check if the stop reason is plan complete, should we make sure that - // it is OUR plan that is complete? - if (stop_reason == eStopReasonPlanComplete) - { - if (log) - log->PutCString ("Process::RunThreadPlan(): execution completed successfully."); - - // Restore the plan state so it will get reported as intended when we are done. - thread_plan_restorer.Clean(); - - return_value = eExpressionCompleted; - } - else - { - // Something restarted the target, so just wait for it to stop for real. - if (stop_reason == eStopReasonBreakpoint) - { - if (log) - log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription()); - return_value = eExpressionHitBreakpoint; - if (!options.DoesIgnoreBreakpoints()) - { - // Restore the plan state and then force Private to false. We are - // going to stop because of this plan so we need it to become a public - // plan or it won't report correctly when we continue to its termination - // later on. - thread_plan_restorer.Clean(); - if (thread_plan_sp) - thread_plan_sp->SetPrivate(false); - event_to_broadcast_sp = event_sp; - } - } - else - { - if (log) - log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete."); - if (!options.DoesUnwindOnError()) - event_to_broadcast_sp = event_sp; - return_value = eExpressionInterrupted; - } - } - } - } - } - break; - - case lldb::eStateRunning: - // This shouldn't really happen, but sometimes we do get two running events without an - // intervening stop, and in that case we should just go back to waiting for the stop. - do_resume = false; - keep_going = true; - handle_running_event = false; - break; - - default: - if (log) - log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state)); - - if (stop_state == eStateExited) - event_to_broadcast_sp = event_sp; - - diagnostic_manager.PutCString(eDiagnosticSeverityError, - "execution stopped with unexpected state."); - return_value = eExpressionInterrupted; - break; - } - } - - if (keep_going) - continue; - else - break; - } - else - { + log->Printf( + "Process::RunThreadPlan(): in while loop, got event: %s.", + StateAsCString(stop_state)); + + switch (stop_state) { + case lldb::eStateStopped: { + // We stopped, figure out what we are going to do now. + ThreadSP thread_sp = + GetThreadList().FindThreadByIndexID(thread_idx_id); + if (!thread_sp) { + // Ooh, our thread has vanished. Unlikely that this was + // successful execution... + if (log) + log->Printf("Process::RunThreadPlan(): execution completed " + "but our thread (index-id=%u) has vanished.", + thread_idx_id); + return_value = eExpressionInterrupted; + } else { + // If we were restarted, we just need to go back up to fetch + // another event. + if (Process::ProcessEventData::GetRestartedFromEvent( + event_sp.get())) { + if (log) { + log->Printf("Process::RunThreadPlan(): Got a stop and " + "restart, so we'll continue waiting."); + } + keep_going = true; + do_resume = false; + handle_running_event = true; + } else { + StopInfoSP stop_info_sp(thread_sp->GetStopInfo()); + StopReason stop_reason = eStopReasonInvalid; + if (stop_info_sp) + stop_reason = stop_info_sp->GetStopReason(); + + // FIXME: We only check if the stop reason is plan complete, + // should we make sure that + // it is OUR plan that is complete? + if (stop_reason == eStopReasonPlanComplete) { if (log) - log->PutCString ("Process::RunThreadPlan(): got_event was true, but the event pointer was null. How odd..."); - return_value = eExpressionInterrupted; - break; - } - } - else - { - // If we didn't get an event that means we've timed out... - // We will interrupt the process here. Depending on what we were asked to do we will - // either exit, or try with all threads running for the same timeout. - - if (log) { - if (options.GetTryAllThreads()) - { - if (before_first_timeout) - { - if (timeout_usec != 0) - { - log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, " - "running for %" PRIu32 " usec with all threads enabled.", - all_threads_timeout_usec); - } - else - { - log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, " - "running forever with all threads enabled."); - } - } - else - log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled " - "and timeout: %u timed out, abandoning execution.", - timeout_usec); - } - else - log->Printf ("Process::RunThreadPlan(): Running function with timeout: %u timed out, " - "abandoning execution.", - timeout_usec); - } - - // It is possible that between the time we issued the Halt, and we get around to calling Halt the target - // could have stopped. That's fine, Halt will figure that out and send the appropriate Stopped event. - // BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.) In - // that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's - // stopped event. That's what this while loop does. - - bool back_to_top = true; - uint32_t try_halt_again = 0; - bool do_halt = true; - const uint32_t num_retries = 5; - while (try_halt_again < num_retries) - { - Error halt_error; - if (do_halt) - { - if (log) - log->Printf ("Process::RunThreadPlan(): Running Halt."); - const bool clear_thread_plans = false; - const bool use_run_lock = false; - Halt(clear_thread_plans, use_run_lock); - } - if (halt_error.Success()) - { - if (log) - log->PutCString ("Process::RunThreadPlan(): Halt succeeded."); - - got_event = listener_sp->WaitForEvent(std::chrono::microseconds(500000), event_sp); - - if (got_event) - { - stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get()); - if (log) - { - log->Printf ("Process::RunThreadPlan(): Stopped with event: %s", StateAsCString(stop_state)); - if (stop_state == lldb::eStateStopped - && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get())) - log->PutCString (" Event was the Halt interruption event."); - } - - if (stop_state == lldb::eStateStopped) - { - // Between the time we initiated the Halt and the time we delivered it, the process could have - // already finished its job. Check that here: - - if (thread->IsThreadPlanDone (thread_plan_sp.get())) - { - if (log) - log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. " - "Exiting wait loop."); - return_value = eExpressionCompleted; - back_to_top = false; - break; - } - - if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) - { - if (log) - log->PutCString ("Process::RunThreadPlan(): Went to halt but got a restarted event, there must be an un-restarted stopped event so try again... " - "Exiting wait loop."); - try_halt_again++; - do_halt = false; - continue; - } - - if (!options.GetTryAllThreads()) - { - if (log) - log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting."); - return_value = eExpressionInterrupted; - back_to_top = false; - break; - } - - if (before_first_timeout) - { - // Set all the other threads to run, and return to the top of the loop, which will continue; - before_first_timeout = false; - thread_plan_sp->SetStopOthers (false); - if (log) - log->PutCString ("Process::RunThreadPlan(): about to resume."); - - back_to_top = true; - break; - } - else - { - // Running all threads failed, so return Interrupted. - if (log) - log->PutCString("Process::RunThreadPlan(): running all threads timed out."); - return_value = eExpressionInterrupted; - back_to_top = false; - break; - } - } - } - else - { if (log) - log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event. " - "I'm getting out of here passing Interrupted."); - return_value = eExpressionInterrupted; - back_to_top = false; - break; - } - } - else - { - try_halt_again++; - continue; + log->PutCString("Process::RunThreadPlan(): execution " + "completed successfully."); + + // Restore the plan state so it will get reported as + // intended when we are done. + thread_plan_restorer.Clean(); + + return_value = eExpressionCompleted; + } else { + // Something restarted the target, so just wait for it to + // stop for real. + if (stop_reason == eStopReasonBreakpoint) { + if (log) + log->Printf("Process::RunThreadPlan() stopped for " + "breakpoint: %s.", + stop_info_sp->GetDescription()); + return_value = eExpressionHitBreakpoint; + if (!options.DoesIgnoreBreakpoints()) { + // Restore the plan state and then force Private to + // false. We are + // going to stop because of this plan so we need it to + // become a public + // plan or it won't report correctly when we continue to + // its termination + // later on. + thread_plan_restorer.Clean(); + if (thread_plan_sp) + thread_plan_sp->SetPrivate(false); + event_to_broadcast_sp = event_sp; + } + } else { + if (log) + log->PutCString("Process::RunThreadPlan(): thread plan " + "didn't successfully complete."); + if (!options.DoesUnwindOnError()) + event_to_broadcast_sp = event_sp; + return_value = eExpressionInterrupted; } + } } - - if (!back_to_top || try_halt_again > num_retries) - break; - else - continue; - } - } // END WAIT LOOP - - // If we had to start up a temporary private state thread to run this thread plan, shut it down now. - if (backup_private_state_thread.IsJoinable()) - { - StopPrivateStateThread(); - Error error; - m_private_state_thread = backup_private_state_thread; - if (stopper_base_plan_sp) - { - thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp); + } + } break; + + case lldb::eStateRunning: + // This shouldn't really happen, but sometimes we do get two + // running events without an + // intervening stop, and in that case we should just go back to + // waiting for the stop. + do_resume = false; + keep_going = true; + handle_running_event = false; + break; + + default: + if (log) + log->Printf("Process::RunThreadPlan(): execution stopped with " + "unexpected state: %s.", + StateAsCString(stop_state)); + + if (stop_state == eStateExited) + event_to_broadcast_sp = event_sp; + + diagnostic_manager.PutCString( + eDiagnosticSeverityError, + "execution stopped with unexpected state."); + return_value = eExpressionInterrupted; + break; } - if (old_state != eStateInvalid) - m_public_state.SetValueNoLock(old_state); - } - - if (return_value != eExpressionCompleted && log) - { - // Print a backtrace into the log so we can figure out where we are: - StreamString s; - s.PutCString("Thread state after unsuccessful completion: \n"); - thread->GetStackFrameStatus (s, - 0, - UINT32_MAX, - true, - UINT32_MAX); - log->PutCString(s.GetData()); + } + if (keep_going) + continue; + else + break; + } else { + if (log) + log->PutCString("Process::RunThreadPlan(): got_event was true, but " + "the event pointer was null. How odd..."); + return_value = eExpressionInterrupted; + break; } - // Restore the thread state if we are going to discard the plan execution. There are three cases where this - // could happen: - // 1) The execution successfully completed - // 2) We hit a breakpoint, and ignore_breakpoints was true - // 3) We got some other error, and discard_on_error was true - bool should_unwind = (return_value == eExpressionInterrupted && options.DoesUnwindOnError()) - || (return_value == eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints()); - - if (return_value == eExpressionCompleted - || should_unwind) - { - thread_plan_sp->RestoreThreadState(); + } else { + // If we didn't get an event that means we've timed out... + // We will interrupt the process here. Depending on what we were asked + // to do we will + // either exit, or try with all threads running for the same timeout. + + if (log) { + if (options.GetTryAllThreads()) { + if (before_first_timeout) { + if (timeout_usec != 0) { + log->Printf("Process::RunThreadPlan(): Running function with " + "one thread timeout timed out, " + "running for %" PRIu32 + " usec with all threads enabled.", + all_threads_timeout_usec); + } else { + log->Printf("Process::RunThreadPlan(): Running function with " + "one thread timeout timed out, " + "running forever with all threads enabled."); + } + } else + log->Printf("Process::RunThreadPlan(): Restarting function with " + "all threads enabled " + "and timeout: %u timed out, abandoning execution.", + timeout_usec); + } else + log->Printf("Process::RunThreadPlan(): Running function with " + "timeout: %u timed out, " + "abandoning execution.", + timeout_usec); } - // Now do some processing on the results of the run: - if (return_value == eExpressionInterrupted || return_value == eExpressionHitBreakpoint) - { + // It is possible that between the time we issued the Halt, and we get + // around to calling Halt the target + // could have stopped. That's fine, Halt will figure that out and send + // the appropriate Stopped event. + // BUT it is also possible that we stopped & restarted (e.g. hit a + // signal with "stop" set to false.) In + // that case, we'll get the stopped & restarted event, and we should go + // back to waiting for the Halt's + // stopped event. That's what this while loop does. + + bool back_to_top = true; + uint32_t try_halt_again = 0; + bool do_halt = true; + const uint32_t num_retries = 5; + while (try_halt_again < num_retries) { + Error halt_error; + if (do_halt) { if (log) - { - StreamString s; - if (event_sp) - event_sp->Dump (&s); - else - { - log->PutCString ("Process::RunThreadPlan(): Stop event that interrupted us is NULL."); + log->Printf("Process::RunThreadPlan(): Running Halt."); + const bool clear_thread_plans = false; + const bool use_run_lock = false; + Halt(clear_thread_plans, use_run_lock); + } + if (halt_error.Success()) { + if (log) + log->PutCString("Process::RunThreadPlan(): Halt succeeded."); + + got_event = listener_sp->WaitForEvent( + std::chrono::microseconds(500000), event_sp); + + if (got_event) { + stop_state = + Process::ProcessEventData::GetStateFromEvent(event_sp.get()); + if (log) { + log->Printf("Process::RunThreadPlan(): Stopped with event: %s", + StateAsCString(stop_state)); + if (stop_state == lldb::eStateStopped && + Process::ProcessEventData::GetInterruptedFromEvent( + event_sp.get())) + log->PutCString(" Event was the Halt interruption event."); + } + + if (stop_state == lldb::eStateStopped) { + // Between the time we initiated the Halt and the time we + // delivered it, the process could have + // already finished its job. Check that here: + + if (thread->IsThreadPlanDone(thread_plan_sp.get())) { + if (log) + log->PutCString("Process::RunThreadPlan(): Even though we " + "timed out, the call plan was done. " + "Exiting wait loop."); + return_value = eExpressionCompleted; + back_to_top = false; + break; } - StreamString ts; - - const char *event_explanation = nullptr; - - do - { - if (!event_sp) - { - event_explanation = "<no event>"; - break; - } - else if (event_sp->GetType() == eBroadcastBitInterrupt) - { - event_explanation = "<user interrupt>"; - break; - } - else - { - const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get()); - - if (!event_data) - { - event_explanation = "<no event data>"; - break; - } - - Process *process = event_data->GetProcessSP().get(); - - if (!process) - { - event_explanation = "<no process>"; - break; - } - - ThreadList &thread_list = process->GetThreadList(); - - uint32_t num_threads = thread_list.GetSize(); - uint32_t thread_index; - - ts.Printf("<%u threads> ", num_threads); - - for (thread_index = 0; - thread_index < num_threads; - ++thread_index) - { - Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); - - if (!thread) - { - ts.Printf("<?> "); - continue; - } - - ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID()); - RegisterContext *register_context = thread->GetRegisterContext().get(); - - if (register_context) - ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC()); - else - ts.Printf("[ip unknown] "); - - // Show the private stop info here, the public stop info will be from the last natural stop. - lldb::StopInfoSP stop_info_sp = thread->GetPrivateStopInfo(); - if (stop_info_sp) - { - const char *stop_desc = stop_info_sp->GetDescription(); - if (stop_desc) - ts.PutCString (stop_desc); - } - ts.Printf(">"); - } - - event_explanation = ts.GetData(); - } - } while (0); - - if (event_explanation) - log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation); - else - log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData()); - } + if (Process::ProcessEventData::GetRestartedFromEvent( + event_sp.get())) { + if (log) + log->PutCString("Process::RunThreadPlan(): Went to halt " + "but got a restarted event, there must be " + "an un-restarted stopped event so try " + "again... " + "Exiting wait loop."); + try_halt_again++; + do_halt = false; + continue; + } - if (should_unwind) - { - if (log) - log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", - static_cast<void*>(thread_plan_sp.get())); - thread->DiscardThreadPlansUpToPlan (thread_plan_sp); - } - else - { - if (log) - log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", - static_cast<void*>(thread_plan_sp.get())); - } - } - else if (return_value == eExpressionSetupError) - { - if (log) - log->PutCString("Process::RunThreadPlan(): execution set up error."); + if (!options.GetTryAllThreads()) { + if (log) + log->PutCString("Process::RunThreadPlan(): try_all_threads " + "was false, we stopped so now we're " + "quitting."); + return_value = eExpressionInterrupted; + back_to_top = false; + break; + } - if (options.DoesUnwindOnError()) - { - thread->DiscardThreadPlansUpToPlan (thread_plan_sp); - } - } - else - { - if (thread->IsThreadPlanDone (thread_plan_sp.get())) - { - if (log) - log->PutCString("Process::RunThreadPlan(): thread plan is done"); - return_value = eExpressionCompleted; - } - else if (thread->WasThreadPlanDiscarded (thread_plan_sp.get())) - { - if (log) - log->PutCString("Process::RunThreadPlan(): thread plan was discarded"); - return_value = eExpressionDiscarded; - } - else - { - if (log) - log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course"); - if (options.DoesUnwindOnError() && thread_plan_sp) - { - if (log) - log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set."); - thread->DiscardThreadPlansUpToPlan (thread_plan_sp); + if (before_first_timeout) { + // Set all the other threads to run, and return to the top of + // the loop, which will continue; + before_first_timeout = false; + thread_plan_sp->SetStopOthers(false); + if (log) + log->PutCString( + "Process::RunThreadPlan(): about to resume."); + + back_to_top = true; + break; + } else { + // Running all threads failed, so return Interrupted. + if (log) + log->PutCString("Process::RunThreadPlan(): running all " + "threads timed out."); + return_value = eExpressionInterrupted; + back_to_top = false; + break; } + } + } else { + if (log) + log->PutCString("Process::RunThreadPlan(): halt said it " + "succeeded, but I got no event. " + "I'm getting out of here passing Interrupted."); + return_value = eExpressionInterrupted; + back_to_top = false; + break; } + } else { + try_halt_again++; + continue; + } } - // Thread we ran the function in may have gone away because we ran the target - // Check that it's still there, and if it is put it back in the context. Also restore the - // frame in the context if it is still present. - thread = GetThreadList().FindThreadByIndexID(thread_idx_id, true).get(); - if (thread) - { - exe_ctx.SetFrameSP (thread->GetFrameWithStackID (ctx_frame_id)); - } - - // Also restore the current process'es selected frame & thread, since this function calling may - // be done behind the user's back. - - if (selected_tid != LLDB_INVALID_THREAD_ID) - { - if (GetThreadList().SetSelectedThreadByIndexID (selected_tid) && selected_stack_id.IsValid()) - { - // We were able to restore the selected thread, now restore the frame: - std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex()); - StackFrameSP old_frame_sp = GetThreadList().GetSelectedThread()->GetFrameWithStackID(selected_stack_id); - if (old_frame_sp) - GetThreadList().GetSelectedThread()->SetSelectedFrame(old_frame_sp.get()); - } + if (!back_to_top || try_halt_again > num_retries) + break; + else + continue; + } + } // END WAIT LOOP + + // If we had to start up a temporary private state thread to run this thread + // plan, shut it down now. + if (backup_private_state_thread.IsJoinable()) { + StopPrivateStateThread(); + Error error; + m_private_state_thread = backup_private_state_thread; + if (stopper_base_plan_sp) { + thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp); + } + if (old_state != eStateInvalid) + m_public_state.SetValueNoLock(old_state); + } + + if (return_value != eExpressionCompleted && log) { + // Print a backtrace into the log so we can figure out where we are: + StreamString s; + s.PutCString("Thread state after unsuccessful completion: \n"); + thread->GetStackFrameStatus(s, 0, UINT32_MAX, true, UINT32_MAX); + log->PutCString(s.GetData()); + } + // Restore the thread state if we are going to discard the plan execution. + // There are three cases where this + // could happen: + // 1) The execution successfully completed + // 2) We hit a breakpoint, and ignore_breakpoints was true + // 3) We got some other error, and discard_on_error was true + bool should_unwind = (return_value == eExpressionInterrupted && + options.DoesUnwindOnError()) || + (return_value == eExpressionHitBreakpoint && + options.DoesIgnoreBreakpoints()); + + if (return_value == eExpressionCompleted || should_unwind) { + thread_plan_sp->RestoreThreadState(); + } + + // Now do some processing on the results of the run: + if (return_value == eExpressionInterrupted || + return_value == eExpressionHitBreakpoint) { + if (log) { + StreamString s; + if (event_sp) + event_sp->Dump(&s); + else { + log->PutCString("Process::RunThreadPlan(): Stop event that " + "interrupted us is NULL."); } - } - - // If the process exited during the run of the thread plan, notify everyone. - if (event_to_broadcast_sp) - { - if (log) - log->PutCString("Process::RunThreadPlan(): rebroadcasting event."); - BroadcastEvent(event_to_broadcast_sp); - } + StreamString ts; - return return_value; -} + const char *event_explanation = nullptr; -const char * -Process::ExecutionResultAsCString (ExpressionResults result) -{ - const char *result_name; - - switch (result) - { - case eExpressionCompleted: - result_name = "eExpressionCompleted"; - break; - case eExpressionDiscarded: - result_name = "eExpressionDiscarded"; - break; - case eExpressionInterrupted: - result_name = "eExpressionInterrupted"; - break; - case eExpressionHitBreakpoint: - result_name = "eExpressionHitBreakpoint"; + do { + if (!event_sp) { + event_explanation = "<no event>"; break; - case eExpressionSetupError: - result_name = "eExpressionSetupError"; + } else if (event_sp->GetType() == eBroadcastBitInterrupt) { + event_explanation = "<user interrupt>"; break; - case eExpressionParseError: - result_name = "eExpressionParseError"; - break; - case eExpressionResultUnavailable: - result_name = "eExpressionResultUnavailable"; - break; - case eExpressionTimedOut: - result_name = "eExpressionTimedOut"; - break; - case eExpressionStoppedForDebug: - result_name = "eExpressionStoppedForDebug"; - break; - } - return result_name; -} - -void -Process::GetStatus (Stream &strm) -{ - const StateType state = GetState(); - if (StateIsStoppedState(state, false)) - { - if (state == eStateExited) - { - int exit_status = GetExitStatus(); - const char *exit_description = GetExitDescription(); - strm.Printf ("Process %" PRIu64 " exited with status = %i (0x%8.8x) %s\n", - GetID(), - exit_status, - exit_status, - exit_description ? exit_description : ""); - } - else - { - if (state == eStateConnected) - strm.Printf ("Connected to remote target.\n"); - else - strm.Printf ("Process %" PRIu64 " %s\n", GetID(), StateAsCString (state)); - } - } - else - { - strm.Printf ("Process %" PRIu64 " is running.\n", GetID()); - } -} - -size_t -Process::GetThreadStatus (Stream &strm, - bool only_threads_with_stop_reason, - uint32_t start_frame, - uint32_t num_frames, - uint32_t num_frames_with_source) -{ - size_t num_thread_infos_dumped = 0; - - // You can't hold the thread list lock while calling Thread::GetStatus. That very well might run code (e.g. if we need it - // to get return values or arguments.) For that to work the process has to be able to acquire it. So instead copy the thread - // ID's, and look them up one by one: - - uint32_t num_threads; - std::vector<lldb::tid_t> thread_id_array; - //Scope for thread list locker; - { - std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex()); - ThreadList &curr_thread_list = GetThreadList(); - num_threads = curr_thread_list.GetSize(); - uint32_t idx; - thread_id_array.resize(num_threads); - for (idx = 0; idx < num_threads; ++idx) - thread_id_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID(); - } - - for (uint32_t i = 0; i < num_threads; i++) - { - ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_id_array[i])); - if (thread_sp) - { - if (only_threads_with_stop_reason) - { - StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); - if (!stop_info_sp || !stop_info_sp->IsValid()) - continue; + } else { + const Process::ProcessEventData *event_data = + Process::ProcessEventData::GetEventDataFromEvent( + event_sp.get()); + + if (!event_data) { + event_explanation = "<no event data>"; + break; } - thread_sp->GetStatus (strm, - start_frame, - num_frames, - num_frames_with_source); - ++num_thread_infos_dumped; - } - else - { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf("Process::GetThreadStatus - thread 0x" PRIu64 " vanished while running Thread::GetStatus."); - } - } - return num_thread_infos_dumped; -} -void -Process::AddInvalidMemoryRegion (const LoadRange ®ion) -{ - m_memory_cache.AddInvalidRange(region.GetRangeBase(), region.GetByteSize()); -} + Process *process = event_data->GetProcessSP().get(); -bool -Process::RemoveInvalidMemoryRange (const LoadRange ®ion) -{ - return m_memory_cache.RemoveInvalidRange(region.GetRangeBase(), region.GetByteSize()); -} + if (!process) { + event_explanation = "<no process>"; + break; + } -void -Process::AddPreResumeAction (PreResumeActionCallback callback, void *baton) -{ - m_pre_resume_actions.push_back(PreResumeCallbackAndBaton (callback, baton)); -} + ThreadList &thread_list = process->GetThreadList(); -bool -Process::RunPreResumeActions () -{ - bool result = true; - while (!m_pre_resume_actions.empty()) - { - struct PreResumeCallbackAndBaton action = m_pre_resume_actions.back(); - m_pre_resume_actions.pop_back(); - bool this_result = action.callback (action.baton); - if (result) - result = this_result; - } - return result; -} + uint32_t num_threads = thread_list.GetSize(); + uint32_t thread_index; -void -Process::ClearPreResumeActions () -{ - m_pre_resume_actions.clear(); -} + ts.Printf("<%u threads> ", num_threads); -ProcessRunLock & -Process::GetRunLock() -{ - if (m_private_state_thread.EqualsThread(Host::GetCurrentThread())) - return m_private_run_lock; - else - return m_public_run_lock; -} + for (thread_index = 0; thread_index < num_threads; ++thread_index) { + Thread *thread = thread_list.GetThreadAtIndex(thread_index).get(); -void -Process::Flush () -{ - m_thread_list.Flush(); - m_extended_thread_list.Flush(); - m_extended_thread_stop_id = 0; - m_queue_list.Clear(); - m_queue_list_stop_id = 0; -} + if (!thread) { + ts.Printf("<?> "); + continue; + } + + ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID()); + RegisterContext *register_context = + thread->GetRegisterContext().get(); + + if (register_context) + ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC()); + else + ts.Printf("[ip unknown] "); + + // Show the private stop info here, the public stop info will be + // from the last natural stop. + lldb::StopInfoSP stop_info_sp = thread->GetPrivateStopInfo(); + if (stop_info_sp) { + const char *stop_desc = stop_info_sp->GetDescription(); + if (stop_desc) + ts.PutCString(stop_desc); + } + ts.Printf(">"); + } -void -Process::DidExec () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log) - log->Printf ("Process::%s()", __FUNCTION__); - - Target &target = GetTarget(); - target.CleanupProcess (); - target.ClearModules(false); - m_dynamic_checkers_ap.reset(); - m_abi_sp.reset(); - m_system_runtime_ap.reset(); - m_os_ap.reset(); - m_dyld_ap.reset(); - m_jit_loaders_ap.reset(); - m_image_tokens.clear(); - m_allocated_memory_cache.Clear(); - m_language_runtimes.clear(); - m_instrumentation_runtimes.clear(); - m_thread_list.DiscardThreadPlans(); - m_memory_cache.Clear(true); - m_stop_info_override_callback = nullptr; - DoDidExec(); - CompleteAttach (); - // Flush the process (threads and all stack frames) after running CompleteAttach() - // in case the dynamic loader loaded things in new locations. - Flush(); - - // After we figure out what was loaded/unloaded in CompleteAttach, - // we need to let the target know so it can do any cleanup it needs to. - target.DidExec(); -} + event_explanation = ts.GetData(); + } + } while (0); -addr_t -Process::ResolveIndirectFunction(const Address *address, Error &error) -{ - if (address == nullptr) - { - error.SetErrorString("Invalid address argument"); - return LLDB_INVALID_ADDRESS; - } - - addr_t function_addr = LLDB_INVALID_ADDRESS; - - addr_t addr = address->GetLoadAddress(&GetTarget()); - std::map<addr_t,addr_t>::const_iterator iter = m_resolved_indirect_addresses.find(addr); - if (iter != m_resolved_indirect_addresses.end()) - { - function_addr = (*iter).second; - } - else - { - if (!InferiorCall(this, address, function_addr)) - { - Symbol *symbol = address->CalculateSymbolContextSymbol(); - error.SetErrorStringWithFormat ("Unable to call resolver for indirect function %s", - symbol ? symbol->GetName().AsCString() : "<UNKNOWN>"); - function_addr = LLDB_INVALID_ADDRESS; - } + if (event_explanation) + log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", + s.GetData(), event_explanation); else - { - m_resolved_indirect_addresses.insert(std::pair<addr_t, addr_t>(addr, function_addr)); - } - } - return function_addr; -} - -void -Process::ModulesDidLoad (ModuleList &module_list) -{ - SystemRuntime *sys_runtime = GetSystemRuntime(); - if (sys_runtime) - { - sys_runtime->ModulesDidLoad (module_list); - } + log->Printf("Process::RunThreadPlan(): execution interrupted: %s", + s.GetData()); + } - GetJITLoaders().ModulesDidLoad (module_list); - - // Give runtimes a chance to be created. - InstrumentationRuntime::ModulesDidLoad(module_list, this, m_instrumentation_runtimes); - - // Tell runtimes about new modules. - for (auto pos = m_instrumentation_runtimes.begin(); pos != m_instrumentation_runtimes.end(); ++pos) - { - InstrumentationRuntimeSP runtime = pos->second; - runtime->ModulesDidLoad(module_list); - } - - // Let any language runtimes we have already created know - // about the modules that loaded. - - // Iterate over a copy of this language runtime list in case - // the language runtime ModulesDidLoad somehow causes the language - // riuntime to be unloaded. - LanguageRuntimeCollection language_runtimes(m_language_runtimes); - for (const auto &pair: language_runtimes) - { - // We must check language_runtime_sp to make sure it is not - // nullptr as we might cache the fact that we didn't have a - // language runtime for a language. - LanguageRuntimeSP language_runtime_sp = pair.second; - if (language_runtime_sp) - language_runtime_sp->ModulesDidLoad(module_list); + if (should_unwind) { + if (log) + log->Printf("Process::RunThreadPlan: ExecutionInterrupted - " + "discarding thread plans up to %p.", + static_cast<void *>(thread_plan_sp.get())); + thread->DiscardThreadPlansUpToPlan(thread_plan_sp); + } else { + if (log) + log->Printf("Process::RunThreadPlan: ExecutionInterrupted - for " + "plan: %p not discarding.", + static_cast<void *>(thread_plan_sp.get())); + } + } else if (return_value == eExpressionSetupError) { + if (log) + log->PutCString("Process::RunThreadPlan(): execution set up error."); + + if (options.DoesUnwindOnError()) { + thread->DiscardThreadPlansUpToPlan(thread_plan_sp); + } + } else { + if (thread->IsThreadPlanDone(thread_plan_sp.get())) { + if (log) + log->PutCString("Process::RunThreadPlan(): thread plan is done"); + return_value = eExpressionCompleted; + } else if (thread->WasThreadPlanDiscarded(thread_plan_sp.get())) { + if (log) + log->PutCString( + "Process::RunThreadPlan(): thread plan was discarded"); + return_value = eExpressionDiscarded; + } else { + if (log) + log->PutCString( + "Process::RunThreadPlan(): thread plan stopped in mid course"); + if (options.DoesUnwindOnError() && thread_plan_sp) { + if (log) + log->PutCString("Process::RunThreadPlan(): discarding thread plan " + "'cause unwind_on_error is set."); + thread->DiscardThreadPlansUpToPlan(thread_plan_sp); + } + } } - // If we don't have an operating system plug-in, try to load one since - // loading shared libraries might cause a new one to try and load - if (!m_os_ap) - LoadOperatingSystemPlugin(false); - - // Give structured-data plugins a chance to see the modified modules. - for (auto pair : m_structured_data_plugin_map) - { - if (pair.second) - pair.second->ModulesDidLoad(*this, module_list); + // Thread we ran the function in may have gone away because we ran the + // target + // Check that it's still there, and if it is put it back in the context. + // Also restore the + // frame in the context if it is still present. + thread = GetThreadList().FindThreadByIndexID(thread_idx_id, true).get(); + if (thread) { + exe_ctx.SetFrameSP(thread->GetFrameWithStackID(ctx_frame_id)); } -} -void -Process::PrintWarning (uint64_t warning_type, const void *repeat_key, const char *fmt, ...) -{ - bool print_warning = true; + // Also restore the current process'es selected frame & thread, since this + // function calling may + // be done behind the user's back. - StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); - if (!stream_sp) - return; - if (warning_type == eWarningsOptimization - && !GetWarningsOptimization()) - { - return; + if (selected_tid != LLDB_INVALID_THREAD_ID) { + if (GetThreadList().SetSelectedThreadByIndexID(selected_tid) && + selected_stack_id.IsValid()) { + // We were able to restore the selected thread, now restore the frame: + std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex()); + StackFrameSP old_frame_sp = + GetThreadList().GetSelectedThread()->GetFrameWithStackID( + selected_stack_id); + if (old_frame_sp) + GetThreadList().GetSelectedThread()->SetSelectedFrame( + old_frame_sp.get()); + } } + } - if (repeat_key != nullptr) - { - WarningsCollection::iterator it = m_warnings_issued.find (warning_type); - if (it == m_warnings_issued.end()) - { - m_warnings_issued[warning_type] = WarningsPointerSet(); - m_warnings_issued[warning_type].insert (repeat_key); - } - else - { - if (it->second.find (repeat_key) != it->second.end()) - { - print_warning = false; - } - else - { - it->second.insert (repeat_key); - } - } - } + // If the process exited during the run of the thread plan, notify everyone. - if (print_warning) - { - va_list args; - va_start (args, fmt); - stream_sp->PrintfVarArg (fmt, args); - va_end (args); - } -} + if (event_to_broadcast_sp) { + if (log) + log->PutCString("Process::RunThreadPlan(): rebroadcasting event."); + BroadcastEvent(event_to_broadcast_sp); + } + + return return_value; +} + +const char *Process::ExecutionResultAsCString(ExpressionResults result) { + const char *result_name; + + switch (result) { + case eExpressionCompleted: + result_name = "eExpressionCompleted"; + break; + case eExpressionDiscarded: + result_name = "eExpressionDiscarded"; + break; + case eExpressionInterrupted: + result_name = "eExpressionInterrupted"; + break; + case eExpressionHitBreakpoint: + result_name = "eExpressionHitBreakpoint"; + break; + case eExpressionSetupError: + result_name = "eExpressionSetupError"; + break; + case eExpressionParseError: + result_name = "eExpressionParseError"; + break; + case eExpressionResultUnavailable: + result_name = "eExpressionResultUnavailable"; + break; + case eExpressionTimedOut: + result_name = "eExpressionTimedOut"; + break; + case eExpressionStoppedForDebug: + result_name = "eExpressionStoppedForDebug"; + break; + } + return result_name; +} + +void Process::GetStatus(Stream &strm) { + const StateType state = GetState(); + if (StateIsStoppedState(state, false)) { + if (state == eStateExited) { + int exit_status = GetExitStatus(); + const char *exit_description = GetExitDescription(); + strm.Printf("Process %" PRIu64 " exited with status = %i (0x%8.8x) %s\n", + GetID(), exit_status, exit_status, + exit_description ? exit_description : ""); + } else { + if (state == eStateConnected) + strm.Printf("Connected to remote target.\n"); + else + strm.Printf("Process %" PRIu64 " %s\n", GetID(), StateAsCString(state)); + } + } else { + strm.Printf("Process %" PRIu64 " is running.\n", GetID()); + } +} + +size_t Process::GetThreadStatus(Stream &strm, + bool only_threads_with_stop_reason, + uint32_t start_frame, uint32_t num_frames, + uint32_t num_frames_with_source) { + size_t num_thread_infos_dumped = 0; + + // You can't hold the thread list lock while calling Thread::GetStatus. That + // very well might run code (e.g. if we need it + // to get return values or arguments.) For that to work the process has to be + // able to acquire it. So instead copy the thread + // ID's, and look them up one by one: + + uint32_t num_threads; + std::vector<lldb::tid_t> thread_id_array; + // Scope for thread list locker; + { + std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex()); + ThreadList &curr_thread_list = GetThreadList(); + num_threads = curr_thread_list.GetSize(); + uint32_t idx; + thread_id_array.resize(num_threads); + for (idx = 0; idx < num_threads; ++idx) + thread_id_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID(); + } + + for (uint32_t i = 0; i < num_threads; i++) { + ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_id_array[i])); + if (thread_sp) { + if (only_threads_with_stop_reason) { + StopInfoSP stop_info_sp = thread_sp->GetStopInfo(); + if (!stop_info_sp || !stop_info_sp->IsValid()) + continue; + } + thread_sp->GetStatus(strm, start_frame, num_frames, + num_frames_with_source); + ++num_thread_infos_dumped; + } else { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::GetThreadStatus - thread 0x" PRIu64 + " vanished while running Thread::GetStatus."); + } + } + return num_thread_infos_dumped; +} + +void Process::AddInvalidMemoryRegion(const LoadRange ®ion) { + m_memory_cache.AddInvalidRange(region.GetRangeBase(), region.GetByteSize()); +} + +bool Process::RemoveInvalidMemoryRange(const LoadRange ®ion) { + return m_memory_cache.RemoveInvalidRange(region.GetRangeBase(), + region.GetByteSize()); +} + +void Process::AddPreResumeAction(PreResumeActionCallback callback, + void *baton) { + m_pre_resume_actions.push_back(PreResumeCallbackAndBaton(callback, baton)); +} + +bool Process::RunPreResumeActions() { + bool result = true; + while (!m_pre_resume_actions.empty()) { + struct PreResumeCallbackAndBaton action = m_pre_resume_actions.back(); + m_pre_resume_actions.pop_back(); + bool this_result = action.callback(action.baton); + if (result) + result = this_result; + } + return result; +} + +void Process::ClearPreResumeActions() { m_pre_resume_actions.clear(); } + +ProcessRunLock &Process::GetRunLock() { + if (m_private_state_thread.EqualsThread(Host::GetCurrentThread())) + return m_private_run_lock; + else + return m_public_run_lock; +} + +void Process::Flush() { + m_thread_list.Flush(); + m_extended_thread_list.Flush(); + m_extended_thread_stop_id = 0; + m_queue_list.Clear(); + m_queue_list_stop_id = 0; +} + +void Process::DidExec() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + if (log) + log->Printf("Process::%s()", __FUNCTION__); + + Target &target = GetTarget(); + target.CleanupProcess(); + target.ClearModules(false); + m_dynamic_checkers_ap.reset(); + m_abi_sp.reset(); + m_system_runtime_ap.reset(); + m_os_ap.reset(); + m_dyld_ap.reset(); + m_jit_loaders_ap.reset(); + m_image_tokens.clear(); + m_allocated_memory_cache.Clear(); + m_language_runtimes.clear(); + m_instrumentation_runtimes.clear(); + m_thread_list.DiscardThreadPlans(); + m_memory_cache.Clear(true); + m_stop_info_override_callback = nullptr; + DoDidExec(); + CompleteAttach(); + // Flush the process (threads and all stack frames) after running + // CompleteAttach() + // in case the dynamic loader loaded things in new locations. + Flush(); + + // After we figure out what was loaded/unloaded in CompleteAttach, + // we need to let the target know so it can do any cleanup it needs to. + target.DidExec(); +} + +addr_t Process::ResolveIndirectFunction(const Address *address, Error &error) { + if (address == nullptr) { + error.SetErrorString("Invalid address argument"); + return LLDB_INVALID_ADDRESS; + } + + addr_t function_addr = LLDB_INVALID_ADDRESS; + + addr_t addr = address->GetLoadAddress(&GetTarget()); + std::map<addr_t, addr_t>::const_iterator iter = + m_resolved_indirect_addresses.find(addr); + if (iter != m_resolved_indirect_addresses.end()) { + function_addr = (*iter).second; + } else { + if (!InferiorCall(this, address, function_addr)) { + Symbol *symbol = address->CalculateSymbolContextSymbol(); + error.SetErrorStringWithFormat( + "Unable to call resolver for indirect function %s", + symbol ? symbol->GetName().AsCString() : "<UNKNOWN>"); + function_addr = LLDB_INVALID_ADDRESS; + } else { + m_resolved_indirect_addresses.insert( + std::pair<addr_t, addr_t>(addr, function_addr)); + } + } + return function_addr; +} + +void Process::ModulesDidLoad(ModuleList &module_list) { + SystemRuntime *sys_runtime = GetSystemRuntime(); + if (sys_runtime) { + sys_runtime->ModulesDidLoad(module_list); + } + + GetJITLoaders().ModulesDidLoad(module_list); + + // Give runtimes a chance to be created. + InstrumentationRuntime::ModulesDidLoad(module_list, this, + m_instrumentation_runtimes); + + // Tell runtimes about new modules. + for (auto pos = m_instrumentation_runtimes.begin(); + pos != m_instrumentation_runtimes.end(); ++pos) { + InstrumentationRuntimeSP runtime = pos->second; + runtime->ModulesDidLoad(module_list); + } + + // Let any language runtimes we have already created know + // about the modules that loaded. + + // Iterate over a copy of this language runtime list in case + // the language runtime ModulesDidLoad somehow causes the language + // riuntime to be unloaded. + LanguageRuntimeCollection language_runtimes(m_language_runtimes); + for (const auto &pair : language_runtimes) { + // We must check language_runtime_sp to make sure it is not + // nullptr as we might cache the fact that we didn't have a + // language runtime for a language. + LanguageRuntimeSP language_runtime_sp = pair.second; + if (language_runtime_sp) + language_runtime_sp->ModulesDidLoad(module_list); + } + + // If we don't have an operating system plug-in, try to load one since + // loading shared libraries might cause a new one to try and load + if (!m_os_ap) + LoadOperatingSystemPlugin(false); + + // Give structured-data plugins a chance to see the modified modules. + for (auto pair : m_structured_data_plugin_map) { + if (pair.second) + pair.second->ModulesDidLoad(*this, module_list); + } +} + +void Process::PrintWarning(uint64_t warning_type, const void *repeat_key, + const char *fmt, ...) { + bool print_warning = true; + + StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream(); + if (!stream_sp) + return; + if (warning_type == eWarningsOptimization && !GetWarningsOptimization()) { + return; + } + + if (repeat_key != nullptr) { + WarningsCollection::iterator it = m_warnings_issued.find(warning_type); + if (it == m_warnings_issued.end()) { + m_warnings_issued[warning_type] = WarningsPointerSet(); + m_warnings_issued[warning_type].insert(repeat_key); + } else { + if (it->second.find(repeat_key) != it->second.end()) { + print_warning = false; + } else { + it->second.insert(repeat_key); + } + } + } + + if (print_warning) { + va_list args; + va_start(args, fmt); + stream_sp->PrintfVarArg(fmt, args); + va_end(args); + } +} + +void Process::PrintWarningOptimization(const SymbolContext &sc) { + if (GetWarningsOptimization() && sc.module_sp && + !sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function && + sc.function->GetIsOptimized()) { + PrintWarning(Process::Warnings::eWarningsOptimization, sc.module_sp.get(), + "%s was compiled with optimization - stepping may behave " + "oddly; variables may not be available.\n", + sc.module_sp->GetFileSpec().GetFilename().GetCString()); + } +} + +bool Process::GetProcessInfo(ProcessInstanceInfo &info) { + info.Clear(); + + PlatformSP platform_sp = GetTarget().GetPlatform(); + if (!platform_sp) + return false; -void -Process::PrintWarningOptimization (const SymbolContext &sc) -{ - if (GetWarningsOptimization() - && sc.module_sp - && !sc.module_sp->GetFileSpec().GetFilename().IsEmpty() - && sc.function - && sc.function->GetIsOptimized()) - { - PrintWarning (Process::Warnings::eWarningsOptimization, sc.module_sp.get(), "%s was compiled with optimization - stepping may behave oddly; variables may not be available.\n", sc.module_sp->GetFileSpec().GetFilename().GetCString()); - } + return platform_sp->GetProcessInfo(GetID(), info); } -bool -Process::GetProcessInfo(ProcessInstanceInfo &info) -{ - info.Clear(); +ThreadCollectionSP Process::GetHistoryThreads(lldb::addr_t addr) { + ThreadCollectionSP threads; - PlatformSP platform_sp = GetTarget().GetPlatform(); - if (! platform_sp) - return false; + const MemoryHistorySP &memory_history = + MemoryHistory::FindPlugin(shared_from_this()); - return platform_sp->GetProcessInfo(GetID(), info); -} + if (!memory_history) { + return threads; + } -ThreadCollectionSP -Process::GetHistoryThreads(lldb::addr_t addr) -{ - ThreadCollectionSP threads; + threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr))); - const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(shared_from_this()); - - if (!memory_history) { - return threads; - } - - threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr))); - - return threads; + return threads; } InstrumentationRuntimeSP -Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type) -{ - InstrumentationRuntimeCollection::iterator pos; - pos = m_instrumentation_runtimes.find (type); - if (pos == m_instrumentation_runtimes.end()) - { - return InstrumentationRuntimeSP(); - } - else - return (*pos).second; +Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type) { + InstrumentationRuntimeCollection::iterator pos; + pos = m_instrumentation_runtimes.find(type); + if (pos == m_instrumentation_runtimes.end()) { + return InstrumentationRuntimeSP(); + } else + return (*pos).second; } -bool -Process::GetModuleSpec(const FileSpec& module_file_spec, - const ArchSpec& arch, - ModuleSpec& module_spec) -{ - module_spec.Clear(); - return false; +bool Process::GetModuleSpec(const FileSpec &module_file_spec, + const ArchSpec &arch, ModuleSpec &module_spec) { + module_spec.Clear(); + return false; } -size_t -Process::AddImageToken(lldb::addr_t image_ptr) -{ - m_image_tokens.push_back(image_ptr); - return m_image_tokens.size() - 1; +size_t Process::AddImageToken(lldb::addr_t image_ptr) { + m_image_tokens.push_back(image_ptr); + return m_image_tokens.size() - 1; } -lldb::addr_t -Process::GetImagePtrFromToken(size_t token) const -{ - if (token < m_image_tokens.size()) - return m_image_tokens[token]; - return LLDB_INVALID_IMAGE_TOKEN; +lldb::addr_t Process::GetImagePtrFromToken(size_t token) const { + if (token < m_image_tokens.size()) + return m_image_tokens[token]; + return LLDB_INVALID_IMAGE_TOKEN; } -void -Process::ResetImageToken(size_t token) -{ - if (token < m_image_tokens.size()) - m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN; +void Process::ResetImageToken(size_t token) { + if (token < m_image_tokens.size()) + m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN; } Address -Process::AdvanceAddressToNextBranchInstruction (Address default_stop_addr, AddressRange range_bounds) -{ - Target &target = GetTarget(); - DisassemblerSP disassembler_sp; - InstructionList *insn_list = nullptr; - - Address retval = default_stop_addr; - - if (!target.GetUseFastStepping()) - return retval; - if (!default_stop_addr.IsValid()) - return retval; - - ExecutionContext exe_ctx (this); - const char *plugin_name = nullptr; - const char *flavor = nullptr; - const bool prefer_file_cache = true; - disassembler_sp = Disassembler::DisassembleRange(target.GetArchitecture(), - plugin_name, - flavor, - exe_ctx, - range_bounds, - prefer_file_cache); - if (disassembler_sp) - insn_list = &disassembler_sp->GetInstructionList(); - - if (insn_list == nullptr) - { - return retval; - } +Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr, + AddressRange range_bounds) { + Target &target = GetTarget(); + DisassemblerSP disassembler_sp; + InstructionList *insn_list = nullptr; - size_t insn_offset = insn_list->GetIndexOfInstructionAtAddress (default_stop_addr); - if (insn_offset == UINT32_MAX) - { - return retval; - } + Address retval = default_stop_addr; - uint32_t branch_index = insn_list->GetIndexOfNextBranchInstruction (insn_offset, target); - if (branch_index == UINT32_MAX) - { - return retval; - } + if (!target.GetUseFastStepping()) + return retval; + if (!default_stop_addr.IsValid()) + return retval; - if (branch_index > insn_offset) - { - Address next_branch_insn_address = insn_list->GetInstructionAtIndex (branch_index)->GetAddress(); - if (next_branch_insn_address.IsValid() && range_bounds.ContainsFileAddress (next_branch_insn_address)) - { - retval = next_branch_insn_address; - } - } + ExecutionContext exe_ctx(this); + const char *plugin_name = nullptr; + const char *flavor = nullptr; + const bool prefer_file_cache = true; + disassembler_sp = Disassembler::DisassembleRange( + target.GetArchitecture(), plugin_name, flavor, exe_ctx, range_bounds, + prefer_file_cache); + if (disassembler_sp) + insn_list = &disassembler_sp->GetInstructionList(); + + if (insn_list == nullptr) { + return retval; + } + size_t insn_offset = + insn_list->GetIndexOfInstructionAtAddress(default_stop_addr); + if (insn_offset == UINT32_MAX) { return retval; -} + } -Error -Process::GetMemoryRegions (std::vector<lldb::MemoryRegionInfoSP>& region_list) -{ + uint32_t branch_index = + insn_list->GetIndexOfNextBranchInstruction(insn_offset, target); + if (branch_index == UINT32_MAX) { + return retval; + } - Error error; + if (branch_index > insn_offset) { + Address next_branch_insn_address = + insn_list->GetInstructionAtIndex(branch_index)->GetAddress(); + if (next_branch_insn_address.IsValid() && + range_bounds.ContainsFileAddress(next_branch_insn_address)) { + retval = next_branch_insn_address; + } + } - lldb::addr_t range_end = 0; - - region_list.clear(); - do - { - lldb::MemoryRegionInfoSP region_info( new lldb_private::MemoryRegionInfo() ); - error = GetMemoryRegionInfo (range_end, *region_info); - // GetMemoryRegionInfo should only return an error if it is unimplemented. - if (error.Fail()) - { - region_list.clear(); - break; - } + return retval; +} - range_end = region_info->GetRange().GetRangeEnd(); - if( region_info->GetMapped() == MemoryRegionInfo::eYes ) - { - region_list.push_back(region_info); - } - } while (range_end != LLDB_INVALID_ADDRESS); +Error Process::GetMemoryRegions( + std::vector<lldb::MemoryRegionInfoSP> ®ion_list) { - return error; -} + Error error; -Error -Process::ConfigureStructuredData(const ConstString &type_name, - const StructuredData::ObjectSP &config_sp) -{ - // If you get this, the Process-derived class needs to implement a method - // to enable an already-reported asynchronous structured data feature. - // See ProcessGDBRemote for an example implementation over gdb-remote. - return Error("unimplemented"); -} + lldb::addr_t range_end = 0; -void -Process::MapSupportedStructuredDataPlugins(const StructuredData::Array - &supported_type_names) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + region_list.clear(); + do { + lldb::MemoryRegionInfoSP region_info(new lldb_private::MemoryRegionInfo()); + error = GetMemoryRegionInfo(range_end, *region_info); + // GetMemoryRegionInfo should only return an error if it is unimplemented. + if (error.Fail()) { + region_list.clear(); + break; + } - // Bail out early if there are no type names to map. - if (supported_type_names.GetSize() == 0) - { - if (log) - log->Printf("Process::%s(): no structured data types supported", - __FUNCTION__); - return; + range_end = region_info->GetRange().GetRangeEnd(); + if (region_info->GetMapped() == MemoryRegionInfo::eYes) { + region_list.push_back(region_info); } + } while (range_end != LLDB_INVALID_ADDRESS); - // Convert StructuredData type names to ConstString instances. - std::set<ConstString> const_type_names; + return error; +} + +Error Process::ConfigureStructuredData( + const ConstString &type_name, const StructuredData::ObjectSP &config_sp) { + // If you get this, the Process-derived class needs to implement a method + // to enable an already-reported asynchronous structured data feature. + // See ProcessGDBRemote for an example implementation over gdb-remote. + return Error("unimplemented"); +} +void Process::MapSupportedStructuredDataPlugins( + const StructuredData::Array &supported_type_names) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // Bail out early if there are no type names to map. + if (supported_type_names.GetSize() == 0) { if (log) - log->Printf("Process::%s(): the process supports the following async " - "structured data types:", __FUNCTION__); - - supported_type_names.ForEach([&const_type_names, &log] - (StructuredData::Object *object) { - if (!object) - { - // Invalid - shouldn't be null objects in the array. - return false; + log->Printf("Process::%s(): no structured data types supported", + __FUNCTION__); + return; + } + + // Convert StructuredData type names to ConstString instances. + std::set<ConstString> const_type_names; + + if (log) + log->Printf("Process::%s(): the process supports the following async " + "structured data types:", + __FUNCTION__); + + supported_type_names.ForEach( + [&const_type_names, &log](StructuredData::Object *object) { + if (!object) { + // Invalid - shouldn't be null objects in the array. + return false; } auto type_name = object->GetAsString(); - if (!type_name) - { - // Invalid format - all type names should be strings. - return false; + if (!type_name) { + // Invalid format - all type names should be strings. + return false; } const_type_names.insert(ConstString(type_name->GetValue())); if (log) - log->Printf("- %s", type_name->GetValue().c_str()); + log->Printf("- %s", type_name->GetValue().c_str()); return true; - }); + }); + + // For each StructuredDataPlugin, if the plugin handles any of the + // types in the supported_type_names, map that type name to that plugin. + uint32_t plugin_index = 0; + for (auto create_instance = + PluginManager::GetStructuredDataPluginCreateCallbackAtIndex( + plugin_index); + create_instance && !const_type_names.empty(); ++plugin_index) { + // Create the plugin. + StructuredDataPluginSP plugin_sp = (*create_instance)(*this); + if (!plugin_sp) { + // This plugin doesn't think it can work with the process. + // Move on to the next. + continue; + } + + // For any of the remaining type names, map any that this plugin + // supports. + std::vector<ConstString> names_to_remove; + for (auto &type_name : const_type_names) { + if (plugin_sp->SupportsStructuredDataType(type_name)) { + m_structured_data_plugin_map.insert( + std::make_pair(type_name, plugin_sp)); + names_to_remove.push_back(type_name); + if (log) + log->Printf("Process::%s(): using plugin %s for type name " + "%s", + __FUNCTION__, plugin_sp->GetPluginName().GetCString(), + type_name.GetCString()); + } + } - // For each StructuredDataPlugin, if the plugin handles any of the - // types in the supported_type_names, map that type name to that plugin. - uint32_t plugin_index = 0; - for (auto create_instance = - PluginManager::GetStructuredDataPluginCreateCallbackAtIndex(plugin_index); - create_instance && !const_type_names.empty(); - ++plugin_index) - { - // Create the plugin. - StructuredDataPluginSP plugin_sp = (*create_instance)(*this); - if (!plugin_sp) - { - // This plugin doesn't think it can work with the process. - // Move on to the next. - continue; - } + // Remove the type names that were consumed by this plugin. + for (auto &type_name : names_to_remove) + const_type_names.erase(type_name); + } +} - // For any of the remaining type names, map any that this plugin - // supports. - std::vector<ConstString> names_to_remove; - for (auto &type_name : const_type_names) - { - if (plugin_sp->SupportsStructuredDataType(type_name)) - { - m_structured_data_plugin_map.insert(std::make_pair(type_name, - plugin_sp)); - names_to_remove.push_back(type_name); - if (log) - log->Printf("Process::%s(): using plugin %s for type name " - "%s", __FUNCTION__, - plugin_sp->GetPluginName().GetCString(), - type_name.GetCString()); - } - } +bool Process::RouteAsyncStructuredData( + const StructuredData::ObjectSP object_sp) { + // Nothing to do if there's no data. + if (!object_sp) + return false; - // Remove the type names that were consumed by this plugin. - for (auto &type_name : names_to_remove) - const_type_names.erase(type_name); - } -} + // The contract is this must be a dictionary, so we can look up the + // routing key via the top-level 'type' string value within the dictionary. + StructuredData::Dictionary *dictionary = object_sp->GetAsDictionary(); + if (!dictionary) + return false; -bool -Process::RouteAsyncStructuredData(const StructuredData::ObjectSP object_sp) -{ - // Nothing to do if there's no data. - if (!object_sp) - return false; - - // The contract is this must be a dictionary, so we can look up the - // routing key via the top-level 'type' string value within the dictionary. - StructuredData::Dictionary *dictionary = object_sp->GetAsDictionary(); - if (!dictionary) - return false; - - // Grab the async structured type name (i.e. the feature/plugin name). - ConstString type_name; - if (!dictionary->GetValueForKeyAsString("type", type_name)) - return false; - - // Check if there's a plugin registered for this type name. - auto find_it = m_structured_data_plugin_map.find(type_name); - if (find_it == m_structured_data_plugin_map.end()) - { - // We don't have a mapping for this structured data type. - return false; - } + // Grab the async structured type name (i.e. the feature/plugin name). + ConstString type_name; + if (!dictionary->GetValueForKeyAsString("type", type_name)) + return false; - // Route the structured data to the plugin. - find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp); - return true; + // Check if there's a plugin registered for this type name. + auto find_it = m_structured_data_plugin_map.find(type_name); + if (find_it == m_structured_data_plugin_map.end()) { + // We don't have a mapping for this structured data type. + return false; + } + + // Route the structured data to the plugin. + find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp); + return true; } diff --git a/lldb/source/Target/ProcessInfo.cpp b/lldb/source/Target/ProcessInfo.cpp index b57fd23ea2e..be537c1b313 100644 --- a/lldb/source/Target/ProcessInfo.cpp +++ b/lldb/source/Target/ProcessInfo.cpp @@ -21,138 +21,101 @@ using namespace lldb; using namespace lldb_private; -ProcessInfo::ProcessInfo () : - m_executable (), - m_arguments (), - m_environment (), - m_uid (UINT32_MAX), - m_gid (UINT32_MAX), - m_arch(), - m_pid (LLDB_INVALID_PROCESS_ID) -{ +ProcessInfo::ProcessInfo() + : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX), + m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {} + +ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch, + lldb::pid_t pid) + : m_executable(name, false), m_arguments(), m_environment(), + m_uid(UINT32_MAX), m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {} + +void ProcessInfo::Clear() { + m_executable.Clear(); + m_arguments.Clear(); + m_environment.Clear(); + m_uid = UINT32_MAX; + m_gid = UINT32_MAX; + m_arch.Clear(); + m_pid = LLDB_INVALID_PROCESS_ID; } -ProcessInfo::ProcessInfo (const char *name, const ArchSpec &arch, lldb::pid_t pid) : - m_executable (name, false), - m_arguments (), - m_environment(), - m_uid (UINT32_MAX), - m_gid (UINT32_MAX), - m_arch (arch), - m_pid (pid) -{ +const char *ProcessInfo::GetName() const { + return m_executable.GetFilename().GetCString(); } -void -ProcessInfo::Clear () -{ - m_executable.Clear(); - m_arguments.Clear(); - m_environment.Clear(); - m_uid = UINT32_MAX; - m_gid = UINT32_MAX; - m_arch.Clear(); - m_pid = LLDB_INVALID_PROCESS_ID; -} - -const char * -ProcessInfo::GetName() const -{ - return m_executable.GetFilename().GetCString(); +size_t ProcessInfo::GetNameLength() const { + return m_executable.GetFilename().GetLength(); } -size_t -ProcessInfo::GetNameLength() const -{ - return m_executable.GetFilename().GetLength(); -} +void ProcessInfo::Dump(Stream &s, Platform *platform) const { + s << "Executable: " << GetName() << "\n"; + s << "Triple: "; + m_arch.DumpTriple(s); + s << "\n"; -void -ProcessInfo::Dump (Stream &s, Platform *platform) const -{ - s << "Executable: " << GetName() << "\n"; - s << "Triple: "; - m_arch.DumpTriple(s); - s << "\n"; + s << "Arguments:\n"; + m_arguments.Dump(s); - s << "Arguments:\n"; - m_arguments.Dump(s); - - s << "Environment:\n"; - m_environment.Dump(s, "env"); + s << "Environment:\n"; + m_environment.Dump(s, "env"); } -void -ProcessInfo::SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg) -{ - if (exe_file) - { - m_executable = exe_file; - if (add_exe_file_as_first_arg) - { - char filename[PATH_MAX]; - if (exe_file.GetPath(filename, sizeof(filename))) - m_arguments.InsertArgumentAtIndex (0, filename); - } - } - else - { - m_executable.Clear(); +void ProcessInfo::SetExecutableFile(const FileSpec &exe_file, + bool add_exe_file_as_first_arg) { + if (exe_file) { + m_executable = exe_file; + if (add_exe_file_as_first_arg) { + char filename[PATH_MAX]; + if (exe_file.GetPath(filename, sizeof(filename))) + m_arguments.InsertArgumentAtIndex(0, filename); } + } else { + m_executable.Clear(); + } } -const char * -ProcessInfo::GetArg0 () const -{ - return (m_arg0.empty() ? nullptr : m_arg0.c_str()); +const char *ProcessInfo::GetArg0() const { + return (m_arg0.empty() ? nullptr : m_arg0.c_str()); } -void -ProcessInfo::SetArg0 (const char *arg) -{ - if (arg && arg[0]) - m_arg0 = arg; - else - m_arg0.clear(); +void ProcessInfo::SetArg0(const char *arg) { + if (arg && arg[0]) + m_arg0 = arg; + else + m_arg0.clear(); } -void -ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable) -{ - m_arguments.SetArguments (argv); - - // Is the first argument the executable? - if (first_arg_is_executable) - { - const char *first_arg = m_arguments.GetArgumentAtIndex (0); - if (first_arg) - { - // Yes the first argument is an executable, set it as the executable - // in the launch options. Don't resolve the file path as the path - // could be a remote platform path - const bool resolve = false; - m_executable.SetFile(first_arg, resolve); - } +void ProcessInfo::SetArguments(char const **argv, + bool first_arg_is_executable) { + m_arguments.SetArguments(argv); + + // Is the first argument the executable? + if (first_arg_is_executable) { + const char *first_arg = m_arguments.GetArgumentAtIndex(0); + if (first_arg) { + // Yes the first argument is an executable, set it as the executable + // in the launch options. Don't resolve the file path as the path + // could be a remote platform path + const bool resolve = false; + m_executable.SetFile(first_arg, resolve); } + } } -void -ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable) -{ - // Copy all arguments - m_arguments = args; - - // Is the first argument the executable? - if (first_arg_is_executable) - { - const char *first_arg = m_arguments.GetArgumentAtIndex (0); - if (first_arg) - { - // Yes the first argument is an executable, set it as the executable - // in the launch options. Don't resolve the file path as the path - // could be a remote platform path - const bool resolve = false; - m_executable.SetFile(first_arg, resolve); - } +void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) { + // Copy all arguments + m_arguments = args; + + // Is the first argument the executable? + if (first_arg_is_executable) { + const char *first_arg = m_arguments.GetArgumentAtIndex(0); + if (first_arg) { + // Yes the first argument is an executable, set it as the executable + // in the launch options. Don't resolve the file path as the path + // could be a remote platform path + const bool resolve = false; + m_executable.SetFile(first_arg, resolve); } + } } diff --git a/lldb/source/Target/ProcessLaunchInfo.cpp b/lldb/source/Target/ProcessLaunchInfo.cpp index f132450ca35..2f9e95ecc7b 100644 --- a/lldb/source/Target/ProcessLaunchInfo.cpp +++ b/lldb/source/Target/ProcessLaunchInfo.cpp @@ -35,498 +35,415 @@ using namespace lldb_private; // ProcessLaunchInfo member functions //---------------------------------------------------------------------------- -ProcessLaunchInfo::ProcessLaunchInfo() : - ProcessInfo(), - m_working_dir(), - m_plugin_name(), - m_flags(0), - m_file_actions(), - m_pty(new lldb_utility::PseudoTerminal), - m_resume_count(0), - m_monitor_callback(nullptr), - m_monitor_callback_baton(nullptr), - m_monitor_signals(false), - m_listener_sp(), - m_hijack_listener_sp() -{ -} +ProcessLaunchInfo::ProcessLaunchInfo() + : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0), + m_file_actions(), m_pty(new lldb_utility::PseudoTerminal), + m_resume_count(0), m_monitor_callback(nullptr), + m_monitor_callback_baton(nullptr), m_monitor_signals(false), + m_listener_sp(), m_hijack_listener_sp() {} ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec, const FileSpec &stdout_file_spec, const FileSpec &stderr_file_spec, const FileSpec &working_directory, - uint32_t launch_flags) : - ProcessInfo(), - m_working_dir(), - m_plugin_name(), - m_flags(launch_flags), - m_file_actions(), - m_pty(new lldb_utility::PseudoTerminal), - m_resume_count(0), - m_monitor_callback(nullptr), - m_monitor_callback_baton(nullptr), - m_monitor_signals(false), - m_listener_sp (), - m_hijack_listener_sp() -{ - if (stdin_file_spec) - { - FileAction file_action; - const bool read = true; - const bool write = false; - if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write)) - AppendFileAction (file_action); - } - if (stdout_file_spec) - { - FileAction file_action; - const bool read = false; - const bool write = true; - if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write)) - AppendFileAction (file_action); - } - if (stderr_file_spec) - { - FileAction file_action; - const bool read = false; - const bool write = true; - if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write)) - AppendFileAction (file_action); - } - if (working_directory) - SetWorkingDirectory(working_directory); -} - -bool -ProcessLaunchInfo::AppendCloseFileAction (int fd) -{ + uint32_t launch_flags) + : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags), + m_file_actions(), m_pty(new lldb_utility::PseudoTerminal), + m_resume_count(0), m_monitor_callback(nullptr), + m_monitor_callback_baton(nullptr), m_monitor_signals(false), + m_listener_sp(), m_hijack_listener_sp() { + if (stdin_file_spec) { FileAction file_action; - if (file_action.Close (fd)) - { - AppendFileAction (file_action); - return true; - } - return false; + const bool read = true; + const bool write = false; + if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write)) + AppendFileAction(file_action); + } + if (stdout_file_spec) { + FileAction file_action; + const bool read = false; + const bool write = true; + if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write)) + AppendFileAction(file_action); + } + if (stderr_file_spec) { + FileAction file_action; + const bool read = false; + const bool write = true; + if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write)) + AppendFileAction(file_action); + } + if (working_directory) + SetWorkingDirectory(working_directory); } -bool -ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd) -{ - FileAction file_action; - if (file_action.Duplicate (fd, dup_fd)) - { - AppendFileAction (file_action); - return true; - } - return false; +bool ProcessLaunchInfo::AppendCloseFileAction(int fd) { + FileAction file_action; + if (file_action.Close(fd)) { + AppendFileAction(file_action); + return true; + } + return false; } -bool -ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec, - bool read, bool write) -{ - FileAction file_action; - if (file_action.Open(fd, file_spec, read, write)) - { - AppendFileAction (file_action); - return true; - } - return false; +bool ProcessLaunchInfo::AppendDuplicateFileAction(int fd, int dup_fd) { + FileAction file_action; + if (file_action.Duplicate(fd, dup_fd)) { + AppendFileAction(file_action); + return true; + } + return false; } -bool -ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write) -{ - FileAction file_action; - if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read, write)) - { - AppendFileAction (file_action); - return true; - } - return false; +bool ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec, + bool read, bool write) { + FileAction file_action; + if (file_action.Open(fd, file_spec, read, write)) { + AppendFileAction(file_action); + return true; + } + return false; } -const FileAction * -ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const -{ - if (idx < m_file_actions.size()) - return &m_file_actions[idx]; - return nullptr; +bool ProcessLaunchInfo::AppendSuppressFileAction(int fd, bool read, + bool write) { + FileAction file_action; + if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read, + write)) { + AppendFileAction(file_action); + return true; + } + return false; } -const FileAction * -ProcessLaunchInfo::GetFileActionForFD(int fd) const -{ - for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx) - { - if (m_file_actions[idx].GetFD () == fd) - return &m_file_actions[idx]; - } - return nullptr; +const FileAction *ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const { + if (idx < m_file_actions.size()) + return &m_file_actions[idx]; + return nullptr; } -const FileSpec & -ProcessLaunchInfo::GetWorkingDirectory() const -{ - return m_working_dir; +const FileAction *ProcessLaunchInfo::GetFileActionForFD(int fd) const { + for (size_t idx = 0, count = m_file_actions.size(); idx < count; ++idx) { + if (m_file_actions[idx].GetFD() == fd) + return &m_file_actions[idx]; + } + return nullptr; } -void -ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) -{ - m_working_dir = working_dir; +const FileSpec &ProcessLaunchInfo::GetWorkingDirectory() const { + return m_working_dir; } -const char * -ProcessLaunchInfo::GetProcessPluginName () const -{ - return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str()); +void ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) { + m_working_dir = working_dir; } -void -ProcessLaunchInfo::SetProcessPluginName (const char *plugin) -{ - if (plugin && plugin[0]) - m_plugin_name.assign (plugin); - else - m_plugin_name.clear(); +const char *ProcessLaunchInfo::GetProcessPluginName() const { + return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str()); } -const FileSpec & -ProcessLaunchInfo::GetShell () const -{ - return m_shell; +void ProcessLaunchInfo::SetProcessPluginName(const char *plugin) { + if (plugin && plugin[0]) + m_plugin_name.assign(plugin); + else + m_plugin_name.clear(); } -void -ProcessLaunchInfo::SetShell (const FileSpec &shell) -{ - m_shell = shell; - if (m_shell) - { - m_shell.ResolveExecutableLocation(); - m_flags.Set (lldb::eLaunchFlagLaunchInShell); - } - else - m_flags.Clear (lldb::eLaunchFlagLaunchInShell); +const FileSpec &ProcessLaunchInfo::GetShell() const { return m_shell; } + +void ProcessLaunchInfo::SetShell(const FileSpec &shell) { + m_shell = shell; + if (m_shell) { + m_shell.ResolveExecutableLocation(); + m_flags.Set(lldb::eLaunchFlagLaunchInShell); + } else + m_flags.Clear(lldb::eLaunchFlagLaunchInShell); } -void -ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate) -{ - if (separate) - m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup); - else - m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup); +void ProcessLaunchInfo::SetLaunchInSeparateProcessGroup(bool separate) { + if (separate) + m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup); + else + m_flags.Clear(lldb::eLaunchFlagLaunchInSeparateProcessGroup); } -void -ProcessLaunchInfo::SetShellExpandArguments (bool expand) -{ - if (expand) - m_flags.Set(lldb::eLaunchFlagShellExpandArguments); - else - m_flags.Clear(lldb::eLaunchFlagShellExpandArguments); +void ProcessLaunchInfo::SetShellExpandArguments(bool expand) { + if (expand) + m_flags.Set(lldb::eLaunchFlagShellExpandArguments); + else + m_flags.Clear(lldb::eLaunchFlagShellExpandArguments); } -void -ProcessLaunchInfo::Clear () -{ - ProcessInfo::Clear(); - m_working_dir.Clear(); - m_plugin_name.clear(); - m_shell.Clear(); - m_flags.Clear(); - m_file_actions.clear(); - m_resume_count = 0; - m_listener_sp.reset(); - m_hijack_listener_sp.reset(); +void ProcessLaunchInfo::Clear() { + ProcessInfo::Clear(); + m_working_dir.Clear(); + m_plugin_name.clear(); + m_shell.Clear(); + m_flags.Clear(); + m_file_actions.clear(); + m_resume_count = 0; + m_listener_sp.reset(); + m_hijack_listener_sp.reset(); } -void -ProcessLaunchInfo::SetMonitorProcessCallback(const Host::MonitorChildProcessCallback &callback, bool monitor_signals) -{ - m_monitor_callback = callback; - m_monitor_signals = monitor_signals; +void ProcessLaunchInfo::SetMonitorProcessCallback( + const Host::MonitorChildProcessCallback &callback, bool monitor_signals) { + m_monitor_callback = callback; + m_monitor_signals = monitor_signals; } -bool -ProcessLaunchInfo::MonitorProcess () const -{ - if (m_monitor_callback && ProcessIDIsValid()) - { - Host::StartMonitoringChildProcess (m_monitor_callback, - GetProcessID(), - m_monitor_signals); - return true; - } - return false; +bool ProcessLaunchInfo::MonitorProcess() const { + if (m_monitor_callback && ProcessIDIsValid()) { + Host::StartMonitoringChildProcess(m_monitor_callback, GetProcessID(), + m_monitor_signals); + return true; + } + return false; } -void -ProcessLaunchInfo::SetDetachOnError (bool enable) -{ - if (enable) - m_flags.Set(lldb::eLaunchFlagDetachOnError); - else - m_flags.Clear(lldb::eLaunchFlagDetachOnError); +void ProcessLaunchInfo::SetDetachOnError(bool enable) { + if (enable) + m_flags.Set(lldb::eLaunchFlagDetachOnError); + else + m_flags.Clear(lldb::eLaunchFlagDetachOnError); } -void -ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - - // If nothing for stdin or stdout or stderr was specified, then check the process for any default - // settings that were set with "settings set" - if (GetFileActionForFD(STDIN_FILENO) == nullptr || - GetFileActionForFD(STDOUT_FILENO) == nullptr || - GetFileActionForFD(STDERR_FILENO) == nullptr) - { +void ProcessLaunchInfo::FinalizeFileActions(Target *target, + bool default_to_use_pty) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + // If nothing for stdin or stdout or stderr was specified, then check the + // process for any default + // settings that were set with "settings set" + if (GetFileActionForFD(STDIN_FILENO) == nullptr || + GetFileActionForFD(STDOUT_FILENO) == nullptr || + GetFileActionForFD(STDERR_FILENO) == nullptr) { + if (log) + log->Printf("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr " + "was not set, evaluating default handling", + __FUNCTION__); + + if (m_flags.Test(eLaunchFlagLaunchInTTY)) { + // Do nothing, if we are launching in a remote terminal + // no file actions should be done at all. + return; + } + + if (m_flags.Test(eLaunchFlagDisableSTDIO)) { + if (log) + log->Printf("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding " + "suppression action for stdin, stdout and stderr", + __FUNCTION__); + AppendSuppressFileAction(STDIN_FILENO, true, false); + AppendSuppressFileAction(STDOUT_FILENO, false, true); + AppendSuppressFileAction(STDERR_FILENO, false, true); + } else { + // Check for any values that might have gotten set with any of: + // (lldb) settings set target.input-path + // (lldb) settings set target.output-path + // (lldb) settings set target.error-path + FileSpec in_file_spec; + FileSpec out_file_spec; + FileSpec err_file_spec; + if (target) { + // Only override with the target settings if we don't already have + // an action for in, out or error + if (GetFileActionForFD(STDIN_FILENO) == nullptr) + in_file_spec = target->GetStandardInputPath(); + if (GetFileActionForFD(STDOUT_FILENO) == nullptr) + out_file_spec = target->GetStandardOutputPath(); + if (GetFileActionForFD(STDERR_FILENO) == nullptr) + err_file_spec = target->GetStandardErrorPath(); + } + + if (log) + log->Printf("ProcessLaunchInfo::%s target stdin='%s', target " + "stdout='%s', stderr='%s'", + __FUNCTION__, + in_file_spec ? in_file_spec.GetCString() : "<null>", + out_file_spec ? out_file_spec.GetCString() : "<null>", + err_file_spec ? err_file_spec.GetCString() : "<null>"); + + if (in_file_spec) { + AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false); if (log) - log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling", - __FUNCTION__); + log->Printf( + "ProcessLaunchInfo::%s appended stdin open file action for %s", + __FUNCTION__, in_file_spec.GetCString()); + } - if (m_flags.Test(eLaunchFlagLaunchInTTY)) - { - // Do nothing, if we are launching in a remote terminal - // no file actions should be done at all. - return; - } + if (out_file_spec) { + AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true); + if (log) + log->Printf( + "ProcessLaunchInfo::%s appended stdout open file action for %s", + __FUNCTION__, out_file_spec.GetCString()); + } - if (m_flags.Test(eLaunchFlagDisableSTDIO)) - { - if (log) - log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr", - __FUNCTION__); - AppendSuppressFileAction (STDIN_FILENO , true, false); - AppendSuppressFileAction (STDOUT_FILENO, false, true); - AppendSuppressFileAction (STDERR_FILENO, false, true); - } - else - { - // Check for any values that might have gotten set with any of: - // (lldb) settings set target.input-path - // (lldb) settings set target.output-path - // (lldb) settings set target.error-path - FileSpec in_file_spec; - FileSpec out_file_spec; - FileSpec err_file_spec; - if (target) - { - // Only override with the target settings if we don't already have - // an action for in, out or error - if (GetFileActionForFD(STDIN_FILENO) == nullptr) - in_file_spec = target->GetStandardInputPath(); - if (GetFileActionForFD(STDOUT_FILENO) == nullptr) - out_file_spec = target->GetStandardOutputPath(); - if (GetFileActionForFD(STDERR_FILENO) == nullptr) - err_file_spec = target->GetStandardErrorPath(); - } - - if (log) - log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'", - __FUNCTION__, - in_file_spec ? in_file_spec.GetCString() : "<null>", - out_file_spec ? out_file_spec.GetCString() : "<null>", - err_file_spec ? err_file_spec.GetCString() : "<null>"); - - if (in_file_spec) - { - AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false); - if (log) - log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s", - __FUNCTION__, in_file_spec.GetCString()); - } - - if (out_file_spec) - { - AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true); - if (log) - log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s", - __FUNCTION__, out_file_spec.GetCString()); - } - - if (err_file_spec) - { - AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true); - if (log) - log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s", - __FUNCTION__, err_file_spec.GetCString()); - } - - if (default_to_use_pty && (!in_file_spec || !out_file_spec || !err_file_spec)) - { - if (log) - log->Printf ("ProcessLaunchInfo::%s default_to_use_pty is set, and at least one stdin/stderr/stdout is unset, so generating a pty to use for it", - __FUNCTION__); - - int open_flags = O_RDWR | O_NOCTTY; + if (err_file_spec) { + AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true); + if (log) + log->Printf( + "ProcessLaunchInfo::%s appended stderr open file action for %s", + __FUNCTION__, err_file_spec.GetCString()); + } + + if (default_to_use_pty && + (!in_file_spec || !out_file_spec || !err_file_spec)) { + if (log) + log->Printf("ProcessLaunchInfo::%s default_to_use_pty is set, and at " + "least one stdin/stderr/stdout is unset, so generating a " + "pty to use for it", + __FUNCTION__); + + int open_flags = O_RDWR | O_NOCTTY; #if !defined(_MSC_VER) - // We really shouldn't be specifying platform specific flags - // that are intended for a system call in generic code. But - // this will have to do for now. - open_flags |= O_CLOEXEC; + // We really shouldn't be specifying platform specific flags + // that are intended for a system call in generic code. But + // this will have to do for now. + open_flags |= O_CLOEXEC; #endif - if (m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0)) - { - const FileSpec slave_file_spec{m_pty->GetSlaveName(nullptr, 0), false}; - - // Only use the slave tty if we don't have anything specified for - // input and don't have an action for stdin - if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == nullptr) - { - AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false); - } - - // Only use the slave tty if we don't have anything specified for - // output and don't have an action for stdout - if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == nullptr) - { - AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true); - } - - // Only use the slave tty if we don't have anything specified for - // error and don't have an action for stderr - if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == nullptr) - { - AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true); - } - } - } + if (m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0)) { + const FileSpec slave_file_spec{m_pty->GetSlaveName(nullptr, 0), + false}; + + // Only use the slave tty if we don't have anything specified for + // input and don't have an action for stdin + if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == nullptr) { + AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false); + } + + // Only use the slave tty if we don't have anything specified for + // output and don't have an action for stdout + if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == nullptr) { + AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true); + } + + // Only use the slave tty if we don't have anything specified for + // error and don't have an action for stderr + if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == nullptr) { + AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true); + } } + } } + } } -bool -ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error, - bool localhost, - bool will_debug, - bool first_arg_is_full_shell_command, - int32_t num_resumes) -{ - error.Clear(); - - if (GetFlags().Test (eLaunchFlagLaunchInShell)) - { - if (m_shell) +bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell( + Error &error, bool localhost, bool will_debug, + bool first_arg_is_full_shell_command, int32_t num_resumes) { + error.Clear(); + + if (GetFlags().Test(eLaunchFlagLaunchInShell)) { + if (m_shell) { + std::string shell_executable = m_shell.GetPath(); + + const char **argv = GetArguments().GetConstArgumentVector(); + if (argv == nullptr || argv[0] == nullptr) + return false; + Args shell_arguments; + std::string safe_arg; + shell_arguments.AppendArgument(shell_executable.c_str()); + const llvm::Triple &triple = GetArchitecture().GetTriple(); + if (triple.getOS() == llvm::Triple::Win32 && + !triple.isWindowsCygwinEnvironment()) + shell_arguments.AppendArgument("/C"); + else + shell_arguments.AppendArgument("-c"); + + StreamString shell_command; + if (will_debug) { + // Add a modified PATH environment variable in case argv[0] + // is a relative path. + const char *argv0 = argv[0]; + FileSpec arg_spec(argv0, false); + if (arg_spec.IsRelative()) { + // We have a relative path to our executable which may not work if + // we just try to run "a.out" (without it being converted to + // "./a.out") + FileSpec working_dir = GetWorkingDirectory(); + // Be sure to put quotes around PATH's value in case any paths have + // spaces... + std::string new_path("PATH=\""); + const size_t empty_path_len = new_path.size(); + + if (working_dir) { + new_path += working_dir.GetPath(); + } else { + char current_working_dir[PATH_MAX]; + const char *cwd = + getcwd(current_working_dir, sizeof(current_working_dir)); + if (cwd && cwd[0]) + new_path += cwd; + } + std::string curr_path; + if (HostInfo::GetEnvironmentVar("PATH", curr_path)) { + if (new_path.size() > empty_path_len) + new_path += ':'; + new_path += curr_path; + } + new_path += "\" "; + shell_command.PutCString(new_path.c_str()); + } + + if (triple.getOS() != llvm::Triple::Win32 || + triple.isWindowsCygwinEnvironment()) + shell_command.PutCString("exec"); + + // Only Apple supports /usr/bin/arch being able to specify the + // architecture + if (GetArchitecture().IsValid() && // Valid architecture + GetArchitecture().GetTriple().getVendor() == + llvm::Triple::Apple && // Apple only + GetArchitecture().GetCore() != + ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h { - std::string shell_executable = m_shell.GetPath(); - - const char **argv = GetArguments().GetConstArgumentVector (); - if (argv == nullptr || argv[0] == nullptr) - return false; - Args shell_arguments; - std::string safe_arg; - shell_arguments.AppendArgument (shell_executable.c_str()); - const llvm::Triple &triple = GetArchitecture().GetTriple(); - if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment()) - shell_arguments.AppendArgument("/C"); - else - shell_arguments.AppendArgument("-c"); - - StreamString shell_command; - if (will_debug) - { - // Add a modified PATH environment variable in case argv[0] - // is a relative path. - const char *argv0 = argv[0]; - FileSpec arg_spec(argv0, false); - if (arg_spec.IsRelative()) - { - // We have a relative path to our executable which may not work if - // we just try to run "a.out" (without it being converted to "./a.out") - FileSpec working_dir = GetWorkingDirectory(); - // Be sure to put quotes around PATH's value in case any paths have spaces... - std::string new_path("PATH=\""); - const size_t empty_path_len = new_path.size(); - - if (working_dir) - { - new_path += working_dir.GetPath(); - } - else - { - char current_working_dir[PATH_MAX]; - const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir)); - if (cwd && cwd[0]) - new_path += cwd; - } - std::string curr_path; - if (HostInfo::GetEnvironmentVar("PATH", curr_path)) - { - if (new_path.size() > empty_path_len) - new_path += ':'; - new_path += curr_path; - } - new_path += "\" "; - shell_command.PutCString(new_path.c_str()); - } - - if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment()) - shell_command.PutCString("exec"); - - // Only Apple supports /usr/bin/arch being able to specify the architecture - if (GetArchitecture().IsValid() && // Valid architecture - GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only - GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h - { - shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName()); - // Set the resume count to 2: - // 1 - stop in shell - // 2 - stop in /usr/bin/arch - // 3 - then we will stop in our program - SetResumeCount(num_resumes + 1); - } - else - { - // Set the resume count to 1: - // 1 - stop in shell - // 2 - then we will stop in our program - SetResumeCount(num_resumes); - } - } - - if (first_arg_is_full_shell_command) - { - // There should only be one argument that is the shell command itself to be used as is - if (argv[0] && !argv[1]) - shell_command.Printf("%s", argv[0]); - else - return false; - } - else - { - for (size_t i=0; argv[i] != nullptr; ++i) - { - const char *arg = Args::GetShellSafeArgument (m_shell, - argv[i], - safe_arg); - shell_command.Printf(" %s", arg); - } - } - shell_arguments.AppendArgument (shell_command.GetString().c_str()); - m_executable = m_shell; - m_arguments = shell_arguments; - return true; + shell_command.Printf(" /usr/bin/arch -arch %s", + GetArchitecture().GetArchitectureName()); + // Set the resume count to 2: + // 1 - stop in shell + // 2 - stop in /usr/bin/arch + // 3 - then we will stop in our program + SetResumeCount(num_resumes + 1); + } else { + // Set the resume count to 1: + // 1 - stop in shell + // 2 - then we will stop in our program + SetResumeCount(num_resumes); } + } + + if (first_arg_is_full_shell_command) { + // There should only be one argument that is the shell command itself to + // be used as is + if (argv[0] && !argv[1]) + shell_command.Printf("%s", argv[0]); else - { - error.SetErrorString ("invalid shell path"); + return false; + } else { + for (size_t i = 0; argv[i] != nullptr; ++i) { + const char *arg = + Args::GetShellSafeArgument(m_shell, argv[i], safe_arg); + shell_command.Printf(" %s", arg); } + } + shell_arguments.AppendArgument(shell_command.GetString().c_str()); + m_executable = m_shell; + m_arguments = shell_arguments; + return true; + } else { + error.SetErrorString("invalid shell path"); } - else - { - error.SetErrorString ("not launching in shell"); - } - return false; + } else { + error.SetErrorString("not launching in shell"); + } + return false; } -ListenerSP -ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger) -{ - if (m_listener_sp) - return m_listener_sp; - else - return debugger.GetListener(); +ListenerSP ProcessLaunchInfo::GetListenerForProcess(Debugger &debugger) { + if (m_listener_sp) + return m_listener_sp; + else + return debugger.GetListener(); } diff --git a/lldb/source/Target/Queue.cpp b/lldb/source/Target/Queue.cpp index 9d4032a29e6..45fdbea13db 100644 --- a/lldb/source/Target/Queue.cpp +++ b/lldb/source/Target/Queue.cpp @@ -11,127 +11,84 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/Target/Process.h" #include "lldb/Target/Queue.h" +#include "lldb/Target/Process.h" #include "lldb/Target/QueueList.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/SystemRuntime.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; -Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue_name) : - m_process_wp (), - m_queue_id (queue_id), - m_queue_name (), - m_running_work_items_count(0), - m_pending_work_items_count(0), - m_pending_items(), - m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS), - m_kind (eQueueKindUnknown) -{ - if (queue_name) - m_queue_name = queue_name; - - m_process_wp = process_sp; +Queue::Queue(ProcessSP process_sp, lldb::queue_id_t queue_id, + const char *queue_name) + : m_process_wp(), m_queue_id(queue_id), m_queue_name(), + m_running_work_items_count(0), m_pending_work_items_count(0), + m_pending_items(), m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS), + m_kind(eQueueKindUnknown) { + if (queue_name) + m_queue_name = queue_name; + + m_process_wp = process_sp; } Queue::~Queue() = default; -queue_id_t -Queue::GetID () -{ - return m_queue_id; -} +queue_id_t Queue::GetID() { return m_queue_id; } -const char * -Queue::GetName () -{ - return (m_queue_name.empty() ? nullptr : m_queue_name.c_str()); +const char *Queue::GetName() { + return (m_queue_name.empty() ? nullptr : m_queue_name.c_str()); } -uint32_t -Queue::GetIndexID () -{ - return m_queue_id; -} +uint32_t Queue::GetIndexID() { return m_queue_id; } -std::vector<lldb::ThreadSP> -Queue::GetThreads () -{ - std::vector<ThreadSP> result; - ProcessSP process_sp = m_process_wp.lock(); - if (process_sp) - { - for (ThreadSP thread_sp : process_sp->Threads()) - { - if (thread_sp->GetQueueID() == m_queue_id) - { - result.push_back (thread_sp); - } - } +std::vector<lldb::ThreadSP> Queue::GetThreads() { + std::vector<ThreadSP> result; + ProcessSP process_sp = m_process_wp.lock(); + if (process_sp) { + for (ThreadSP thread_sp : process_sp->Threads()) { + if (thread_sp->GetQueueID() == m_queue_id) { + result.push_back(thread_sp); + } } - return result; + } + return result; } -void -Queue::SetNumRunningWorkItems (uint32_t count) -{ - m_running_work_items_count = count; +void Queue::SetNumRunningWorkItems(uint32_t count) { + m_running_work_items_count = count; } -uint32_t -Queue::GetNumRunningWorkItems () const -{ - return m_running_work_items_count; +uint32_t Queue::GetNumRunningWorkItems() const { + return m_running_work_items_count; } -void -Queue::SetNumPendingWorkItems (uint32_t count) -{ - m_pending_work_items_count = count; +void Queue::SetNumPendingWorkItems(uint32_t count) { + m_pending_work_items_count = count; } -uint32_t -Queue::GetNumPendingWorkItems () const -{ - return m_pending_work_items_count; +uint32_t Queue::GetNumPendingWorkItems() const { + return m_pending_work_items_count; } -void -Queue::SetLibdispatchQueueAddress (addr_t dispatch_queue_t_addr) -{ - m_dispatch_queue_t_addr = dispatch_queue_t_addr; +void Queue::SetLibdispatchQueueAddress(addr_t dispatch_queue_t_addr) { + m_dispatch_queue_t_addr = dispatch_queue_t_addr; } -addr_t -Queue::GetLibdispatchQueueAddress () const -{ - return m_dispatch_queue_t_addr; +addr_t Queue::GetLibdispatchQueueAddress() const { + return m_dispatch_queue_t_addr; } -const std::vector<lldb::QueueItemSP> & -Queue::GetPendingItems () -{ - if (m_pending_items.empty()) - { - ProcessSP process_sp = m_process_wp.lock(); - if (process_sp && process_sp->GetSystemRuntime()) - { - process_sp->GetSystemRuntime()->PopulatePendingItemsForQueue (this); - } +const std::vector<lldb::QueueItemSP> &Queue::GetPendingItems() { + if (m_pending_items.empty()) { + ProcessSP process_sp = m_process_wp.lock(); + if (process_sp && process_sp->GetSystemRuntime()) { + process_sp->GetSystemRuntime()->PopulatePendingItemsForQueue(this); } - return m_pending_items; + } + return m_pending_items; } -lldb::QueueKind -Queue::GetKind () -{ - return m_kind; -} +lldb::QueueKind Queue::GetKind() { return m_kind; } -void -Queue::SetKind (lldb::QueueKind kind) -{ - m_kind = kind; -} +void Queue::SetKind(lldb::QueueKind kind) { m_kind = kind; } diff --git a/lldb/source/Target/QueueItem.cpp b/lldb/source/Target/QueueItem.cpp index 002187b8d20..fe58980c01c 100644 --- a/lldb/source/Target/QueueItem.cpp +++ b/lldb/source/Target/QueueItem.cpp @@ -15,142 +15,93 @@ using namespace lldb; using namespace lldb_private; -QueueItem::QueueItem (QueueSP queue_sp, ProcessSP process_sp, lldb::addr_t item_ref, lldb_private::Address address) : - m_queue_wp (), - m_process_wp (), - m_item_ref (item_ref), - m_address (address), - m_have_fetched_entire_item (false), - m_kind (eQueueItemKindUnknown), - m_item_that_enqueued_this_ref (LLDB_INVALID_ADDRESS), - m_enqueueing_thread_id (LLDB_INVALID_THREAD_ID), - m_enqueueing_queue_id (LLDB_INVALID_QUEUE_ID), - m_target_queue_id (LLDB_INVALID_QUEUE_ID), - m_stop_id (0), - m_backtrace(), - m_thread_label(), - m_queue_label(), - m_target_queue_label() -{ - m_queue_wp = queue_sp; - m_process_wp = process_sp; +QueueItem::QueueItem(QueueSP queue_sp, ProcessSP process_sp, + lldb::addr_t item_ref, lldb_private::Address address) + : m_queue_wp(), m_process_wp(), m_item_ref(item_ref), m_address(address), + m_have_fetched_entire_item(false), m_kind(eQueueItemKindUnknown), + m_item_that_enqueued_this_ref(LLDB_INVALID_ADDRESS), + m_enqueueing_thread_id(LLDB_INVALID_THREAD_ID), + m_enqueueing_queue_id(LLDB_INVALID_QUEUE_ID), + m_target_queue_id(LLDB_INVALID_QUEUE_ID), m_stop_id(0), m_backtrace(), + m_thread_label(), m_queue_label(), m_target_queue_label() { + m_queue_wp = queue_sp; + m_process_wp = process_sp; } -QueueItem::~QueueItem () -{ -} +QueueItem::~QueueItem() {} -QueueItemKind -QueueItem::GetKind() -{ - FetchEntireItem (); - return m_kind; +QueueItemKind QueueItem::GetKind() { + FetchEntireItem(); + return m_kind; } -void -QueueItem::SetKind (QueueItemKind item_kind) -{ - m_kind = item_kind; -} +void QueueItem::SetKind(QueueItemKind item_kind) { m_kind = item_kind; } -Address & -QueueItem::GetAddress () -{ - return m_address; -} +Address &QueueItem::GetAddress() { return m_address; } -void -QueueItem::SetAddress (Address addr) -{ - m_address = addr; -} +void QueueItem::SetAddress(Address addr) { m_address = addr; } -ThreadSP -QueueItem::GetExtendedBacktraceThread (ConstString type) -{ - FetchEntireItem (); - ThreadSP return_thread; - QueueSP queue_sp = m_queue_wp.lock(); - if (queue_sp) - { - ProcessSP process_sp = queue_sp->GetProcess(); - if (process_sp && process_sp->GetSystemRuntime()) - { - return_thread = process_sp->GetSystemRuntime()->GetExtendedBacktraceForQueueItem (this->shared_from_this(), type); - } +ThreadSP QueueItem::GetExtendedBacktraceThread(ConstString type) { + FetchEntireItem(); + ThreadSP return_thread; + QueueSP queue_sp = m_queue_wp.lock(); + if (queue_sp) { + ProcessSP process_sp = queue_sp->GetProcess(); + if (process_sp && process_sp->GetSystemRuntime()) { + return_thread = + process_sp->GetSystemRuntime()->GetExtendedBacktraceForQueueItem( + this->shared_from_this(), type); } - return return_thread; + } + return return_thread; } -lldb::addr_t -QueueItem::GetItemThatEnqueuedThis () -{ - FetchEntireItem (); - return m_item_that_enqueued_this_ref; +lldb::addr_t QueueItem::GetItemThatEnqueuedThis() { + FetchEntireItem(); + return m_item_that_enqueued_this_ref; } -lldb::tid_t -QueueItem::GetEnqueueingThreadID () -{ - FetchEntireItem (); - return m_enqueueing_thread_id; +lldb::tid_t QueueItem::GetEnqueueingThreadID() { + FetchEntireItem(); + return m_enqueueing_thread_id; } -lldb::queue_id_t -QueueItem::GetEnqueueingQueueID () -{ - FetchEntireItem (); - return m_enqueueing_queue_id; -} - -uint32_t -QueueItem::GetStopID () -{ - FetchEntireItem (); - return m_stop_id; +lldb::queue_id_t QueueItem::GetEnqueueingQueueID() { + FetchEntireItem(); + return m_enqueueing_queue_id; } -std::vector<lldb::addr_t> & -QueueItem::GetEnqueueingBacktrace () -{ - FetchEntireItem (); - return m_backtrace; +uint32_t QueueItem::GetStopID() { + FetchEntireItem(); + return m_stop_id; } -std::string -QueueItem::GetThreadLabel () -{ - FetchEntireItem (); - return m_thread_label; +std::vector<lldb::addr_t> &QueueItem::GetEnqueueingBacktrace() { + FetchEntireItem(); + return m_backtrace; } -std::string -QueueItem::GetQueueLabel () -{ - FetchEntireItem (); - return m_queue_label; +std::string QueueItem::GetThreadLabel() { + FetchEntireItem(); + return m_thread_label; } - -ProcessSP -QueueItem::GetProcessSP() -{ - return m_process_wp.lock (); +std::string QueueItem::GetQueueLabel() { + FetchEntireItem(); + return m_queue_label; } -void -QueueItem::FetchEntireItem() -{ - if (m_have_fetched_entire_item == true) - return; - ProcessSP process_sp = m_process_wp.lock(); - if (process_sp) - { - SystemRuntime *runtime = process_sp->GetSystemRuntime(); - if (runtime) - { - runtime->CompleteQueueItem (this, m_item_ref); - m_have_fetched_entire_item = true; - } +ProcessSP QueueItem::GetProcessSP() { return m_process_wp.lock(); } + +void QueueItem::FetchEntireItem() { + if (m_have_fetched_entire_item == true) + return; + ProcessSP process_sp = m_process_wp.lock(); + if (process_sp) { + SystemRuntime *runtime = process_sp->GetSystemRuntime(); + if (runtime) { + runtime->CompleteQueueItem(this, m_item_ref); + m_have_fetched_entire_item = true; } + } } diff --git a/lldb/source/Target/QueueList.cpp b/lldb/source/Target/QueueList.cpp index c63331db975..ae9e7b93793 100644 --- a/lldb/source/Target/QueueList.cpp +++ b/lldb/source/Target/QueueList.cpp @@ -7,92 +7,64 @@ // //===----------------------------------------------------------------------===// -#include "lldb/Target/Process.h" #include "lldb/Target/Queue.h" +#include "lldb/Target/Process.h" #include "lldb/Target/QueueList.h" using namespace lldb; using namespace lldb_private; -QueueList::QueueList(Process *process) : m_process(process), m_stop_id(0), m_queues(), m_mutex() -{ -} +QueueList::QueueList(Process *process) + : m_process(process), m_stop_id(0), m_queues(), m_mutex() {} -QueueList::~QueueList () -{ - Clear(); -} +QueueList::~QueueList() { Clear(); } -uint32_t -QueueList::GetSize () -{ - std::lock_guard<std::mutex> guard(m_mutex); - return m_queues.size(); +uint32_t QueueList::GetSize() { + std::lock_guard<std::mutex> guard(m_mutex); + return m_queues.size(); } -lldb::QueueSP -QueueList::GetQueueAtIndex (uint32_t idx) -{ - std::lock_guard<std::mutex> guard(m_mutex); - if (idx < m_queues.size()) - { - return m_queues[idx]; - } - else - { - return QueueSP(); - } +lldb::QueueSP QueueList::GetQueueAtIndex(uint32_t idx) { + std::lock_guard<std::mutex> guard(m_mutex); + if (idx < m_queues.size()) { + return m_queues[idx]; + } else { + return QueueSP(); + } } -void -QueueList::Clear () -{ - std::lock_guard<std::mutex> guard(m_mutex); - m_queues.clear(); +void QueueList::Clear() { + std::lock_guard<std::mutex> guard(m_mutex); + m_queues.clear(); } -void -QueueList::AddQueue (QueueSP queue_sp) -{ - std::lock_guard<std::mutex> guard(m_mutex); - if (queue_sp.get ()) - { - m_queues.push_back (queue_sp); - } +void QueueList::AddQueue(QueueSP queue_sp) { + std::lock_guard<std::mutex> guard(m_mutex); + if (queue_sp.get()) { + m_queues.push_back(queue_sp); + } } -lldb::QueueSP -QueueList::FindQueueByID (lldb::queue_id_t qid) -{ - QueueSP ret; - for (QueueSP queue_sp : Queues()) - { - if (queue_sp->GetID() == qid) - { - ret = queue_sp; - break; - } +lldb::QueueSP QueueList::FindQueueByID(lldb::queue_id_t qid) { + QueueSP ret; + for (QueueSP queue_sp : Queues()) { + if (queue_sp->GetID() == qid) { + ret = queue_sp; + break; } - return ret; + } + return ret; } -lldb::QueueSP -QueueList::FindQueueByIndexID (uint32_t index_id) -{ - QueueSP ret; - for (QueueSP queue_sp : Queues()) - { - if (queue_sp->GetIndexID() == index_id) - { - ret = queue_sp; - break; - } +lldb::QueueSP QueueList::FindQueueByIndexID(uint32_t index_id) { + QueueSP ret; + for (QueueSP queue_sp : Queues()) { + if (queue_sp->GetIndexID() == index_id) { + ret = queue_sp; + break; } - return ret; + } + return ret; } -std::mutex & -QueueList::GetMutex() -{ - return m_mutex; -} +std::mutex &QueueList::GetMutex() { return m_mutex; } diff --git a/lldb/source/Target/RegisterContext.cpp b/lldb/source/Target/RegisterContext.cpp index ae3c43def27..31ccd2a4a44 100644 --- a/lldb/source/Target/RegisterContext.cpp +++ b/lldb/source/Target/RegisterContext.cpp @@ -13,543 +13,455 @@ // Project includes #include "lldb/Target/RegisterContext.h" #include "lldb/Core/DataExtractor.h" +#include "lldb/Core/Module.h" #include "lldb/Core/RegisterValue.h" #include "lldb/Core/Scalar.h" +#include "lldb/Core/Value.h" +#include "lldb/Expression/DWARFExpression.h" #include "lldb/Host/Endian.h" #include "lldb/Target/ExecutionContext.h" -#include "lldb/Target/StackFrame.h" #include "lldb/Target/Process.h" -#include "lldb/Target/Thread.h" +#include "lldb/Target/StackFrame.h" #include "lldb/Target/Target.h" -#include "lldb/Core/Module.h" -#include "lldb/Expression/DWARFExpression.h" -#include "lldb/Core/Value.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; -RegisterContext::RegisterContext (Thread &thread, uint32_t concrete_frame_idx) : - m_thread (thread), - m_concrete_frame_idx (concrete_frame_idx), - m_stop_id (thread.GetProcess()->GetStopID()) -{ -} +RegisterContext::RegisterContext(Thread &thread, uint32_t concrete_frame_idx) + : m_thread(thread), m_concrete_frame_idx(concrete_frame_idx), + m_stop_id(thread.GetProcess()->GetStopID()) {} RegisterContext::~RegisterContext() = default; -void -RegisterContext::InvalidateIfNeeded (bool force) -{ - ProcessSP process_sp (m_thread.GetProcess()); - bool invalidate = force; - uint32_t process_stop_id = UINT32_MAX; +void RegisterContext::InvalidateIfNeeded(bool force) { + ProcessSP process_sp(m_thread.GetProcess()); + bool invalidate = force; + uint32_t process_stop_id = UINT32_MAX; - if (process_sp) - process_stop_id = process_sp->GetStopID(); - else - invalidate = true; - - if (!invalidate) - invalidate = process_stop_id != GetStopID(); - - if (invalidate) - { - InvalidateAllRegisters (); - SetStopID (process_stop_id); - } + if (process_sp) + process_stop_id = process_sp->GetStopID(); + else + invalidate = true; + + if (!invalidate) + invalidate = process_stop_id != GetStopID(); + + if (invalidate) { + InvalidateAllRegisters(); + SetStopID(process_stop_id); + } } -const RegisterInfo * -RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx) -{ - if (reg_name && reg_name[0]) - { - const uint32_t num_registers = GetRegisterCount(); - for (uint32_t reg = start_idx; reg < num_registers; ++reg) - { - const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); - - if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) || - (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0)) - { - return reg_info; - } - } +const RegisterInfo *RegisterContext::GetRegisterInfoByName(const char *reg_name, + uint32_t start_idx) { + if (reg_name && reg_name[0]) { + const uint32_t num_registers = GetRegisterCount(); + for (uint32_t reg = start_idx; reg < num_registers; ++reg) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + + if ((reg_info->name != nullptr && + ::strcasecmp(reg_info->name, reg_name) == 0) || + (reg_info->alt_name != nullptr && + ::strcasecmp(reg_info->alt_name, reg_name) == 0)) { + return reg_info; + } } - return nullptr; + } + return nullptr; } uint32_t -RegisterContext::UpdateDynamicRegisterSize (const lldb_private::ArchSpec &arch, - RegisterInfo* reg_info) -{ - ExecutionContext exe_ctx (CalculateThread()); - - // In MIPS, the floating point registers size is depends on FR bit of SR register. - // if SR.FR == 1 then all floating point registers are 64 bits. - // else they are all 32 bits. - - int expr_result; - uint32_t addr_size = arch.GetAddressByteSize (); - const uint8_t* dwarf_opcode_ptr = reg_info->dynamic_size_dwarf_expr_bytes; - const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; - - DataExtractor dwarf_data (dwarf_opcode_ptr, dwarf_opcode_len, - arch.GetByteOrder (), addr_size); - ModuleSP opcode_ctx; - DWARFExpression dwarf_expr (opcode_ctx, dwarf_data, nullptr, 0, dwarf_opcode_len); - Value result; - Error error; - const lldb::offset_t offset = 0; - if (dwarf_expr.Evaluate (&exe_ctx, nullptr, nullptr, this, opcode_ctx, dwarf_data, nullptr, - offset, dwarf_opcode_len, eRegisterKindDWARF, nullptr, nullptr, result, &error)) - { - expr_result = result.GetScalar ().SInt (-1); - switch (expr_result) - { - case 0: return 4; - case 1: return 8; - default: return reg_info->byte_size; - } - } - else - { - printf ("Error executing DwarfExpression::Evaluate %s\n", error.AsCString()); - return reg_info->byte_size; +RegisterContext::UpdateDynamicRegisterSize(const lldb_private::ArchSpec &arch, + RegisterInfo *reg_info) { + ExecutionContext exe_ctx(CalculateThread()); + + // In MIPS, the floating point registers size is depends on FR bit of SR + // register. + // if SR.FR == 1 then all floating point registers are 64 bits. + // else they are all 32 bits. + + int expr_result; + uint32_t addr_size = arch.GetAddressByteSize(); + const uint8_t *dwarf_opcode_ptr = reg_info->dynamic_size_dwarf_expr_bytes; + const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len; + + DataExtractor dwarf_data(dwarf_opcode_ptr, dwarf_opcode_len, + arch.GetByteOrder(), addr_size); + ModuleSP opcode_ctx; + DWARFExpression dwarf_expr(opcode_ctx, dwarf_data, nullptr, 0, + dwarf_opcode_len); + Value result; + Error error; + const lldb::offset_t offset = 0; + if (dwarf_expr.Evaluate(&exe_ctx, nullptr, nullptr, this, opcode_ctx, + dwarf_data, nullptr, offset, dwarf_opcode_len, + eRegisterKindDWARF, nullptr, nullptr, result, + &error)) { + expr_result = result.GetScalar().SInt(-1); + switch (expr_result) { + case 0: + return 4; + case 1: + return 8; + default: + return reg_info->byte_size; } + } else { + printf("Error executing DwarfExpression::Evaluate %s\n", error.AsCString()); + return reg_info->byte_size; + } } -const RegisterInfo * -RegisterContext::GetRegisterInfo (lldb::RegisterKind kind, uint32_t num) -{ - const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); - if (reg_num == LLDB_INVALID_REGNUM) - return nullptr; - return GetRegisterInfoAtIndex (reg_num); +const RegisterInfo *RegisterContext::GetRegisterInfo(lldb::RegisterKind kind, + uint32_t num) { + const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num); + if (reg_num == LLDB_INVALID_REGNUM) + return nullptr; + return GetRegisterInfoAtIndex(reg_num); } -const char * -RegisterContext::GetRegisterName (uint32_t reg) -{ - const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg); - if (reg_info) - return reg_info->name; - return nullptr; +const char *RegisterContext::GetRegisterName(uint32_t reg) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (reg_info) + return reg_info->name; + return nullptr; } -uint64_t -RegisterContext::GetPC(uint64_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - uint64_t pc = ReadRegisterAsUnsigned (reg, fail_value); - - if (pc != fail_value) - { - TargetSP target_sp = m_thread.CalculateTarget(); - if (target_sp) - { - Target *target = target_sp.get(); - if (target) - pc = target->GetOpcodeLoadAddress (pc, eAddressClassCode); - } - } +uint64_t RegisterContext::GetPC(uint64_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); + uint64_t pc = ReadRegisterAsUnsigned(reg, fail_value); - return pc; -} - -bool -RegisterContext::SetPC(uint64_t pc) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); - bool success = WriteRegisterFromUnsigned (reg, pc); - if (success) - { - StackFrameSP frame_sp(m_thread.GetFrameWithConcreteFrameIndex (m_concrete_frame_idx)); - if (frame_sp) - frame_sp->ChangePC(pc); - else - m_thread.ClearStackFrames (); + if (pc != fail_value) { + TargetSP target_sp = m_thread.CalculateTarget(); + if (target_sp) { + Target *target = target_sp.get(); + if (target) + pc = target->GetOpcodeLoadAddress(pc, eAddressClassCode); } - return success; + } + + return pc; } -bool -RegisterContext::SetPC(Address addr) -{ - TargetSP target_sp = m_thread.CalculateTarget(); - Target *target = target_sp.get(); +bool RegisterContext::SetPC(uint64_t pc) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_PC); + bool success = WriteRegisterFromUnsigned(reg, pc); + if (success) { + StackFrameSP frame_sp( + m_thread.GetFrameWithConcreteFrameIndex(m_concrete_frame_idx)); + if (frame_sp) + frame_sp->ChangePC(pc); + else + m_thread.ClearStackFrames(); + } + return success; +} - lldb::addr_t callAddr = addr.GetCallableLoadAddress (target); - if (callAddr == LLDB_INVALID_ADDRESS) - return false; +bool RegisterContext::SetPC(Address addr) { + TargetSP target_sp = m_thread.CalculateTarget(); + Target *target = target_sp.get(); - return SetPC (callAddr); -} + lldb::addr_t callAddr = addr.GetCallableLoadAddress(target); + if (callAddr == LLDB_INVALID_ADDRESS) + return false; -uint64_t -RegisterContext::GetSP(uint64_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - return ReadRegisterAsUnsigned (reg, fail_value); + return SetPC(callAddr); } -bool -RegisterContext::SetSP(uint64_t sp) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP); - return WriteRegisterFromUnsigned (reg, sp); +uint64_t RegisterContext::GetSP(uint64_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_SP); + return ReadRegisterAsUnsigned(reg, fail_value); } -uint64_t -RegisterContext::GetFP(uint64_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); - return ReadRegisterAsUnsigned (reg, fail_value); +bool RegisterContext::SetSP(uint64_t sp) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_SP); + return WriteRegisterFromUnsigned(reg, sp); } -bool -RegisterContext::SetFP(uint64_t fp) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP); - return WriteRegisterFromUnsigned (reg, fp); +uint64_t RegisterContext::GetFP(uint64_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_FP); + return ReadRegisterAsUnsigned(reg, fail_value); } -uint64_t -RegisterContext::GetReturnAddress (uint64_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA); - return ReadRegisterAsUnsigned (reg, fail_value); +bool RegisterContext::SetFP(uint64_t fp) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_FP); + return WriteRegisterFromUnsigned(reg, fp); } -uint64_t -RegisterContext::GetFlags (uint64_t fail_value) -{ - uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); - return ReadRegisterAsUnsigned (reg, fail_value); +uint64_t RegisterContext::GetReturnAddress(uint64_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_RA); + return ReadRegisterAsUnsigned(reg, fail_value); } -uint64_t -RegisterContext::ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value) -{ - if (reg != LLDB_INVALID_REGNUM) - return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value); - return fail_value; +uint64_t RegisterContext::GetFlags(uint64_t fail_value) { + uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, + LLDB_REGNUM_GENERIC_FLAGS); + return ReadRegisterAsUnsigned(reg, fail_value); } -uint64_t -RegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, uint64_t fail_value) -{ - if (reg_info) - { - RegisterValue value; - if (ReadRegister (reg_info, value)) - return value.GetAsUInt64(); - } - return fail_value; +uint64_t RegisterContext::ReadRegisterAsUnsigned(uint32_t reg, + uint64_t fail_value) { + if (reg != LLDB_INVALID_REGNUM) + return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value); + return fail_value; } -bool -RegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval) -{ - if (reg == LLDB_INVALID_REGNUM) - return false; - return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval); +uint64_t RegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info, + uint64_t fail_value) { + if (reg_info) { + RegisterValue value; + if (ReadRegister(reg_info, value)) + return value.GetAsUInt64(); + } + return fail_value; } -bool -RegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval) -{ - if (reg_info) - { - RegisterValue value; - if (value.SetUInt(uval, reg_info->byte_size)) - return WriteRegister (reg_info, value); - } +bool RegisterContext::WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval) { + if (reg == LLDB_INVALID_REGNUM) return false; + return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval); } -bool -RegisterContext::CopyFromRegisterContext (lldb::RegisterContextSP context) -{ - uint32_t num_register_sets = context->GetRegisterSetCount(); - // We don't know that two threads have the same register context, so require the threads to be the same. - if (context->GetThreadID() != GetThreadID()) - return false; - - if (num_register_sets != GetRegisterSetCount()) - return false; - - RegisterContextSP frame_zero_context = m_thread.GetRegisterContext(); - - for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx) - { - const RegisterSet * const reg_set = GetRegisterSet(set_idx); - - const uint32_t num_registers = reg_set->num_registers; - for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) - { - const uint32_t reg = reg_set->registers[reg_idx]; - const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); - if (!reg_info || reg_info->value_regs) - continue; - RegisterValue reg_value; - - // If we can reconstruct the register from the frame we are copying from, then do so, otherwise - // use the value from frame 0. - if (context->ReadRegister(reg_info, reg_value)) - { - WriteRegister(reg_info, reg_value); - } - else if (frame_zero_context->ReadRegister(reg_info, reg_value)) - { - WriteRegister(reg_info, reg_value); - } - } - } - return true; +bool RegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info, + uint64_t uval) { + if (reg_info) { + RegisterValue value; + if (value.SetUInt(uval, reg_info->byte_size)) + return WriteRegister(reg_info, value); + } + return false; } -lldb::tid_t -RegisterContext::GetThreadID() const -{ - return m_thread.GetID(); -} +bool RegisterContext::CopyFromRegisterContext(lldb::RegisterContextSP context) { + uint32_t num_register_sets = context->GetRegisterSetCount(); + // We don't know that two threads have the same register context, so require + // the threads to be the same. + if (context->GetThreadID() != GetThreadID()) + return false; -uint32_t -RegisterContext::NumSupportedHardwareBreakpoints () -{ - return 0; -} + if (num_register_sets != GetRegisterSetCount()) + return false; -uint32_t -RegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size) -{ - return LLDB_INVALID_INDEX32; + RegisterContextSP frame_zero_context = m_thread.GetRegisterContext(); + + for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx) { + const RegisterSet *const reg_set = GetRegisterSet(set_idx); + + const uint32_t num_registers = reg_set->num_registers; + for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) { + const uint32_t reg = reg_set->registers[reg_idx]; + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + if (!reg_info || reg_info->value_regs) + continue; + RegisterValue reg_value; + + // If we can reconstruct the register from the frame we are copying from, + // then do so, otherwise + // use the value from frame 0. + if (context->ReadRegister(reg_info, reg_value)) { + WriteRegister(reg_info, reg_value); + } else if (frame_zero_context->ReadRegister(reg_info, reg_value)) { + WriteRegister(reg_info, reg_value); + } + } + } + return true; } -bool -RegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx) -{ - return false; -} +lldb::tid_t RegisterContext::GetThreadID() const { return m_thread.GetID(); } -uint32_t -RegisterContext::NumSupportedHardwareWatchpoints () -{ - return 0; -} +uint32_t RegisterContext::NumSupportedHardwareBreakpoints() { return 0; } -uint32_t -RegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write) -{ - return LLDB_INVALID_INDEX32; +uint32_t RegisterContext::SetHardwareBreakpoint(lldb::addr_t addr, + size_t size) { + return LLDB_INVALID_INDEX32; } -bool -RegisterContext::ClearHardwareWatchpoint (uint32_t hw_index) -{ - return false; +bool RegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { return false; } + +uint32_t RegisterContext::NumSupportedHardwareWatchpoints() { return 0; } + +uint32_t RegisterContext::SetHardwareWatchpoint(lldb::addr_t addr, size_t size, + bool read, bool write) { + return LLDB_INVALID_INDEX32; } -bool -RegisterContext::HardwareSingleStep (bool enable) -{ - return false; +bool RegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) { + return false; } -Error -RegisterContext::ReadRegisterValueFromMemory (const RegisterInfo *reg_info, - lldb::addr_t src_addr, - uint32_t src_len, - RegisterValue ®_value) -{ - Error error; - if (reg_info == nullptr) - { - error.SetErrorString ("invalid register info argument."); - return error; - } +bool RegisterContext::HardwareSingleStep(bool enable) { return false; } - // Moving from addr into a register - // - // Case 1: src_len == dst_len - // - // |AABBCCDD| Address contents - // |AABBCCDD| Register contents - // - // Case 2: src_len > dst_len - // - // Error! (The register should always be big enough to hold the data) - // - // Case 3: src_len < dst_len - // - // |AABB| Address contents - // |AABB0000| Register contents [on little-endian hardware] - // |0000AABB| Register contents [on big-endian hardware] - if (src_len > RegisterValue::kMaxRegisterByteSize) - { - error.SetErrorString ("register too small to receive memory data"); - return error; - } - - const uint32_t dst_len = reg_info->byte_size; - - if (src_len > dst_len) - { - error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len); - return error; - } - - ProcessSP process_sp (m_thread.GetProcess()); - if (process_sp) - { - uint8_t src[RegisterValue::kMaxRegisterByteSize]; - - // Read the memory - const uint32_t bytes_read = process_sp->ReadMemory (src_addr, src, src_len, error); - - // Make sure the memory read succeeded... - if (bytes_read != src_len) - { - if (error.Success()) - { - // This might happen if we read _some_ bytes but not all - error.SetErrorStringWithFormat("read %u of %u bytes", bytes_read, src_len); - } - return error; - } - - // We now have a memory buffer that contains the part or all of the register - // value. Set the register value using this memory data. - // TODO: we might need to add a parameter to this function in case the byte - // order of the memory data doesn't match the process. For now we are assuming - // they are the same. - reg_value.SetFromMemoryData (reg_info, - src, - src_len, - process_sp->GetByteOrder(), - error); - } - else - error.SetErrorString("invalid process"); +Error RegisterContext::ReadRegisterValueFromMemory(const RegisterInfo *reg_info, + lldb::addr_t src_addr, + uint32_t src_len, + RegisterValue ®_value) { + Error error; + if (reg_info == nullptr) { + error.SetErrorString("invalid register info argument."); + return error; + } + + // Moving from addr into a register + // + // Case 1: src_len == dst_len + // + // |AABBCCDD| Address contents + // |AABBCCDD| Register contents + // + // Case 2: src_len > dst_len + // + // Error! (The register should always be big enough to hold the data) + // + // Case 3: src_len < dst_len + // + // |AABB| Address contents + // |AABB0000| Register contents [on little-endian hardware] + // |0000AABB| Register contents [on big-endian hardware] + if (src_len > RegisterValue::kMaxRegisterByteSize) { + error.SetErrorString("register too small to receive memory data"); + return error; + } + const uint32_t dst_len = reg_info->byte_size; + + if (src_len > dst_len) { + error.SetErrorStringWithFormat( + "%u bytes is too big to store in register %s (%u bytes)", src_len, + reg_info->name, dst_len); return error; -} + } + + ProcessSP process_sp(m_thread.GetProcess()); + if (process_sp) { + uint8_t src[RegisterValue::kMaxRegisterByteSize]; + + // Read the memory + const uint32_t bytes_read = + process_sp->ReadMemory(src_addr, src, src_len, error); + + // Make sure the memory read succeeded... + if (bytes_read != src_len) { + if (error.Success()) { + // This might happen if we read _some_ bytes but not all + error.SetErrorStringWithFormat("read %u of %u bytes", bytes_read, + src_len); + } + return error; + } -Error -RegisterContext::WriteRegisterValueToMemory (const RegisterInfo *reg_info, - lldb::addr_t dst_addr, - uint32_t dst_len, - const RegisterValue ®_value) -{ - uint8_t dst[RegisterValue::kMaxRegisterByteSize]; - - Error error; - - ProcessSP process_sp (m_thread.GetProcess()); - if (process_sp) - { - - // TODO: we might need to add a parameter to this function in case the byte - // order of the memory data doesn't match the process. For now we are assuming - // they are the same. - - const uint32_t bytes_copied = reg_value.GetAsMemoryData (reg_info, - dst, - dst_len, - process_sp->GetByteOrder(), - error); - - if (error.Success()) - { - if (bytes_copied == 0) - { - error.SetErrorString("byte copy failed."); - } - else - { - const uint32_t bytes_written = process_sp->WriteMemory (dst_addr, dst, bytes_copied, error); - if (bytes_written != bytes_copied) - { - if (error.Success()) - { - // This might happen if we read _some_ bytes but not all - error.SetErrorStringWithFormat("only wrote %u of %u bytes", bytes_written, bytes_copied); - } - } - } + // We now have a memory buffer that contains the part or all of the register + // value. Set the register value using this memory data. + // TODO: we might need to add a parameter to this function in case the byte + // order of the memory data doesn't match the process. For now we are + // assuming + // they are the same. + reg_value.SetFromMemoryData(reg_info, src, src_len, + process_sp->GetByteOrder(), error); + } else + error.SetErrorString("invalid process"); + + return error; +} + +Error RegisterContext::WriteRegisterValueToMemory( + const RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len, + const RegisterValue ®_value) { + uint8_t dst[RegisterValue::kMaxRegisterByteSize]; + + Error error; + + ProcessSP process_sp(m_thread.GetProcess()); + if (process_sp) { + + // TODO: we might need to add a parameter to this function in case the byte + // order of the memory data doesn't match the process. For now we are + // assuming + // they are the same. + + const uint32_t bytes_copied = reg_value.GetAsMemoryData( + reg_info, dst, dst_len, process_sp->GetByteOrder(), error); + + if (error.Success()) { + if (bytes_copied == 0) { + error.SetErrorString("byte copy failed."); + } else { + const uint32_t bytes_written = + process_sp->WriteMemory(dst_addr, dst, bytes_copied, error); + if (bytes_written != bytes_copied) { + if (error.Success()) { + // This might happen if we read _some_ bytes but not all + error.SetErrorStringWithFormat("only wrote %u of %u bytes", + bytes_written, bytes_copied); + } } + } } - else - error.SetErrorString("invalid process"); + } else + error.SetErrorString("invalid process"); - return error; + return error; } -bool -RegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint) -{ - return ReadAllRegisterValues(reg_checkpoint.GetData()); +bool RegisterContext::ReadAllRegisterValues( + lldb_private::RegisterCheckpoint ®_checkpoint) { + return ReadAllRegisterValues(reg_checkpoint.GetData()); } -bool -RegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint) -{ - return WriteAllRegisterValues(reg_checkpoint.GetData()); +bool RegisterContext::WriteAllRegisterValues( + const lldb_private::RegisterCheckpoint ®_checkpoint) { + return WriteAllRegisterValues(reg_checkpoint.GetData()); } -TargetSP -RegisterContext::CalculateTarget () -{ - return m_thread.CalculateTarget(); +TargetSP RegisterContext::CalculateTarget() { + return m_thread.CalculateTarget(); } -ProcessSP -RegisterContext::CalculateProcess () -{ - return m_thread.CalculateProcess (); +ProcessSP RegisterContext::CalculateProcess() { + return m_thread.CalculateProcess(); } -ThreadSP -RegisterContext::CalculateThread () -{ - return m_thread.shared_from_this(); +ThreadSP RegisterContext::CalculateThread() { + return m_thread.shared_from_this(); } -StackFrameSP -RegisterContext::CalculateStackFrame () -{ - // Register contexts might belong to many frames if we have inlined - // functions inside a frame since all inlined functions share the - // same registers, so we can't definitively say which frame we come from... - return StackFrameSP(); +StackFrameSP RegisterContext::CalculateStackFrame() { + // Register contexts might belong to many frames if we have inlined + // functions inside a frame since all inlined functions share the + // same registers, so we can't definitively say which frame we come from... + return StackFrameSP(); } -void -RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx) -{ - m_thread.CalculateExecutionContext (exe_ctx); +void RegisterContext::CalculateExecutionContext(ExecutionContext &exe_ctx) { + m_thread.CalculateExecutionContext(exe_ctx); } -bool -RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum) -{ - const uint32_t num_registers = GetRegisterCount(); - for (uint32_t reg = 0; reg < num_registers; ++reg) - { - const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg); - - if (reg_info->kinds[source_rk] == source_regnum) - { - target_regnum = reg_info->kinds[target_rk]; - return (target_regnum != LLDB_INVALID_REGNUM); - } +bool RegisterContext::ConvertBetweenRegisterKinds(lldb::RegisterKind source_rk, + uint32_t source_regnum, + lldb::RegisterKind target_rk, + uint32_t &target_regnum) { + const uint32_t num_registers = GetRegisterCount(); + for (uint32_t reg = 0; reg < num_registers; ++reg) { + const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg); + + if (reg_info->kinds[source_rk] == source_regnum) { + target_regnum = reg_info->kinds[target_rk]; + return (target_regnum != LLDB_INVALID_REGNUM); } - return false; + } + return false; } -//bool -//RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value) +// bool +// RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value) //{ // DataExtractor data; // if (!ReadRegisterBytes (reg, data)) @@ -594,7 +506,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case 1: // { // int8_t v; -// if (data.ExtractBytes (0, sizeof (int8_t), endian::InlHostByteOrder(), &v) != sizeof (int8_t)) +// if (data.ExtractBytes (0, sizeof (int8_t), +// endian::InlHostByteOrder(), &v) != sizeof (int8_t)) // return false; // value = v; // return true; @@ -602,7 +515,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case 2: // { // int16_t v; -// if (data.ExtractBytes (0, sizeof (int16_t), endian::InlHostByteOrder(), &v) != sizeof (int16_t)) +// if (data.ExtractBytes (0, sizeof (int16_t), +// endian::InlHostByteOrder(), &v) != sizeof (int16_t)) // return false; // value = v; // return true; @@ -610,7 +524,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case 4: // { // int32_t v; -// if (data.ExtractBytes (0, sizeof (int32_t), endian::InlHostByteOrder(), &v) != sizeof (int32_t)) +// if (data.ExtractBytes (0, sizeof (int32_t), +// endian::InlHostByteOrder(), &v) != sizeof (int32_t)) // return false; // value = v; // return true; @@ -618,7 +533,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case 8: // { // int64_t v; -// if (data.ExtractBytes (0, sizeof (int64_t), endian::InlHostByteOrder(), &v) != sizeof (int64_t)) +// if (data.ExtractBytes (0, sizeof (int64_t), +// endian::InlHostByteOrder(), &v) != sizeof (int64_t)) // return false; // value = v; // return true; @@ -631,7 +547,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case sizeof (float): // { // float v; -// if (data.ExtractBytes (0, sizeof (float), endian::InlHostByteOrder(), &v) != sizeof (float)) +// if (data.ExtractBytes (0, sizeof (float), +// endian::InlHostByteOrder(), &v) != sizeof (float)) // return false; // value = v; // return true; @@ -639,7 +556,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case sizeof (double): // { // double v; -// if (data.ExtractBytes (0, sizeof (double), endian::InlHostByteOrder(), &v) != sizeof (double)) +// if (data.ExtractBytes (0, sizeof (double), +// endian::InlHostByteOrder(), &v) != sizeof (double)) // return false; // value = v; // return true; @@ -647,7 +565,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // case sizeof (long double): // { // double v; -// if (data.ExtractBytes (0, sizeof (long double), endian::InlHostByteOrder(), &v) != sizeof (long double)) +// if (data.ExtractBytes (0, sizeof (long double), +// endian::InlHostByteOrder(), &v) != sizeof (long double)) // return false; // value = v; // return true; @@ -658,8 +577,8 @@ RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint // return false; //} // -//bool -//RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value) +// bool +// RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value) //{ // DataExtractor data; // if (!value.IsValid()) diff --git a/lldb/source/Target/SectionLoadHistory.cpp b/lldb/source/Target/SectionLoadHistory.cpp index 196d5b07db2..49a7cef8e39 100644 --- a/lldb/source/Target/SectionLoadHistory.cpp +++ b/lldb/source/Target/SectionLoadHistory.cpp @@ -19,161 +19,154 @@ using namespace lldb; using namespace lldb_private; - -bool -SectionLoadHistory::IsEmpty() const -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - return m_stop_id_to_section_load_list.empty(); +bool SectionLoadHistory::IsEmpty() const { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + return m_stop_id_to_section_load_list.empty(); } -void -SectionLoadHistory::Clear () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_stop_id_to_section_load_list.clear(); +void SectionLoadHistory::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_stop_id_to_section_load_list.clear(); } -uint32_t -SectionLoadHistory::GetLastStopID() const -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_stop_id_to_section_load_list.empty()) - return 0; - else - return m_stop_id_to_section_load_list.rbegin()->first; +uint32_t SectionLoadHistory::GetLastStopID() const { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_stop_id_to_section_load_list.empty()) + return 0; + else + return m_stop_id_to_section_load_list.rbegin()->first; } SectionLoadList * -SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_only) -{ - if (!m_stop_id_to_section_load_list.empty()) - { - if (read_only) - { - // The section load list is for reading data only so we don't need to create - // a new SectionLoadList for the current stop ID, just return the section - // load list for the stop ID that is equal to or less than the current stop ID - if (stop_id == eStopIDNow) - { - // If we are asking for the latest and greatest value, it is always - // at the end of our list because that will be the highest stop ID. - StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin(); - return rpos->second.get(); - } - else - { - StopIDToSectionLoadList::iterator pos = m_stop_id_to_section_load_list.lower_bound(stop_id); - if (pos != m_stop_id_to_section_load_list.end() && pos->first == stop_id) - return pos->second.get(); - else if (pos != m_stop_id_to_section_load_list.begin()) - { - --pos; - return pos->second.get(); - } - } - } - else - { - // You can only use "eStopIDNow" when reading from the section load history - assert(stop_id != eStopIDNow); - - // We are updating the section load list (not read only), so if the stop ID - // passed in isn't the same as the last stop ID in our collection, then create - // a new node using the current stop ID - StopIDToSectionLoadList::iterator pos = m_stop_id_to_section_load_list.lower_bound(stop_id); - if (pos != m_stop_id_to_section_load_list.end() && pos->first == stop_id) - { - // We already have an entry for this value - return pos->second.get(); - } - - // We must make a new section load list that is based on the last valid - // section load list, so here we copy the last section load list and add - // a new node for the current stop ID. - StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin(); - SectionLoadListSP section_load_list_sp(new SectionLoadList(*rpos->second.get())); - m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; - return section_load_list_sp.get(); +SectionLoadHistory::GetSectionLoadListForStopID(uint32_t stop_id, + bool read_only) { + if (!m_stop_id_to_section_load_list.empty()) { + if (read_only) { + // The section load list is for reading data only so we don't need to + // create + // a new SectionLoadList for the current stop ID, just return the section + // load list for the stop ID that is equal to or less than the current + // stop ID + if (stop_id == eStopIDNow) { + // If we are asking for the latest and greatest value, it is always + // at the end of our list because that will be the highest stop ID. + StopIDToSectionLoadList::reverse_iterator rpos = + m_stop_id_to_section_load_list.rbegin(); + return rpos->second.get(); + } else { + StopIDToSectionLoadList::iterator pos = + m_stop_id_to_section_load_list.lower_bound(stop_id); + if (pos != m_stop_id_to_section_load_list.end() && + pos->first == stop_id) + return pos->second.get(); + else if (pos != m_stop_id_to_section_load_list.begin()) { + --pos; + return pos->second.get(); } + } + } else { + // You can only use "eStopIDNow" when reading from the section load + // history + assert(stop_id != eStopIDNow); + + // We are updating the section load list (not read only), so if the stop + // ID + // passed in isn't the same as the last stop ID in our collection, then + // create + // a new node using the current stop ID + StopIDToSectionLoadList::iterator pos = + m_stop_id_to_section_load_list.lower_bound(stop_id); + if (pos != m_stop_id_to_section_load_list.end() && + pos->first == stop_id) { + // We already have an entry for this value + return pos->second.get(); + } + + // We must make a new section load list that is based on the last valid + // section load list, so here we copy the last section load list and add + // a new node for the current stop ID. + StopIDToSectionLoadList::reverse_iterator rpos = + m_stop_id_to_section_load_list.rbegin(); + SectionLoadListSP section_load_list_sp( + new SectionLoadList(*rpos->second.get())); + m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; + return section_load_list_sp.get(); } - SectionLoadListSP section_load_list_sp(new SectionLoadList()); - if (stop_id == eStopIDNow) - stop_id = 0; - m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; - return section_load_list_sp.get(); + } + SectionLoadListSP section_load_list_sp(new SectionLoadList()); + if (stop_id == eStopIDNow) + stop_id = 0; + m_stop_id_to_section_load_list[stop_id] = section_load_list_sp; + return section_load_list_sp.get(); } -SectionLoadList & -SectionLoadHistory::GetCurrentSectionLoadList () -{ - const bool read_only = true; - std::lock_guard<std::recursive_mutex> guard(m_mutex); - SectionLoadList *section_load_list = GetSectionLoadListForStopID (eStopIDNow, read_only); - assert(section_load_list != NULL); - return *section_load_list; +SectionLoadList &SectionLoadHistory::GetCurrentSectionLoadList() { + const bool read_only = true; + std::lock_guard<std::recursive_mutex> guard(m_mutex); + SectionLoadList *section_load_list = + GetSectionLoadListForStopID(eStopIDNow, read_only); + assert(section_load_list != NULL); + return *section_load_list; } addr_t -SectionLoadHistory::GetSectionLoadAddress (uint32_t stop_id, const lldb::SectionSP §ion_sp) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const bool read_only = true; - SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); - return section_load_list->GetSectionLoadAddress(section_sp); +SectionLoadHistory::GetSectionLoadAddress(uint32_t stop_id, + const lldb::SectionSP §ion_sp) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const bool read_only = true; + SectionLoadList *section_load_list = + GetSectionLoadListForStopID(stop_id, read_only); + return section_load_list->GetSectionLoadAddress(section_sp); } -bool -SectionLoadHistory::ResolveLoadAddress (uint32_t stop_id, addr_t load_addr, Address &so_addr) -{ - // First find the top level section that this load address exists in - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const bool read_only = true; - SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); - return section_load_list->ResolveLoadAddress (load_addr, so_addr); +bool SectionLoadHistory::ResolveLoadAddress(uint32_t stop_id, addr_t load_addr, + Address &so_addr) { + // First find the top level section that this load address exists in + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const bool read_only = true; + SectionLoadList *section_load_list = + GetSectionLoadListForStopID(stop_id, read_only); + return section_load_list->ResolveLoadAddress(load_addr, so_addr); } -bool -SectionLoadHistory::SetSectionLoadAddress (uint32_t stop_id, - const lldb::SectionSP §ion_sp, - addr_t load_addr, - bool warn_multiple) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const bool read_only = false; - SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); - return section_load_list->SetSectionLoadAddress(section_sp, load_addr, warn_multiple); +bool SectionLoadHistory::SetSectionLoadAddress( + uint32_t stop_id, const lldb::SectionSP §ion_sp, addr_t load_addr, + bool warn_multiple) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const bool read_only = false; + SectionLoadList *section_load_list = + GetSectionLoadListForStopID(stop_id, read_only); + return section_load_list->SetSectionLoadAddress(section_sp, load_addr, + warn_multiple); } size_t -SectionLoadHistory::SetSectionUnloaded (uint32_t stop_id, const lldb::SectionSP §ion_sp) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const bool read_only = false; - SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); - return section_load_list->SetSectionUnloaded (section_sp); +SectionLoadHistory::SetSectionUnloaded(uint32_t stop_id, + const lldb::SectionSP §ion_sp) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const bool read_only = false; + SectionLoadList *section_load_list = + GetSectionLoadListForStopID(stop_id, read_only); + return section_load_list->SetSectionUnloaded(section_sp); } -bool -SectionLoadHistory::SetSectionUnloaded (uint32_t stop_id, const lldb::SectionSP §ion_sp, addr_t load_addr) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const bool read_only = false; - SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only); - return section_load_list->SetSectionUnloaded (section_sp, load_addr); +bool SectionLoadHistory::SetSectionUnloaded(uint32_t stop_id, + const lldb::SectionSP §ion_sp, + addr_t load_addr) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const bool read_only = false; + SectionLoadList *section_load_list = + GetSectionLoadListForStopID(stop_id, read_only); + return section_load_list->SetSectionUnloaded(section_sp, load_addr); } -void -SectionLoadHistory::Dump (Stream &s, Target *target) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - StopIDToSectionLoadList::iterator pos, end = m_stop_id_to_section_load_list.end(); - for (pos = m_stop_id_to_section_load_list.begin(); pos != end; ++pos) - { - s.Printf("StopID = %u:\n", pos->first); - pos->second->Dump(s, target); - s.EOL(); - } +void SectionLoadHistory::Dump(Stream &s, Target *target) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + StopIDToSectionLoadList::iterator pos, + end = m_stop_id_to_section_load_list.end(); + for (pos = m_stop_id_to_section_load_list.begin(); pos != end; ++pos) { + s.Printf("StopID = %u:\n", pos->first); + pos->second->Dump(s, target); + s.EOL(); + } } - - diff --git a/lldb/source/Target/SectionLoadList.cpp b/lldb/source/Target/SectionLoadList.cpp index 1235a379550..a3599dd10e5 100644 --- a/lldb/source/Target/SectionLoadList.cpp +++ b/lldb/source/Target/SectionLoadList.cpp @@ -24,275 +24,244 @@ using namespace lldb; using namespace lldb_private; -SectionLoadList::SectionLoadList(const SectionLoadList &rhs) : m_addr_to_sect(), m_sect_to_addr(), m_mutex() -{ - std::lock_guard<std::recursive_mutex> guard(rhs.m_mutex); - m_addr_to_sect = rhs.m_addr_to_sect; - m_sect_to_addr = rhs.m_sect_to_addr; +SectionLoadList::SectionLoadList(const SectionLoadList &rhs) + : m_addr_to_sect(), m_sect_to_addr(), m_mutex() { + std::lock_guard<std::recursive_mutex> guard(rhs.m_mutex); + m_addr_to_sect = rhs.m_addr_to_sect; + m_sect_to_addr = rhs.m_sect_to_addr; } -void -SectionLoadList::operator=(const SectionLoadList &rhs) -{ - std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex); - std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex); - m_addr_to_sect = rhs.m_addr_to_sect; - m_sect_to_addr = rhs.m_sect_to_addr; +void SectionLoadList::operator=(const SectionLoadList &rhs) { + std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex); + std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex); + m_addr_to_sect = rhs.m_addr_to_sect; + m_sect_to_addr = rhs.m_sect_to_addr; } -bool -SectionLoadList::IsEmpty() const -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - return m_addr_to_sect.empty(); +bool SectionLoadList::IsEmpty() const { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + return m_addr_to_sect.empty(); } -void -SectionLoadList::Clear () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_addr_to_sect.clear(); - m_sect_to_addr.clear(); +void SectionLoadList::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_addr_to_sect.clear(); + m_sect_to_addr.clear(); } addr_t -SectionLoadList::GetSectionLoadAddress (const lldb::SectionSP §ion) const -{ - // TODO: add support for the same section having multiple load addresses - addr_t section_load_addr = LLDB_INVALID_ADDRESS; - if (section) - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - sect_to_addr_collection::const_iterator pos = m_sect_to_addr.find (section.get()); - - if (pos != m_sect_to_addr.end()) - section_load_addr = pos->second; - } - return section_load_addr; +SectionLoadList::GetSectionLoadAddress(const lldb::SectionSP §ion) const { + // TODO: add support for the same section having multiple load addresses + addr_t section_load_addr = LLDB_INVALID_ADDRESS; + if (section) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + sect_to_addr_collection::const_iterator pos = + m_sect_to_addr.find(section.get()); + + if (pos != m_sect_to_addr.end()) + section_load_addr = pos->second; + } + return section_load_addr; } -bool -SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP §ion, addr_t load_addr, bool warn_multiple) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE)); +bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP §ion, + addr_t load_addr, + bool warn_multiple) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER | + LIBLLDB_LOG_VERBOSE)); - ModuleSP module_sp (section->GetModule()); + ModuleSP module_sp(section->GetModule()); - if (module_sp) - { - if (log) - { - const FileSpec &module_file_spec (module_sp->GetFileSpec()); - log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ") module = %p", - __FUNCTION__, static_cast<void*>(section.get()), - module_file_spec.GetPath().c_str(), - section->GetName().AsCString(), load_addr, - static_cast<void*>(module_sp.get())); - } + if (module_sp) { + if (log) { + const FileSpec &module_file_spec(module_sp->GetFileSpec()); + log->Printf("SectionLoadList::%s (section = %p (%s.%s), load_addr = " + "0x%16.16" PRIx64 ") module = %p", + __FUNCTION__, static_cast<void *>(section.get()), + module_file_spec.GetPath().c_str(), + section->GetName().AsCString(), load_addr, + static_cast<void *>(module_sp.get())); + } - if (section->GetByteSize() == 0) - return false; // No change + if (section->GetByteSize() == 0) + return false; // No change - // Fill in the section -> load_addr map - std::lock_guard<std::recursive_mutex> guard(m_mutex); - sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section.get()); - if (sta_pos != m_sect_to_addr.end()) - { - if (load_addr == sta_pos->second) - return false; // No change... - else - sta_pos->second = load_addr; - } - else - m_sect_to_addr[section.get()] = load_addr; + // Fill in the section -> load_addr map + std::lock_guard<std::recursive_mutex> guard(m_mutex); + sect_to_addr_collection::iterator sta_pos = + m_sect_to_addr.find(section.get()); + if (sta_pos != m_sect_to_addr.end()) { + if (load_addr == sta_pos->second) + return false; // No change... + else + sta_pos->second = load_addr; + } else + m_sect_to_addr[section.get()] = load_addr; - // Fill in the load_addr -> section map - addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr); - if (ats_pos != m_addr_to_sect.end()) - { - // Some sections are ok to overlap, and for others we should warn. When - // we have multiple load addresses that correspond to a section, we will - // always attribute the section to the be last section that claims it - // exists at that address. Sometimes it is ok for more that one section - // to be loaded at a specific load address, and other times it isn't. - // The "warn_multiple" parameter tells us if we should warn in this case - // or not. The DynamicLoader plug-in subclasses should know which - // sections should warn and which shouldn't (darwin shared cache modules - // all shared the same "__LINKEDIT" sections, so the dynamic loader can - // pass false for "warn_multiple"). - if (warn_multiple && section != ats_pos->second) - { - ModuleSP module_sp (section->GetModule()); - if (module_sp) - { - ModuleSP curr_module_sp (ats_pos->second->GetModule()); - if (curr_module_sp) - { - module_sp->ReportWarning ("address 0x%16.16" PRIx64 " maps to more than one section: %s.%s and %s.%s", - load_addr, - module_sp->GetFileSpec().GetFilename().GetCString(), - section->GetName().GetCString(), - curr_module_sp->GetFileSpec().GetFilename().GetCString(), - ats_pos->second->GetName().GetCString()); - } - } - } - ats_pos->second = section; + // Fill in the load_addr -> section map + addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr); + if (ats_pos != m_addr_to_sect.end()) { + // Some sections are ok to overlap, and for others we should warn. When + // we have multiple load addresses that correspond to a section, we will + // always attribute the section to the be last section that claims it + // exists at that address. Sometimes it is ok for more that one section + // to be loaded at a specific load address, and other times it isn't. + // The "warn_multiple" parameter tells us if we should warn in this case + // or not. The DynamicLoader plug-in subclasses should know which + // sections should warn and which shouldn't (darwin shared cache modules + // all shared the same "__LINKEDIT" sections, so the dynamic loader can + // pass false for "warn_multiple"). + if (warn_multiple && section != ats_pos->second) { + ModuleSP module_sp(section->GetModule()); + if (module_sp) { + ModuleSP curr_module_sp(ats_pos->second->GetModule()); + if (curr_module_sp) { + module_sp->ReportWarning( + "address 0x%16.16" PRIx64 + " maps to more than one section: %s.%s and %s.%s", + load_addr, module_sp->GetFileSpec().GetFilename().GetCString(), + section->GetName().GetCString(), + curr_module_sp->GetFileSpec().GetFilename().GetCString(), + ats_pos->second->GetName().GetCString()); + } } - else - m_addr_to_sect[load_addr] = section; - return true; // Changed + } + ats_pos->second = section; + } else + m_addr_to_sect[load_addr] = section; + return true; // Changed + } else { + if (log) { + log->Printf( + "SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 + ") error: module has been deleted", + __FUNCTION__, static_cast<void *>(section.get()), + section->GetName().AsCString(), load_addr); } - else - { - if (log) - { - log->Printf ("SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 ") error: module has been deleted", - __FUNCTION__, static_cast<void*>(section.get()), - section->GetName().AsCString(), - load_addr); - } - } - return false; + } + return false; } -size_t -SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp) -{ - size_t unload_count = 0; +size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp) { + size_t unload_count = 0; - if (section_sp) - { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE)); + if (section_sp) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER | + LIBLLDB_LOG_VERBOSE)); - if (log) - { - ModuleSP module_sp = section_sp->GetModule(); - std::string module_name("<Unknown>"); - if (module_sp) - { - const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec()); - module_name = module_file_spec.GetPath(); - } - log->Printf ("SectionLoadList::%s (section = %p (%s.%s))", - __FUNCTION__, static_cast<void*>(section_sp.get()), - module_name.c_str(), - section_sp->GetName().AsCString()); - } + if (log) { + ModuleSP module_sp = section_sp->GetModule(); + std::string module_name("<Unknown>"); + if (module_sp) { + const FileSpec &module_file_spec( + section_sp->GetModule()->GetFileSpec()); + module_name = module_file_spec.GetPath(); + } + log->Printf("SectionLoadList::%s (section = %p (%s.%s))", __FUNCTION__, + static_cast<void *>(section_sp.get()), module_name.c_str(), + section_sp->GetName().AsCString()); + } - std::lock_guard<std::recursive_mutex> guard(m_mutex); + std::lock_guard<std::recursive_mutex> guard(m_mutex); - sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get()); - if (sta_pos != m_sect_to_addr.end()) - { - ++unload_count; - addr_t load_addr = sta_pos->second; - m_sect_to_addr.erase (sta_pos); + sect_to_addr_collection::iterator sta_pos = + m_sect_to_addr.find(section_sp.get()); + if (sta_pos != m_sect_to_addr.end()) { + ++unload_count; + addr_t load_addr = sta_pos->second; + m_sect_to_addr.erase(sta_pos); - addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr); - if (ats_pos != m_addr_to_sect.end()) - m_addr_to_sect.erase (ats_pos); - } + addr_to_sect_collection::iterator ats_pos = + m_addr_to_sect.find(load_addr); + if (ats_pos != m_addr_to_sect.end()) + m_addr_to_sect.erase(ats_pos); } - return unload_count; + } + return unload_count; } -bool -SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp, addr_t load_addr) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE)); +bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp, + addr_t load_addr) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER | + LIBLLDB_LOG_VERBOSE)); - if (log) - { - ModuleSP module_sp = section_sp->GetModule(); - std::string module_name("<Unknown>"); - if (module_sp) - { - const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec()); - module_name = module_file_spec.GetPath(); - } - log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ")", - __FUNCTION__, static_cast<void*>(section_sp.get()), - module_name.c_str(), - section_sp->GetName().AsCString(), load_addr); - } - bool erased = false; - std::lock_guard<std::recursive_mutex> guard(m_mutex); - sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get()); - if (sta_pos != m_sect_to_addr.end()) - { - erased = true; - m_sect_to_addr.erase (sta_pos); + if (log) { + ModuleSP module_sp = section_sp->GetModule(); + std::string module_name("<Unknown>"); + if (module_sp) { + const FileSpec &module_file_spec(section_sp->GetModule()->GetFileSpec()); + module_name = module_file_spec.GetPath(); } + log->Printf( + "SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 + ")", + __FUNCTION__, static_cast<void *>(section_sp.get()), + module_name.c_str(), section_sp->GetName().AsCString(), load_addr); + } + bool erased = false; + std::lock_guard<std::recursive_mutex> guard(m_mutex); + sect_to_addr_collection::iterator sta_pos = + m_sect_to_addr.find(section_sp.get()); + if (sta_pos != m_sect_to_addr.end()) { + erased = true; + m_sect_to_addr.erase(sta_pos); + } - addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr); - if (ats_pos != m_addr_to_sect.end()) - { - erased = true; - m_addr_to_sect.erase (ats_pos); - } + addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr); + if (ats_pos != m_addr_to_sect.end()) { + erased = true; + m_addr_to_sect.erase(ats_pos); + } - return erased; + return erased; } - -bool -SectionLoadList::ResolveLoadAddress (addr_t load_addr, Address &so_addr) const -{ - // First find the top level section that this load address exists in - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (!m_addr_to_sect.empty()) - { - addr_to_sect_collection::const_iterator pos = m_addr_to_sect.lower_bound (load_addr); - if (pos != m_addr_to_sect.end()) - { - if (load_addr != pos->first && pos != m_addr_to_sect.begin()) - --pos; - const addr_t pos_load_addr = pos->first; - if (load_addr >= pos_load_addr) - { - addr_t offset = load_addr - pos_load_addr; - if (offset < pos->second->GetByteSize()) - { - // We have found the top level section, now we need to find the - // deepest child section. - return pos->second->ResolveContainedAddress (offset, so_addr); - } - } +bool SectionLoadList::ResolveLoadAddress(addr_t load_addr, + Address &so_addr) const { + // First find the top level section that this load address exists in + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (!m_addr_to_sect.empty()) { + addr_to_sect_collection::const_iterator pos = + m_addr_to_sect.lower_bound(load_addr); + if (pos != m_addr_to_sect.end()) { + if (load_addr != pos->first && pos != m_addr_to_sect.begin()) + --pos; + const addr_t pos_load_addr = pos->first; + if (load_addr >= pos_load_addr) { + addr_t offset = load_addr - pos_load_addr; + if (offset < pos->second->GetByteSize()) { + // We have found the top level section, now we need to find the + // deepest child section. + return pos->second->ResolveContainedAddress(offset, so_addr); } - else - { - // There are no entries that have an address that is >= load_addr, - // so we need to check the last entry on our collection. - addr_to_sect_collection::const_reverse_iterator rpos = m_addr_to_sect.rbegin(); - if (load_addr >= rpos->first) - { - addr_t offset = load_addr - rpos->first; - if (offset < rpos->second->GetByteSize()) - { - // We have found the top level section, now we need to find the - // deepest child section. - return rpos->second->ResolveContainedAddress (offset, so_addr); - } - } + } + } else { + // There are no entries that have an address that is >= load_addr, + // so we need to check the last entry on our collection. + addr_to_sect_collection::const_reverse_iterator rpos = + m_addr_to_sect.rbegin(); + if (load_addr >= rpos->first) { + addr_t offset = load_addr - rpos->first; + if (offset < rpos->second->GetByteSize()) { + // We have found the top level section, now we need to find the + // deepest child section. + return rpos->second->ResolveContainedAddress(offset, so_addr); } + } } - so_addr.Clear(); - return false; + } + so_addr.Clear(); + return false; } -void -SectionLoadList::Dump (Stream &s, Target *target) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - addr_to_sect_collection::const_iterator pos, end; - for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end; ++pos) - { - s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", - pos->first, static_cast<void*>(pos->second.get())); - pos->second->Dump (&s, target, 0); - } +void SectionLoadList::Dump(Stream &s, Target *target) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + addr_to_sect_collection::const_iterator pos, end; + for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end; + ++pos) { + s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first, + static_cast<void *>(pos->second.get())); + pos->second->Dump(&s, target, 0); + } } - - diff --git a/lldb/source/Target/StackFrame.cpp b/lldb/source/Target/StackFrame.cpp index 887207199e2..e491c594a1f 100644 --- a/lldb/source/Target/StackFrame.cpp +++ b/lldb/source/Target/StackFrame.cpp @@ -18,9 +18,9 @@ #include "lldb/Core/Mangled.h" #include "lldb/Core/Module.h" #include "lldb/Core/Value.h" -#include "lldb/Core/ValueObjectVariable.h" #include "lldb/Core/ValueObjectConstResult.h" #include "lldb/Core/ValueObjectMemory.h" +#include "lldb/Core/ValueObjectVariable.h" #include "lldb/Symbol/CompileUnit.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" @@ -40,289 +40,221 @@ using namespace lldb_private; // The first bits in the flags are reserved for the SymbolContext::Scope bits // so we know if we have tried to look up information in our internal symbol // context (m_sc) already. -#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1)) -#define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1) -#define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1) -#define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1) -#define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1) - -StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index, addr_t cfa, - bool cfa_is_valid, addr_t pc, uint32_t stop_id, bool stop_id_is_valid, bool is_history_frame, +#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1)) +#define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1) +#define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1) +#define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1) +#define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1) + +StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, + user_id_t unwind_frame_index, addr_t cfa, + bool cfa_is_valid, addr_t pc, uint32_t stop_id, + bool stop_id_is_valid, bool is_history_frame, const SymbolContext *sc_ptr) - : m_thread_wp(thread_sp), - m_frame_index(frame_idx), - m_concrete_frame_index(unwind_frame_index), - m_reg_context_sp(), - m_id(pc, cfa, nullptr), - m_frame_code_addr(pc), - m_sc(), - m_flags(), - m_frame_base(), - m_frame_base_error(), - m_cfa_is_valid(cfa_is_valid), - m_stop_id(stop_id), - m_stop_id_is_valid(stop_id_is_valid), - m_is_history_frame(is_history_frame), - m_variable_list_sp(), - m_variable_list_value_objects(), - m_disassembly(), - m_mutex() -{ - // If we don't have a CFA value, use the frame index for our StackID so that recursive - // functions properly aren't confused with one another on a history stack. - if (m_is_history_frame && !m_cfa_is_valid) - { - m_id.SetCFA(m_frame_index); - } - - if (sc_ptr != nullptr) - { - m_sc = *sc_ptr; - m_flags.Set(m_sc.GetResolvedMask()); - } + : m_thread_wp(thread_sp), m_frame_index(frame_idx), + m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(), + m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(), + m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid), + m_stop_id(stop_id), m_stop_id_is_valid(stop_id_is_valid), + m_is_history_frame(is_history_frame), m_variable_list_sp(), + m_variable_list_value_objects(), m_disassembly(), m_mutex() { + // If we don't have a CFA value, use the frame index for our StackID so that + // recursive + // functions properly aren't confused with one another on a history stack. + if (m_is_history_frame && !m_cfa_is_valid) { + m_id.SetCFA(m_frame_index); + } + + if (sc_ptr != nullptr) { + m_sc = *sc_ptr; + m_flags.Set(m_sc.GetResolvedMask()); + } } -StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index, - const RegisterContextSP ®_context_sp, addr_t cfa, addr_t pc, const SymbolContext *sc_ptr) - : m_thread_wp(thread_sp), - m_frame_index(frame_idx), +StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, + user_id_t unwind_frame_index, + const RegisterContextSP ®_context_sp, addr_t cfa, + addr_t pc, const SymbolContext *sc_ptr) + : m_thread_wp(thread_sp), m_frame_index(frame_idx), m_concrete_frame_index(unwind_frame_index), - m_reg_context_sp(reg_context_sp), - m_id(pc, cfa, nullptr), - m_frame_code_addr(pc), - m_sc(), - m_flags(), - m_frame_base(), - m_frame_base_error(), - m_cfa_is_valid(true), - m_stop_id(0), - m_stop_id_is_valid(false), - m_is_history_frame(false), - m_variable_list_sp(), - m_variable_list_value_objects(), - m_disassembly(), - m_mutex() -{ - if (sc_ptr != nullptr) - { - m_sc = *sc_ptr; - m_flags.Set(m_sc.GetResolvedMask()); - } - - if (reg_context_sp && !m_sc.target_sp) - { - m_sc.target_sp = reg_context_sp->CalculateTarget(); - if (m_sc.target_sp) - m_flags.Set(eSymbolContextTarget); - } + m_reg_context_sp(reg_context_sp), m_id(pc, cfa, nullptr), + m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(), + m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0), + m_stop_id_is_valid(false), m_is_history_frame(false), + m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(), + m_mutex() { + if (sc_ptr != nullptr) { + m_sc = *sc_ptr; + m_flags.Set(m_sc.GetResolvedMask()); + } + + if (reg_context_sp && !m_sc.target_sp) { + m_sc.target_sp = reg_context_sp->CalculateTarget(); + if (m_sc.target_sp) + m_flags.Set(eSymbolContextTarget); + } } -StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index, - const RegisterContextSP ®_context_sp, addr_t cfa, const Address &pc_addr, - const SymbolContext *sc_ptr) - : m_thread_wp(thread_sp), - m_frame_index(frame_idx), +StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, + user_id_t unwind_frame_index, + const RegisterContextSP ®_context_sp, addr_t cfa, + const Address &pc_addr, const SymbolContext *sc_ptr) + : m_thread_wp(thread_sp), m_frame_index(frame_idx), m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(reg_context_sp), - m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa, nullptr), - m_frame_code_addr(pc_addr), - m_sc(), - m_flags(), - m_frame_base(), - m_frame_base_error(), - m_cfa_is_valid(true), - m_stop_id(0), - m_stop_id_is_valid(false), - m_is_history_frame(false), - m_variable_list_sp(), - m_variable_list_value_objects(), - m_disassembly(), - m_mutex() -{ - if (sc_ptr != nullptr) - { - m_sc = *sc_ptr; - m_flags.Set(m_sc.GetResolvedMask()); - } - - if (!m_sc.target_sp && reg_context_sp) - { - m_sc.target_sp = reg_context_sp->CalculateTarget(); - if (m_sc.target_sp) - m_flags.Set(eSymbolContextTarget); - } - - ModuleSP pc_module_sp(pc_addr.GetModule()); - if (!m_sc.module_sp || m_sc.module_sp != pc_module_sp) - { - if (pc_module_sp) - { - m_sc.module_sp = pc_module_sp; - m_flags.Set(eSymbolContextModule); - } - else - { - m_sc.module_sp.reset(); - } + m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa, + nullptr), + m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(), + m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0), + m_stop_id_is_valid(false), m_is_history_frame(false), + m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(), + m_mutex() { + if (sc_ptr != nullptr) { + m_sc = *sc_ptr; + m_flags.Set(m_sc.GetResolvedMask()); + } + + if (!m_sc.target_sp && reg_context_sp) { + m_sc.target_sp = reg_context_sp->CalculateTarget(); + if (m_sc.target_sp) + m_flags.Set(eSymbolContextTarget); + } + + ModuleSP pc_module_sp(pc_addr.GetModule()); + if (!m_sc.module_sp || m_sc.module_sp != pc_module_sp) { + if (pc_module_sp) { + m_sc.module_sp = pc_module_sp; + m_flags.Set(eSymbolContextModule); + } else { + m_sc.module_sp.reset(); } + } } StackFrame::~StackFrame() = default; -StackID& -StackFrame::GetStackID() -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - // Make sure we have resolved the StackID object's symbol context scope if - // we already haven't looked it up. - - if (m_flags.IsClear (RESOLVED_FRAME_ID_SYMBOL_SCOPE)) - { - if (m_id.GetSymbolContextScope ()) - { - // We already have a symbol context scope, we just don't have our - // flag bit set. - m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE); - } - else - { - // Calculate the frame block and use this for the stack ID symbol - // context scope if we have one. - SymbolContextScope *scope = GetFrameBlock (); - if (scope == nullptr) - { - // We don't have a block, so use the symbol - if (m_flags.IsClear (eSymbolContextSymbol)) - GetSymbolContext (eSymbolContextSymbol); - - // It is ok if m_sc.symbol is nullptr here - scope = m_sc.symbol; - } - // Set the symbol context scope (the accessor will set the - // RESOLVED_FRAME_ID_SYMBOL_SCOPE bit in m_flags). - SetSymbolContextScope (scope); - } +StackID &StackFrame::GetStackID() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + // Make sure we have resolved the StackID object's symbol context scope if + // we already haven't looked it up. + + if (m_flags.IsClear(RESOLVED_FRAME_ID_SYMBOL_SCOPE)) { + if (m_id.GetSymbolContextScope()) { + // We already have a symbol context scope, we just don't have our + // flag bit set. + m_flags.Set(RESOLVED_FRAME_ID_SYMBOL_SCOPE); + } else { + // Calculate the frame block and use this for the stack ID symbol + // context scope if we have one. + SymbolContextScope *scope = GetFrameBlock(); + if (scope == nullptr) { + // We don't have a block, so use the symbol + if (m_flags.IsClear(eSymbolContextSymbol)) + GetSymbolContext(eSymbolContextSymbol); + + // It is ok if m_sc.symbol is nullptr here + scope = m_sc.symbol; + } + // Set the symbol context scope (the accessor will set the + // RESOLVED_FRAME_ID_SYMBOL_SCOPE bit in m_flags). + SetSymbolContextScope(scope); } - return m_id; + } + return m_id; } -uint32_t -StackFrame::GetFrameIndex () const -{ - ThreadSP thread_sp = GetThread(); - if (thread_sp) - return thread_sp->GetStackFrameList()->GetVisibleStackFrameIndex(m_frame_index); - else - return m_frame_index; +uint32_t StackFrame::GetFrameIndex() const { + ThreadSP thread_sp = GetThread(); + if (thread_sp) + return thread_sp->GetStackFrameList()->GetVisibleStackFrameIndex( + m_frame_index); + else + return m_frame_index; } -void -StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE); - m_id.SetSymbolContextScope (symbol_scope); +void StackFrame::SetSymbolContextScope(SymbolContextScope *symbol_scope) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_flags.Set(RESOLVED_FRAME_ID_SYMBOL_SCOPE); + m_id.SetSymbolContextScope(symbol_scope); } -const Address& -StackFrame::GetFrameCodeAddress() -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset()) - { - m_flags.Set (RESOLVED_FRAME_CODE_ADDR); - - // Resolve the PC into a temporary address because if ResolveLoadAddress - // fails to resolve the address, it will clear the address object... - ThreadSP thread_sp (GetThread()); - if (thread_sp) - { - TargetSP target_sp (thread_sp->CalculateTarget()); - if (target_sp) - { - if (m_frame_code_addr.SetOpcodeLoadAddress (m_frame_code_addr.GetOffset(), target_sp.get(), eAddressClassCode)) - { - ModuleSP module_sp (m_frame_code_addr.GetModule()); - if (module_sp) - { - m_sc.module_sp = module_sp; - m_flags.Set(eSymbolContextModule); - } - } - } +const Address &StackFrame::GetFrameCodeAddress() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && + !m_frame_code_addr.IsSectionOffset()) { + m_flags.Set(RESOLVED_FRAME_CODE_ADDR); + + // Resolve the PC into a temporary address because if ResolveLoadAddress + // fails to resolve the address, it will clear the address object... + ThreadSP thread_sp(GetThread()); + if (thread_sp) { + TargetSP target_sp(thread_sp->CalculateTarget()); + if (target_sp) { + if (m_frame_code_addr.SetOpcodeLoadAddress( + m_frame_code_addr.GetOffset(), target_sp.get(), + eAddressClassCode)) { + ModuleSP module_sp(m_frame_code_addr.GetModule()); + if (module_sp) { + m_sc.module_sp = module_sp; + m_flags.Set(eSymbolContextModule); + } } + } } - return m_frame_code_addr; + } + return m_frame_code_addr; } -bool -StackFrame::ChangePC (addr_t pc) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - // We can't change the pc value of a history stack frame - it is immutable. - if (m_is_history_frame) - return false; - m_frame_code_addr.SetRawAddress(pc); - m_sc.Clear(false); - m_flags.Reset(0); - ThreadSP thread_sp (GetThread()); - if (thread_sp) - thread_sp->ClearStackFrames (); - return true; +bool StackFrame::ChangePC(addr_t pc) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + // We can't change the pc value of a history stack frame - it is immutable. + if (m_is_history_frame) + return false; + m_frame_code_addr.SetRawAddress(pc); + m_sc.Clear(false); + m_flags.Reset(0); + ThreadSP thread_sp(GetThread()); + if (thread_sp) + thread_sp->ClearStackFrames(); + return true; } -const char * -StackFrame::Disassemble () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_disassembly.GetSize() == 0) - { - ExecutionContext exe_ctx (shared_from_this()); - Target *target = exe_ctx.GetTargetPtr(); - if (target) - { - const char *plugin_name = nullptr; - const char *flavor = nullptr; - Disassembler::Disassemble (target->GetDebugger(), - target->GetArchitecture(), - plugin_name, - flavor, - exe_ctx, - 0, - 0, - 0, - m_disassembly); - } - if (m_disassembly.GetSize() == 0) - return nullptr; +const char *StackFrame::Disassemble() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_disassembly.GetSize() == 0) { + ExecutionContext exe_ctx(shared_from_this()); + Target *target = exe_ctx.GetTargetPtr(); + if (target) { + const char *plugin_name = nullptr; + const char *flavor = nullptr; + Disassembler::Disassemble(target->GetDebugger(), + target->GetArchitecture(), plugin_name, flavor, + exe_ctx, 0, 0, 0, m_disassembly); } - return m_disassembly.GetData(); + if (m_disassembly.GetSize() == 0) + return nullptr; + } + return m_disassembly.GetData(); } -Block * -StackFrame::GetFrameBlock () -{ - if (m_sc.block == nullptr && m_flags.IsClear(eSymbolContextBlock)) - GetSymbolContext (eSymbolContextBlock); - - if (m_sc.block) - { - Block *inline_block = m_sc.block->GetContainingInlinedBlock(); - if (inline_block) - { - // Use the block with the inlined function info - // as the frame block we want this frame to have only the variables - // for the inlined function and its non-inlined block child blocks. - return inline_block; - } - else - { - // This block is not contained within any inlined function blocks - // with so we want to use the top most function block. - return &m_sc.function->GetBlock (false); - } - } - return nullptr; +Block *StackFrame::GetFrameBlock() { + if (m_sc.block == nullptr && m_flags.IsClear(eSymbolContextBlock)) + GetSymbolContext(eSymbolContextBlock); + + if (m_sc.block) { + Block *inline_block = m_sc.block->GetContainingInlinedBlock(); + if (inline_block) { + // Use the block with the inlined function info + // as the frame block we want this frame to have only the variables + // for the inlined function and its non-inlined block child blocks. + return inline_block; + } else { + // This block is not contained within any inlined function blocks + // with so we want to use the top most function block. + return &m_sc.function->GetBlock(false); + } + } + return nullptr; } //---------------------------------------------------------------------- @@ -331,1840 +263,1658 @@ StackFrame::GetFrameBlock () // StackFrame object, everyone will have as much information as // possible and no one will ever have to look things up manually. //---------------------------------------------------------------------- -const SymbolContext& -StackFrame::GetSymbolContext (uint32_t resolve_scope) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - // Copy our internal symbol context into "sc". - if ((m_flags.Get() & resolve_scope) != resolve_scope) - { - uint32_t resolved = 0; - - // If the target was requested add that: - if (!m_sc.target_sp) - { - m_sc.target_sp = CalculateTarget(); - if (m_sc.target_sp) - resolved |= eSymbolContextTarget; - } - - // Resolve our PC to section offset if we haven't already done so - // and if we don't have a module. The resolved address section will - // contain the module to which it belongs - if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR)) - GetFrameCodeAddress(); - - // If this is not frame zero, then we need to subtract 1 from the PC - // value when doing address lookups since the PC will be on the - // instruction following the function call instruction... - - Address lookup_addr(GetFrameCodeAddress()); - if (m_frame_index > 0 && lookup_addr.IsValid()) - { - addr_t offset = lookup_addr.GetOffset(); - if (offset > 0) - { - lookup_addr.SetOffset(offset - 1); +const SymbolContext &StackFrame::GetSymbolContext(uint32_t resolve_scope) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + // Copy our internal symbol context into "sc". + if ((m_flags.Get() & resolve_scope) != resolve_scope) { + uint32_t resolved = 0; + + // If the target was requested add that: + if (!m_sc.target_sp) { + m_sc.target_sp = CalculateTarget(); + if (m_sc.target_sp) + resolved |= eSymbolContextTarget; + } - } - else - { - // lookup_addr is the start of a section. We need - // do the math on the actual load address and re-compute - // the section. We're working with a 'noreturn' function - // at the end of a section. - ThreadSP thread_sp (GetThread()); - if (thread_sp) - { - TargetSP target_sp (thread_sp->CalculateTarget()); - if (target_sp) - { - addr_t addr_minus_one = lookup_addr.GetLoadAddress(target_sp.get()) - 1; - lookup_addr.SetLoadAddress (addr_minus_one, target_sp.get()); - } - else - { - lookup_addr.SetOffset(offset - 1); - } - } - } + // Resolve our PC to section offset if we haven't already done so + // and if we don't have a module. The resolved address section will + // contain the module to which it belongs + if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR)) + GetFrameCodeAddress(); + + // If this is not frame zero, then we need to subtract 1 from the PC + // value when doing address lookups since the PC will be on the + // instruction following the function call instruction... + + Address lookup_addr(GetFrameCodeAddress()); + if (m_frame_index > 0 && lookup_addr.IsValid()) { + addr_t offset = lookup_addr.GetOffset(); + if (offset > 0) { + lookup_addr.SetOffset(offset - 1); + + } else { + // lookup_addr is the start of a section. We need + // do the math on the actual load address and re-compute + // the section. We're working with a 'noreturn' function + // at the end of a section. + ThreadSP thread_sp(GetThread()); + if (thread_sp) { + TargetSP target_sp(thread_sp->CalculateTarget()); + if (target_sp) { + addr_t addr_minus_one = + lookup_addr.GetLoadAddress(target_sp.get()) - 1; + lookup_addr.SetLoadAddress(addr_minus_one, target_sp.get()); + } else { + lookup_addr.SetOffset(offset - 1); + } } + } + } - if (m_sc.module_sp) - { - // We have something in our stack frame symbol context, lets check - // if we haven't already tried to lookup one of those things. If we - // haven't then we will do the query. - - uint32_t actual_resolve_scope = 0; - - if (resolve_scope & eSymbolContextCompUnit) - { - if (m_flags.IsClear (eSymbolContextCompUnit)) - { - if (m_sc.comp_unit) - resolved |= eSymbolContextCompUnit; - else - actual_resolve_scope |= eSymbolContextCompUnit; - } - } - - if (resolve_scope & eSymbolContextFunction) - { - if (m_flags.IsClear (eSymbolContextFunction)) - { - if (m_sc.function) - resolved |= eSymbolContextFunction; - else - actual_resolve_scope |= eSymbolContextFunction; - } - } - - if (resolve_scope & eSymbolContextBlock) - { - if (m_flags.IsClear (eSymbolContextBlock)) - { - if (m_sc.block) - resolved |= eSymbolContextBlock; - else - actual_resolve_scope |= eSymbolContextBlock; - } - } + if (m_sc.module_sp) { + // We have something in our stack frame symbol context, lets check + // if we haven't already tried to lookup one of those things. If we + // haven't then we will do the query. - if (resolve_scope & eSymbolContextSymbol) - { - if (m_flags.IsClear (eSymbolContextSymbol)) - { - if (m_sc.symbol) - resolved |= eSymbolContextSymbol; - else - actual_resolve_scope |= eSymbolContextSymbol; - } - } + uint32_t actual_resolve_scope = 0; - if (resolve_scope & eSymbolContextLineEntry) - { - if (m_flags.IsClear (eSymbolContextLineEntry)) - { - if (m_sc.line_entry.IsValid()) - resolved |= eSymbolContextLineEntry; - else - actual_resolve_scope |= eSymbolContextLineEntry; - } - } - - if (actual_resolve_scope) - { - // We might be resolving less information than what is already - // in our current symbol context so resolve into a temporary - // symbol context "sc" so we don't clear out data we have - // already found in "m_sc" - SymbolContext sc; - // Set flags that indicate what we have tried to resolve - resolved |= m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, actual_resolve_scope, sc); - // Only replace what we didn't already have as we may have - // information for an inlined function scope that won't match - // what a standard lookup by address would match - if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == nullptr) - m_sc.comp_unit = sc.comp_unit; - if ((resolved & eSymbolContextFunction) && m_sc.function == nullptr) - m_sc.function = sc.function; - if ((resolved & eSymbolContextBlock) && m_sc.block == nullptr) - m_sc.block = sc.block; - if ((resolved & eSymbolContextSymbol) && m_sc.symbol == nullptr) - m_sc.symbol = sc.symbol; - if ((resolved & eSymbolContextLineEntry) && !m_sc.line_entry.IsValid()) - { - m_sc.line_entry = sc.line_entry; - m_sc.line_entry.ApplyFileMappings(m_sc.target_sp); - } - } + if (resolve_scope & eSymbolContextCompUnit) { + if (m_flags.IsClear(eSymbolContextCompUnit)) { + if (m_sc.comp_unit) + resolved |= eSymbolContextCompUnit; + else + actual_resolve_scope |= eSymbolContextCompUnit; } - else - { - // If we don't have a module, then we can't have the compile unit, - // function, block, line entry or symbol, so we can safely call - // ResolveSymbolContextForAddress with our symbol context member m_sc. - if (m_sc.target_sp) - { - resolved |= m_sc.target_sp->GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc); - } + } + + if (resolve_scope & eSymbolContextFunction) { + if (m_flags.IsClear(eSymbolContextFunction)) { + if (m_sc.function) + resolved |= eSymbolContextFunction; + else + actual_resolve_scope |= eSymbolContextFunction; } - - // Update our internal flags so we remember what we have tried to locate so - // we don't have to keep trying when more calls to this function are made. - // We might have dug up more information that was requested (for example - // if we were asked to only get the block, we will have gotten the - // compile unit, and function) so set any additional bits that we resolved - m_flags.Set (resolve_scope | resolved); + } + + if (resolve_scope & eSymbolContextBlock) { + if (m_flags.IsClear(eSymbolContextBlock)) { + if (m_sc.block) + resolved |= eSymbolContextBlock; + else + actual_resolve_scope |= eSymbolContextBlock; + } + } + + if (resolve_scope & eSymbolContextSymbol) { + if (m_flags.IsClear(eSymbolContextSymbol)) { + if (m_sc.symbol) + resolved |= eSymbolContextSymbol; + else + actual_resolve_scope |= eSymbolContextSymbol; + } + } + + if (resolve_scope & eSymbolContextLineEntry) { + if (m_flags.IsClear(eSymbolContextLineEntry)) { + if (m_sc.line_entry.IsValid()) + resolved |= eSymbolContextLineEntry; + else + actual_resolve_scope |= eSymbolContextLineEntry; + } + } + + if (actual_resolve_scope) { + // We might be resolving less information than what is already + // in our current symbol context so resolve into a temporary + // symbol context "sc" so we don't clear out data we have + // already found in "m_sc" + SymbolContext sc; + // Set flags that indicate what we have tried to resolve + resolved |= m_sc.module_sp->ResolveSymbolContextForAddress( + lookup_addr, actual_resolve_scope, sc); + // Only replace what we didn't already have as we may have + // information for an inlined function scope that won't match + // what a standard lookup by address would match + if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == nullptr) + m_sc.comp_unit = sc.comp_unit; + if ((resolved & eSymbolContextFunction) && m_sc.function == nullptr) + m_sc.function = sc.function; + if ((resolved & eSymbolContextBlock) && m_sc.block == nullptr) + m_sc.block = sc.block; + if ((resolved & eSymbolContextSymbol) && m_sc.symbol == nullptr) + m_sc.symbol = sc.symbol; + if ((resolved & eSymbolContextLineEntry) && + !m_sc.line_entry.IsValid()) { + m_sc.line_entry = sc.line_entry; + m_sc.line_entry.ApplyFileMappings(m_sc.target_sp); + } + } + } else { + // If we don't have a module, then we can't have the compile unit, + // function, block, line entry or symbol, so we can safely call + // ResolveSymbolContextForAddress with our symbol context member m_sc. + if (m_sc.target_sp) { + resolved |= m_sc.target_sp->GetImages().ResolveSymbolContextForAddress( + lookup_addr, resolve_scope, m_sc); + } } - // Return the symbol context with everything that was possible to resolve - // resolved. - return m_sc; + // Update our internal flags so we remember what we have tried to locate so + // we don't have to keep trying when more calls to this function are made. + // We might have dug up more information that was requested (for example + // if we were asked to only get the block, we will have gotten the + // compile unit, and function) so set any additional bits that we resolved + m_flags.Set(resolve_scope | resolved); + } + + // Return the symbol context with everything that was possible to resolve + // resolved. + return m_sc; } -VariableList * -StackFrame::GetVariableList (bool get_file_globals) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_flags.IsClear(RESOLVED_VARIABLES)) - { - m_flags.Set(RESOLVED_VARIABLES); - - Block *frame_block = GetFrameBlock(); - - if (frame_block) - { - const bool get_child_variables = true; - const bool can_create = true; - const bool stop_if_child_block_is_inlined_function = true; - m_variable_list_sp.reset(new VariableList()); - frame_block->AppendBlockVariables(can_create, - get_child_variables, - stop_if_child_block_is_inlined_function, - [this](Variable* v) { return true; }, - m_variable_list_sp.get()); - } +VariableList *StackFrame::GetVariableList(bool get_file_globals) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_flags.IsClear(RESOLVED_VARIABLES)) { + m_flags.Set(RESOLVED_VARIABLES); + + Block *frame_block = GetFrameBlock(); + + if (frame_block) { + const bool get_child_variables = true; + const bool can_create = true; + const bool stop_if_child_block_is_inlined_function = true; + m_variable_list_sp.reset(new VariableList()); + frame_block->AppendBlockVariables(can_create, get_child_variables, + stop_if_child_block_is_inlined_function, + [this](Variable *v) { return true; }, + m_variable_list_sp.get()); } - - if (m_flags.IsClear(RESOLVED_GLOBAL_VARIABLES) && - get_file_globals) - { - m_flags.Set(RESOLVED_GLOBAL_VARIABLES); - - if (m_flags.IsClear (eSymbolContextCompUnit)) - GetSymbolContext (eSymbolContextCompUnit); - - if (m_sc.comp_unit) - { - VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true)); - if (m_variable_list_sp) - m_variable_list_sp->AddVariables (global_variable_list_sp.get()); - else - m_variable_list_sp = global_variable_list_sp; - } + } + + if (m_flags.IsClear(RESOLVED_GLOBAL_VARIABLES) && get_file_globals) { + m_flags.Set(RESOLVED_GLOBAL_VARIABLES); + + if (m_flags.IsClear(eSymbolContextCompUnit)) + GetSymbolContext(eSymbolContextCompUnit); + + if (m_sc.comp_unit) { + VariableListSP global_variable_list_sp( + m_sc.comp_unit->GetVariableList(true)); + if (m_variable_list_sp) + m_variable_list_sp->AddVariables(global_variable_list_sp.get()); + else + m_variable_list_sp = global_variable_list_sp; } - - return m_variable_list_sp.get(); + } + + return m_variable_list_sp.get(); } VariableListSP -StackFrame::GetInScopeVariableList (bool get_file_globals, bool must_have_valid_location) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - // We can't fetch variable information for a history stack frame. - if (m_is_history_frame) - return VariableListSP(); - - VariableListSP var_list_sp(new VariableList); - GetSymbolContext (eSymbolContextCompUnit | eSymbolContextBlock); - - if (m_sc.block) - { - const bool can_create = true; - const bool get_parent_variables = true; - const bool stop_if_block_is_inlined_function = true; - m_sc.block->AppendVariables (can_create, - get_parent_variables, - stop_if_block_is_inlined_function, - [this, must_have_valid_location](Variable* v) - { - return v->IsInScope(this) && (!must_have_valid_location || v->LocationIsValidForFrame(this)); - }, - var_list_sp.get()); - } - - if (m_sc.comp_unit && get_file_globals) - { - VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true)); - if (global_variable_list_sp) - var_list_sp->AddVariables (global_variable_list_sp.get()); - } - - return var_list_sp; +StackFrame::GetInScopeVariableList(bool get_file_globals, + bool must_have_valid_location) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + // We can't fetch variable information for a history stack frame. + if (m_is_history_frame) + return VariableListSP(); + + VariableListSP var_list_sp(new VariableList); + GetSymbolContext(eSymbolContextCompUnit | eSymbolContextBlock); + + if (m_sc.block) { + const bool can_create = true; + const bool get_parent_variables = true; + const bool stop_if_block_is_inlined_function = true; + m_sc.block->AppendVariables( + can_create, get_parent_variables, stop_if_block_is_inlined_function, + [this, must_have_valid_location](Variable *v) { + return v->IsInScope(this) && (!must_have_valid_location || + v->LocationIsValidForFrame(this)); + }, + var_list_sp.get()); + } + + if (m_sc.comp_unit && get_file_globals) { + VariableListSP global_variable_list_sp( + m_sc.comp_unit->GetVariableList(true)); + if (global_variable_list_sp) + var_list_sp->AddVariables(global_variable_list_sp.get()); + } + + return var_list_sp; } -ValueObjectSP -StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr, - DynamicValueType use_dynamic, - uint32_t options, - VariableSP &var_sp, - Error &error) -{ - // We can't fetch variable information for a history stack frame. - if (m_is_history_frame) - return ValueObjectSP(); +ValueObjectSP StackFrame::GetValueForVariableExpressionPath( + const char *var_expr_cstr, DynamicValueType use_dynamic, uint32_t options, + VariableSP &var_sp, Error &error) { + // We can't fetch variable information for a history stack frame. + if (m_is_history_frame) + return ValueObjectSP(); - if (var_expr_cstr && var_expr_cstr[0]) - { - const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0; - const bool no_fragile_ivar = (options & eExpressionPathOptionsNoFragileObjcIvar) != 0; - const bool no_synth_child = (options & eExpressionPathOptionsNoSyntheticChildren) != 0; - //const bool no_synth_array = (options & eExpressionPathOptionsNoSyntheticArrayRange) != 0; - error.Clear(); - bool deref = false; - bool address_of = false; - ValueObjectSP valobj_sp; - const bool get_file_globals = true; - // When looking up a variable for an expression, we need only consider the - // variables that are in scope. - VariableListSP var_list_sp (GetInScopeVariableList (get_file_globals)); - VariableList *variable_list = var_list_sp.get(); - - if (variable_list) - { - // If first character is a '*', then show pointer contents - const char *var_expr = var_expr_cstr; - if (var_expr[0] == '*') - { - deref = true; - var_expr++; // Skip the '*' + if (var_expr_cstr && var_expr_cstr[0]) { + const bool check_ptr_vs_member = + (options & eExpressionPathOptionCheckPtrVsMember) != 0; + const bool no_fragile_ivar = + (options & eExpressionPathOptionsNoFragileObjcIvar) != 0; + const bool no_synth_child = + (options & eExpressionPathOptionsNoSyntheticChildren) != 0; + // const bool no_synth_array = (options & + // eExpressionPathOptionsNoSyntheticArrayRange) != 0; + error.Clear(); + bool deref = false; + bool address_of = false; + ValueObjectSP valobj_sp; + const bool get_file_globals = true; + // When looking up a variable for an expression, we need only consider the + // variables that are in scope. + VariableListSP var_list_sp(GetInScopeVariableList(get_file_globals)); + VariableList *variable_list = var_list_sp.get(); + + if (variable_list) { + // If first character is a '*', then show pointer contents + const char *var_expr = var_expr_cstr; + if (var_expr[0] == '*') { + deref = true; + var_expr++; // Skip the '*' + } else if (var_expr[0] == '&') { + address_of = true; + var_expr++; // Skip the '&' + } + + std::string var_path(var_expr); + size_t separator_idx = var_path.find_first_of(".-[=+~|&^%#@!/?,<>{}"); + StreamString var_expr_path_strm; + + ConstString name_const_string; + if (separator_idx == std::string::npos) + name_const_string.SetCString(var_path.c_str()); + else + name_const_string.SetCStringWithLength(var_path.c_str(), separator_idx); + + var_sp = variable_list->FindVariable(name_const_string, false); + + bool synthetically_added_instance_object = false; + + if (var_sp) { + var_path.erase(0, name_const_string.GetLength()); + } + + if (!var_sp && (options & eExpressionPathOptionsAllowDirectIVarAccess)) { + // Check for direct ivars access which helps us with implicit + // access to ivars with the "this->" or "self->" + GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock); + lldb::LanguageType method_language = eLanguageTypeUnknown; + bool is_instance_method = false; + ConstString method_object_name; + if (m_sc.GetFunctionMethodInfo(method_language, is_instance_method, + method_object_name)) { + if (is_instance_method && method_object_name) { + var_sp = variable_list->FindVariable(method_object_name); + if (var_sp) { + separator_idx = 0; + var_path.insert(0, "->"); + synthetically_added_instance_object = true; } - else if (var_expr[0] == '&') - { - address_of = true; - var_expr++; // Skip the '&' + } + } + } + + if (!var_sp && (options & eExpressionPathOptionsInspectAnonymousUnions)) { + // Check if any anonymous unions are there which contain a variable with + // the name we need + for (size_t i = 0; i < variable_list->GetSize(); i++) { + if (VariableSP variable_sp = variable_list->GetVariableAtIndex(i)) { + if (variable_sp->GetName().IsEmpty()) { + if (Type *var_type = variable_sp->GetType()) { + if (var_type->GetForwardCompilerType().IsAnonymousType()) { + valobj_sp = + GetValueObjectForFrameVariable(variable_sp, use_dynamic); + if (!valobj_sp) + return valobj_sp; + valobj_sp = valobj_sp->GetChildMemberWithName( + name_const_string, true); + if (valobj_sp) + break; + } + } } - - std::string var_path (var_expr); - size_t separator_idx = var_path.find_first_of(".-[=+~|&^%#@!/?,<>{}"); - StreamString var_expr_path_strm; - - ConstString name_const_string; + } + } + } + + if (var_sp && !valobj_sp) { + valobj_sp = GetValueObjectForFrameVariable(var_sp, use_dynamic); + if (!valobj_sp) + return valobj_sp; + } + if (valobj_sp) { + // We are dumping at least one child + while (separator_idx != std::string::npos) { + // Calculate the next separator index ahead of time + ValueObjectSP child_valobj_sp; + const char separator_type = var_path[0]; + switch (separator_type) { + case '-': + if (var_path.size() >= 2 && var_path[1] != '>') + return ValueObjectSP(); + + if (no_fragile_ivar) { + // Make sure we aren't trying to deref an objective + // C ivar if this is not allowed + const uint32_t pointer_type_flags = + valobj_sp->GetCompilerType().GetTypeInfo(nullptr); + if ((pointer_type_flags & eTypeIsObjC) && + (pointer_type_flags & eTypeIsPointer)) { + // This was an objective C object pointer and + // it was requested we skip any fragile ivars + // so return nothing here + return ValueObjectSP(); + } + } + var_path.erase(0, 1); // Remove the '-' + LLVM_FALLTHROUGH; + case '.': { + const bool expr_is_ptr = var_path[0] == '>'; + + var_path.erase(0, 1); // Remove the '.' or '>' + separator_idx = var_path.find_first_of(".-["); + ConstString child_name; if (separator_idx == std::string::npos) - name_const_string.SetCString (var_path.c_str()); + child_name.SetCString(var_path.c_str()); else - name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx); - - var_sp = variable_list->FindVariable(name_const_string, false); - - bool synthetically_added_instance_object = false; - - if (var_sp) - { - var_path.erase (0, name_const_string.GetLength ()); + child_name.SetCStringWithLength(var_path.c_str(), separator_idx); + + if (check_ptr_vs_member) { + // We either have a pointer type and need to verify + // valobj_sp is a pointer, or we have a member of a + // class/union/struct being accessed with the . syntax + // and need to verify we don't have a pointer. + const bool actual_is_ptr = valobj_sp->IsPointerType(); + + if (actual_is_ptr != expr_is_ptr) { + // Incorrect use of "." with a pointer, or "->" with + // a class/union/struct instance or reference. + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + if (actual_is_ptr) + error.SetErrorStringWithFormat( + "\"%s\" is a pointer and . was used to attempt to access " + "\"%s\". Did you mean \"%s->%s\"?", + var_expr_path_strm.GetString().c_str(), + child_name.GetCString(), + var_expr_path_strm.GetString().c_str(), var_path.c_str()); + else + error.SetErrorStringWithFormat( + "\"%s\" is not a pointer and -> was used to attempt to " + "access \"%s\". Did you mean \"%s.%s\"?", + var_expr_path_strm.GetString().c_str(), + child_name.GetCString(), + var_expr_path_strm.GetString().c_str(), var_path.c_str()); + return ValueObjectSP(); + } } - - if (!var_sp && (options & eExpressionPathOptionsAllowDirectIVarAccess)) - { - // Check for direct ivars access which helps us with implicit - // access to ivars with the "this->" or "self->" - GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock); - lldb::LanguageType method_language = eLanguageTypeUnknown; - bool is_instance_method = false; - ConstString method_object_name; - if (m_sc.GetFunctionMethodInfo (method_language, is_instance_method, method_object_name)) - { - if (is_instance_method && method_object_name) - { - var_sp = variable_list->FindVariable(method_object_name); - if (var_sp) - { - separator_idx = 0; - var_path.insert(0, "->"); - synthetically_added_instance_object = true; - } - } + child_valobj_sp = + valobj_sp->GetChildMemberWithName(child_name, true); + if (!child_valobj_sp) { + if (!no_synth_child) { + child_valobj_sp = valobj_sp->GetSyntheticValue(); + if (child_valobj_sp) + child_valobj_sp = + child_valobj_sp->GetChildMemberWithName(child_name, true); + } + + if (no_synth_child || !child_valobj_sp) { + // No child member with name "child_name" + if (synthetically_added_instance_object) { + // We added a "this->" or "self->" to the beginning of the + // expression + // and this is the first pointer ivar access, so just return + // the normal + // error + error.SetErrorStringWithFormat( + "no variable or instance variable named '%s' found in " + "this frame", + name_const_string.GetCString()); + } else { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + if (child_name) { + error.SetErrorStringWithFormat( + "\"%s\" is not a member of \"(%s) %s\"", + child_name.GetCString(), + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } else { + error.SetErrorStringWithFormat( + "incomplete expression path after \"%s\" in \"%s\"", + var_expr_path_strm.GetString().c_str(), var_expr_cstr); + } } + return ValueObjectSP(); + } } - - if (!var_sp && (options & eExpressionPathOptionsInspectAnonymousUnions)) - { - // Check if any anonymous unions are there which contain a variable with the name we need - for (size_t i = 0; - i < variable_list->GetSize(); - i++) - { - if (VariableSP variable_sp = variable_list->GetVariableAtIndex(i)) - { - if (variable_sp->GetName().IsEmpty()) - { - if (Type *var_type = variable_sp->GetType()) - { - if (var_type->GetForwardCompilerType().IsAnonymousType()) - { - valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic); - if (!valobj_sp) - return valobj_sp; - valobj_sp = valobj_sp->GetChildMemberWithName(name_const_string, true); - if (valobj_sp) - break; - } - } - } - } - } + synthetically_added_instance_object = false; + // Remove the child name from the path + var_path.erase(0, child_name.GetLength()); + if (use_dynamic != eNoDynamicValues) { + ValueObjectSP dynamic_value_sp( + child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; } + } break; - if (var_sp && !valobj_sp) + case '[': + // Array member access, or treating pointer as an array + if (var_path.size() > 2) // Need at least two brackets and a number { - valobj_sp = GetValueObjectForFrameVariable (var_sp, use_dynamic); - if (!valobj_sp) - return valobj_sp; - } - if (valobj_sp) - { - // We are dumping at least one child - while (separator_idx != std::string::npos) - { - // Calculate the next separator index ahead of time - ValueObjectSP child_valobj_sp; - const char separator_type = var_path[0]; - switch (separator_type) + char *end = nullptr; + long child_index = ::strtol(&var_path[1], &end, 0); + if (end && *end == ']' && + *(end - 1) != '[') // this code forces an error in the case of + // arr[]. as bitfield[] is not a good + // syntax we're good to go + { + if (valobj_sp->GetCompilerType().IsPointerToScalarType() && + deref) { + // what we have is *ptr[low]. the most similar C++ syntax is + // to deref ptr + // and extract bit low out of it. reading array item low + // would be done by saying ptr[low], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->Dereference(error)); + if (error.Fail()) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "could not dereference \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } else if (valobj_sp->GetCompilerType().IsArrayOfScalarType() && + deref) { + // what we have is *arr[low]. the most similar C++ syntax is + // to get arr[0] + // (an operation that is equivalent to deref-ing arr) + // and extract bit low out of it. reading array item low + // would be done by saying arr[low], without a deref * sign + Error error; + ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true)); + if (error.Fail()) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "could not get item 0 for \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); + } + valobj_sp = temp; + deref = false; + } + + bool is_incomplete_array = false; + if (valobj_sp->IsPointerType()) { + bool is_objc_pointer = true; + + if (valobj_sp->GetCompilerType().GetMinimumLanguage() != + eLanguageTypeObjC) + is_objc_pointer = false; + else if (!valobj_sp->GetCompilerType().IsPointerType()) + is_objc_pointer = false; + + if (no_synth_child && is_objc_pointer) { + error.SetErrorStringWithFormat( + "\"(%s) %s\" is an Objective-C pointer, and cannot be " + "subscripted", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + + return ValueObjectSP(); + } else if (is_objc_pointer) { + // dereferencing ObjC variables is not valid.. so let's try + // and recur to synthetic children + ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); + if (!synthetic /* no synthetic */ + || synthetic == valobj_sp) /* synthetic is the same as + the original object */ { - case '-': - if (var_path.size() >= 2 && var_path[1] != '>') - return ValueObjectSP(); - - if (no_fragile_ivar) - { - // Make sure we aren't trying to deref an objective - // C ivar if this is not allowed - const uint32_t pointer_type_flags = valobj_sp->GetCompilerType().GetTypeInfo(nullptr); - if ((pointer_type_flags & eTypeIsObjC) && - (pointer_type_flags & eTypeIsPointer)) - { - // This was an objective C object pointer and - // it was requested we skip any fragile ivars - // so return nothing here - return ValueObjectSP(); - } - } - var_path.erase (0, 1); // Remove the '-' - LLVM_FALLTHROUGH; - case '.': - { - const bool expr_is_ptr = var_path[0] == '>'; - - var_path.erase (0, 1); // Remove the '.' or '>' - separator_idx = var_path.find_first_of(".-["); - ConstString child_name; - if (separator_idx == std::string::npos) - child_name.SetCString (var_path.c_str()); - else - child_name.SetCStringWithLength(var_path.c_str(), separator_idx); - - if (check_ptr_vs_member) - { - // We either have a pointer type and need to verify - // valobj_sp is a pointer, or we have a member of a - // class/union/struct being accessed with the . syntax - // and need to verify we don't have a pointer. - const bool actual_is_ptr = valobj_sp->IsPointerType (); - - if (actual_is_ptr != expr_is_ptr) - { - // Incorrect use of "." with a pointer, or "->" with - // a class/union/struct instance or reference. - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - if (actual_is_ptr) - error.SetErrorStringWithFormat ("\"%s\" is a pointer and . was used to attempt to access \"%s\". Did you mean \"%s->%s\"?", - var_expr_path_strm.GetString().c_str(), - child_name.GetCString(), - var_expr_path_strm.GetString().c_str(), - var_path.c_str()); - else - error.SetErrorStringWithFormat ("\"%s\" is not a pointer and -> was used to attempt to access \"%s\". Did you mean \"%s.%s\"?", - var_expr_path_strm.GetString().c_str(), - child_name.GetCString(), - var_expr_path_strm.GetString().c_str(), - var_path.c_str()); - return ValueObjectSP(); - } - } - child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true); - if (!child_valobj_sp) - { - if (!no_synth_child) - { - child_valobj_sp = valobj_sp->GetSyntheticValue(); - if (child_valobj_sp) - child_valobj_sp = child_valobj_sp->GetChildMemberWithName (child_name, true); - } - - if (no_synth_child || !child_valobj_sp) - { - // No child member with name "child_name" - if (synthetically_added_instance_object) - { - // We added a "this->" or "self->" to the beginning of the expression - // and this is the first pointer ivar access, so just return the normal - // error - error.SetErrorStringWithFormat("no variable or instance variable named '%s' found in this frame", - name_const_string.GetCString()); - } - else - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - if (child_name) - { - error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"", - child_name.GetCString(), - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - else - { - error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"", - var_expr_path_strm.GetString().c_str(), - var_expr_cstr); - } - } - return ValueObjectSP(); - } - } - synthetically_added_instance_object = false; - // Remove the child name from the path - var_path.erase(0, child_name.GetLength()); - if (use_dynamic != eNoDynamicValues) - { - ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); - if (dynamic_value_sp) - child_valobj_sp = dynamic_value_sp; - } - } - break; - - case '[': - // Array member access, or treating pointer as an array - if (var_path.size() > 2) // Need at least two brackets and a number - { - char *end = nullptr; - long child_index = ::strtol (&var_path[1], &end, 0); - if (end && *end == ']' - && *(end-1) != '[') // this code forces an error in the case of arr[]. as bitfield[] is not a good syntax we're good to go - { - if (valobj_sp->GetCompilerType().IsPointerToScalarType() && deref) - { - // what we have is *ptr[low]. the most similar C++ syntax is to deref ptr - // and extract bit low out of it. reading array item low - // would be done by saying ptr[low], without a deref * sign - Error error; - ValueObjectSP temp(valobj_sp->Dereference(error)); - if (error.Fail()) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - return ValueObjectSP(); - } - valobj_sp = temp; - deref = false; - } - else if (valobj_sp->GetCompilerType().IsArrayOfScalarType() && deref) - { - // what we have is *arr[low]. the most similar C++ syntax is to get arr[0] - // (an operation that is equivalent to deref-ing arr) - // and extract bit low out of it. reading array item low - // would be done by saying arr[low], without a deref * sign - Error error; - ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true)); - if (error.Fail()) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - return ValueObjectSP(); - } - valobj_sp = temp; - deref = false; - } - - bool is_incomplete_array = false; - if (valobj_sp->IsPointerType ()) - { - bool is_objc_pointer = true; - - if (valobj_sp->GetCompilerType().GetMinimumLanguage() != eLanguageTypeObjC) - is_objc_pointer = false; - else if (!valobj_sp->GetCompilerType().IsPointerType()) - is_objc_pointer = false; - - if (no_synth_child && is_objc_pointer) - { - error.SetErrorStringWithFormat("\"(%s) %s\" is an Objective-C pointer, and cannot be subscripted", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - - return ValueObjectSP(); - } - else if (is_objc_pointer) - { - // dereferencing ObjC variables is not valid.. so let's try and recur to synthetic children - ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); - if (!synthetic /* no synthetic */ - || synthetic == valobj_sp) /* synthetic is the same as the original object */ - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", - child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - else - { - child_valobj_sp = synthetic->GetChildAtIndex(child_index, true); - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", - child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - } - } - else - { - child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true); - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("failed to use pointer as array for index %ld for \"(%s) %s\"", - child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - } - } - else if (valobj_sp->GetCompilerType().IsArrayType(nullptr, nullptr, &is_incomplete_array)) - { - // Pass false to dynamic_value here so we can tell the difference between - // no dynamic value and no member of this type... - child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true); - if (!child_valobj_sp && (is_incomplete_array || !no_synth_child)) - child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true); - - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", - child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - } - else if (valobj_sp->GetCompilerType().IsScalarType()) - { - // this is a bitfield asking to display just one bit - child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, child_index, true); - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"", - child_index, child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - } - else - { - ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); - if (no_synth_child /* synthetic is forbidden */ || - !synthetic /* no synthetic */ - || synthetic == valobj_sp) /* synthetic is the same as the original object */ - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", - child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - else - { - child_valobj_sp = synthetic->GetChildAtIndex(child_index, true); - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"", - child_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - } - } - - if (!child_valobj_sp) - { - // Invalid array index... - return ValueObjectSP(); - } - - // Erase the array member specification '[%i]' where - // %i is the array index - var_path.erase(0, (end - var_path.c_str()) + 1); - separator_idx = var_path.find_first_of(".-["); - if (use_dynamic != eNoDynamicValues) - { - ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); - if (dynamic_value_sp) - child_valobj_sp = dynamic_value_sp; - } - // Break out early from the switch since we were - // able to find the child member - break; - } - else if (end && *end == '-') - { - // this is most probably a BitField, let's take a look - char *real_end = nullptr; - long final_index = ::strtol (end+1, &real_end, 0); - bool expand_bitfield = true; - if (real_end && *real_end == ']') - { - // if the format given is [high-low], swap range - if (child_index > final_index) - { - long temp = child_index; - child_index = final_index; - final_index = temp; - } - - if (valobj_sp->GetCompilerType().IsPointerToScalarType() && deref) - { - // what we have is *ptr[low-high]. the most similar C++ syntax is to deref ptr - // and extract bits low thru high out of it. reading array items low thru high - // would be done by saying ptr[low-high], without a deref * sign - Error error; - ValueObjectSP temp(valobj_sp->Dereference(error)); - if (error.Fail()) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - return ValueObjectSP(); - } - valobj_sp = temp; - deref = false; - } - else if (valobj_sp->GetCompilerType().IsArrayOfScalarType() && deref) - { - // what we have is *arr[low-high]. the most similar C++ syntax is to get arr[0] - // (an operation that is equivalent to deref-ing arr) - // and extract bits low thru high out of it. reading array items low thru high - // would be done by saying arr[low-high], without a deref * sign - Error error; - ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true)); - if (error.Fail()) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"", - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - return ValueObjectSP(); - } - valobj_sp = temp; - deref = false; - } - /*else if (valobj_sp->IsArrayType() || valobj_sp->IsPointerType()) - { - child_valobj_sp = valobj_sp->GetSyntheticArrayRangeChild(child_index, final_index, true); - expand_bitfield = false; - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("array range %i-%i is not valid for \"(%s) %s\"", - child_index, final_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - }*/ - - if (expand_bitfield) - { - child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true); - if (!child_valobj_sp) - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"", - child_index, final_index, - valobj_sp->GetTypeName().AsCString("<invalid type>"), - var_expr_path_strm.GetString().c_str()); - } - } - } - - if (!child_valobj_sp) - { - // Invalid bitfield range... - return ValueObjectSP(); - } - - // Erase the bitfield member specification '[%i-%i]' where - // %i is the index - var_path.erase(0, (real_end - var_path.c_str()) + 1); - separator_idx = var_path.find_first_of(".-["); - if (use_dynamic != eNoDynamicValues) - { - ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic)); - if (dynamic_value_sp) - child_valobj_sp = dynamic_value_sp; - } - // Break out early from the switch since we were - // able to find the child member - break; - - } - } - else - { - error.SetErrorStringWithFormat("invalid square bracket encountered after \"%s\" in \"%s\"", - var_expr_path_strm.GetString().c_str(), - var_path.c_str()); - } - return ValueObjectSP(); - - default: - // Failure... - { - valobj_sp->GetExpressionPath (var_expr_path_strm, false); - error.SetErrorStringWithFormat ("unexpected char '%c' encountered after \"%s\" in \"%s\"", - separator_type, - var_expr_path_strm.GetString().c_str(), - var_path.c_str()); - - return ValueObjectSP(); - } + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "\"(%s) %s\" is not an array type", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } else if ( + static_cast<uint32_t>(child_index) >= + synthetic + ->GetNumChildren() /* synthetic does not have that many values */) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } else { + child_valobj_sp = + synthetic->GetChildAtIndex(child_index, true); + if (!child_valobj_sp) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "array index %ld is not valid for \"(%s) %s\"", + child_index, valobj_sp->GetTypeName().AsCString( + "<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + } else { + child_valobj_sp = + valobj_sp->GetSyntheticArrayMember(child_index, true); + if (!child_valobj_sp) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "failed to use pointer as array for index %ld for " + "\"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); } + } + } else if (valobj_sp->GetCompilerType().IsArrayType( + nullptr, nullptr, &is_incomplete_array)) { + // Pass false to dynamic_value here so we can tell the + // difference between + // no dynamic value and no member of this type... + child_valobj_sp = + valobj_sp->GetChildAtIndex(child_index, true); + if (!child_valobj_sp && + (is_incomplete_array || !no_synth_child)) + child_valobj_sp = + valobj_sp->GetSyntheticArrayMember(child_index, true); + + if (!child_valobj_sp) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } else if (valobj_sp->GetCompilerType().IsScalarType()) { + // this is a bitfield asking to display just one bit + child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild( + child_index, child_index, true); + if (!child_valobj_sp) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "bitfield range %ld-%ld is not valid for \"(%s) %s\"", + child_index, child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } else { + ValueObjectSP synthetic = valobj_sp->GetSyntheticValue(); + if (no_synth_child /* synthetic is forbidden */ || + !synthetic /* no synthetic */ + || + synthetic == valobj_sp) /* synthetic is the same as the + original object */ + { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "\"(%s) %s\" is not an array type", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } else if ( + static_cast<uint32_t>(child_index) >= + synthetic + ->GetNumChildren() /* synthetic does not have that many values */) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } else { + child_valobj_sp = + synthetic->GetChildAtIndex(child_index, true); + if (!child_valobj_sp) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "array index %ld is not valid for \"(%s) %s\"", + child_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } + } - if (child_valobj_sp) - valobj_sp = child_valobj_sp; + if (!child_valobj_sp) { + // Invalid array index... + return ValueObjectSP(); + } - if (var_path.empty()) - break; + // Erase the array member specification '[%i]' where + // %i is the array index + var_path.erase(0, (end - var_path.c_str()) + 1); + separator_idx = var_path.find_first_of(".-["); + if (use_dynamic != eNoDynamicValues) { + ValueObjectSP dynamic_value_sp( + child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; } - if (valobj_sp) - { - if (deref) - { - ValueObjectSP deref_valobj_sp (valobj_sp->Dereference(error)); - valobj_sp = deref_valobj_sp; + // Break out early from the switch since we were + // able to find the child member + break; + } else if (end && *end == '-') { + // this is most probably a BitField, let's take a look + char *real_end = nullptr; + long final_index = ::strtol(end + 1, &real_end, 0); + bool expand_bitfield = true; + if (real_end && *real_end == ']') { + // if the format given is [high-low], swap range + if (child_index > final_index) { + long temp = child_index; + child_index = final_index; + final_index = temp; + } + + if (valobj_sp->GetCompilerType().IsPointerToScalarType() && + deref) { + // what we have is *ptr[low-high]. the most similar C++ + // syntax is to deref ptr + // and extract bits low thru high out of it. reading array + // items low thru high + // would be done by saying ptr[low-high], without a deref * + // sign + Error error; + ValueObjectSP temp(valobj_sp->Dereference(error)); + if (error.Fail()) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "could not dereference \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); } - else if (address_of) - { - ValueObjectSP address_of_valobj_sp (valobj_sp->AddressOf(error)); - valobj_sp = address_of_valobj_sp; + valobj_sp = temp; + deref = false; + } else if (valobj_sp->GetCompilerType() + .IsArrayOfScalarType() && + deref) { + // what we have is *arr[low-high]. the most similar C++ + // syntax is to get arr[0] + // (an operation that is equivalent to deref-ing arr) + // and extract bits low thru high out of it. reading array + // items low thru high + // would be done by saying arr[low-high], without a deref * + // sign + Error error; + ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true)); + if (error.Fail()) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "could not get item 0 for \"(%s) %s\"", + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + return ValueObjectSP(); } + valobj_sp = temp; + deref = false; + } + /*else if (valobj_sp->IsArrayType() || + valobj_sp->IsPointerType()) + { + child_valobj_sp = + valobj_sp->GetSyntheticArrayRangeChild(child_index, + final_index, true); + expand_bitfield = false; + if (!child_valobj_sp) + { + valobj_sp->GetExpressionPath (var_expr_path_strm, + false); + error.SetErrorStringWithFormat ("array range %i-%i is + not valid for \"(%s) %s\"", + child_index, + final_index, + valobj_sp->GetTypeName().AsCString("<invalid + type>"), + var_expr_path_strm.GetString().c_str()); + } + }*/ + + if (expand_bitfield) { + child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild( + child_index, final_index, true); + if (!child_valobj_sp) { + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "bitfield range %ld-%ld is not valid for \"(%s) %s\"", + child_index, final_index, + valobj_sp->GetTypeName().AsCString("<invalid type>"), + var_expr_path_strm.GetString().c_str()); + } + } } - return valobj_sp; - } - else - { - error.SetErrorStringWithFormat("no variable named '%s' found in this frame", - name_const_string.GetCString()); - } - } - } - else - { - error.SetErrorStringWithFormat("invalid variable path '%s'", var_expr_cstr); - } - return ValueObjectSP(); -} -bool -StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (!m_cfa_is_valid) - { - m_frame_base_error.SetErrorString("No frame base available for this historical stack frame."); - return false; - } + if (!child_valobj_sp) { + // Invalid bitfield range... + return ValueObjectSP(); + } - if (m_flags.IsClear(GOT_FRAME_BASE)) - { - if (m_sc.function) - { - m_frame_base.Clear(); - m_frame_base_error.Clear(); - - m_flags.Set(GOT_FRAME_BASE); - ExecutionContext exe_ctx (shared_from_this()); - Value expr_value; - addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; - if (m_sc.function->GetFrameBaseExpression().IsLocationList()) - loclist_base_addr = m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (exe_ctx.GetTargetPtr()); - - if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx, - nullptr, - nullptr, - nullptr, - loclist_base_addr, - nullptr, - nullptr, - expr_value, - &m_frame_base_error) == false) - { - // We should really have an error if evaluate returns, but in case - // we don't, lets set the error to something at least. - if (m_frame_base_error.Success()) - m_frame_base_error.SetErrorString("Evaluation of the frame base expression failed."); + // Erase the bitfield member specification '[%i-%i]' where + // %i is the index + var_path.erase(0, (real_end - var_path.c_str()) + 1); + separator_idx = var_path.find_first_of(".-["); + if (use_dynamic != eNoDynamicValues) { + ValueObjectSP dynamic_value_sp( + child_valobj_sp->GetDynamicValue(use_dynamic)); + if (dynamic_value_sp) + child_valobj_sp = dynamic_value_sp; + } + // Break out early from the switch since we were + // able to find the child member + break; + } + } else { + error.SetErrorStringWithFormat( + "invalid square bracket encountered after \"%s\" in \"%s\"", + var_expr_path_strm.GetString().c_str(), var_path.c_str()); } - else + return ValueObjectSP(); + + default: + // Failure... { - m_frame_base = expr_value.ResolveValue(&exe_ctx); + valobj_sp->GetExpressionPath(var_expr_path_strm, false); + error.SetErrorStringWithFormat( + "unexpected char '%c' encountered after \"%s\" in \"%s\"", + separator_type, var_expr_path_strm.GetString().c_str(), + var_path.c_str()); + + return ValueObjectSP(); } + } + + if (child_valobj_sp) + valobj_sp = child_valobj_sp; + + if (var_path.empty()) + break; } - else - { - m_frame_base_error.SetErrorString ("No function in symbol context."); + if (valobj_sp) { + if (deref) { + ValueObjectSP deref_valobj_sp(valobj_sp->Dereference(error)); + valobj_sp = deref_valobj_sp; + } else if (address_of) { + ValueObjectSP address_of_valobj_sp(valobj_sp->AddressOf(error)); + valobj_sp = address_of_valobj_sp; + } } + return valobj_sp; + } else { + error.SetErrorStringWithFormat( + "no variable named '%s' found in this frame", + name_const_string.GetCString()); + } + } + } else { + error.SetErrorStringWithFormat("invalid variable path '%s'", var_expr_cstr); + } + return ValueObjectSP(); +} + +bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Error *error_ptr) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (!m_cfa_is_valid) { + m_frame_base_error.SetErrorString( + "No frame base available for this historical stack frame."); + return false; + } + + if (m_flags.IsClear(GOT_FRAME_BASE)) { + if (m_sc.function) { + m_frame_base.Clear(); + m_frame_base_error.Clear(); + + m_flags.Set(GOT_FRAME_BASE); + ExecutionContext exe_ctx(shared_from_this()); + Value expr_value; + addr_t loclist_base_addr = LLDB_INVALID_ADDRESS; + if (m_sc.function->GetFrameBaseExpression().IsLocationList()) + loclist_base_addr = + m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress( + exe_ctx.GetTargetPtr()); + + if (m_sc.function->GetFrameBaseExpression().Evaluate( + &exe_ctx, nullptr, nullptr, nullptr, loclist_base_addr, nullptr, + nullptr, expr_value, &m_frame_base_error) == false) { + // We should really have an error if evaluate returns, but in case + // we don't, lets set the error to something at least. + if (m_frame_base_error.Success()) + m_frame_base_error.SetErrorString( + "Evaluation of the frame base expression failed."); + } else { + m_frame_base = expr_value.ResolveValue(&exe_ctx); + } + } else { + m_frame_base_error.SetErrorString("No function in symbol context."); } + } - if (m_frame_base_error.Success()) - frame_base = m_frame_base; + if (m_frame_base_error.Success()) + frame_base = m_frame_base; - if (error_ptr) - *error_ptr = m_frame_base_error; - return m_frame_base_error.Success(); + if (error_ptr) + *error_ptr = m_frame_base_error; + return m_frame_base_error.Success(); } -DWARFExpression * -StackFrame::GetFrameBaseExpression(Error *error_ptr) -{ - if (!m_sc.function) - { - if (error_ptr) - { - error_ptr->SetErrorString ("No function in symbol context."); - } - return nullptr; +DWARFExpression *StackFrame::GetFrameBaseExpression(Error *error_ptr) { + if (!m_sc.function) { + if (error_ptr) { + error_ptr->SetErrorString("No function in symbol context."); } + return nullptr; + } - return &m_sc.function->GetFrameBaseExpression(); + return &m_sc.function->GetFrameBaseExpression(); } -RegisterContextSP -StackFrame::GetRegisterContext () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (!m_reg_context_sp) - { - ThreadSP thread_sp (GetThread()); - if (thread_sp) - m_reg_context_sp = thread_sp->CreateRegisterContextForFrame (this); - } - return m_reg_context_sp; +RegisterContextSP StackFrame::GetRegisterContext() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (!m_reg_context_sp) { + ThreadSP thread_sp(GetThread()); + if (thread_sp) + m_reg_context_sp = thread_sp->CreateRegisterContextForFrame(this); + } + return m_reg_context_sp; } -bool -StackFrame::HasDebugInformation () -{ - GetSymbolContext (eSymbolContextLineEntry); - return m_sc.line_entry.IsValid(); +bool StackFrame::HasDebugInformation() { + GetSymbolContext(eSymbolContextLineEntry); + return m_sc.line_entry.IsValid(); } ValueObjectSP -StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - ValueObjectSP valobj_sp; - if (m_is_history_frame) - { - return valobj_sp; - } - VariableList *var_list = GetVariableList (true); - if (var_list) - { - // Make sure the variable is a frame variable - const uint32_t var_idx = var_list->FindIndexForVariable (variable_sp.get()); - const uint32_t num_variables = var_list->GetSize(); - if (var_idx < num_variables) - { - valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex (var_idx); - if (!valobj_sp) - { - if (m_variable_list_value_objects.GetSize() < num_variables) - m_variable_list_value_objects.Resize(num_variables); - valobj_sp = ValueObjectVariable::Create (this, variable_sp); - m_variable_list_value_objects.SetValueObjectAtIndex (var_idx, valobj_sp); - } - } - } - if (use_dynamic != eNoDynamicValues && valobj_sp) - { - ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue (use_dynamic); - if (dynamic_sp) - return dynamic_sp; - } +StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp, + DynamicValueType use_dynamic) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + ValueObjectSP valobj_sp; + if (m_is_history_frame) { return valobj_sp; + } + VariableList *var_list = GetVariableList(true); + if (var_list) { + // Make sure the variable is a frame variable + const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get()); + const uint32_t num_variables = var_list->GetSize(); + if (var_idx < num_variables) { + valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx); + if (!valobj_sp) { + if (m_variable_list_value_objects.GetSize() < num_variables) + m_variable_list_value_objects.Resize(num_variables); + valobj_sp = ValueObjectVariable::Create(this, variable_sp); + m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, valobj_sp); + } + } + } + if (use_dynamic != eNoDynamicValues && valobj_sp) { + ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(use_dynamic); + if (dynamic_sp) + return dynamic_sp; + } + return valobj_sp; } -ValueObjectSP -StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_is_history_frame) - return ValueObjectSP(); +ValueObjectSP StackFrame::TrackGlobalVariable(const VariableSP &variable_sp, + DynamicValueType use_dynamic) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_is_history_frame) + return ValueObjectSP(); - // Check to make sure we aren't already tracking this variable? - ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp, use_dynamic)); - if (!valobj_sp) - { - // We aren't already tracking this global - VariableList *var_list = GetVariableList (true); - // If this frame has no variables, create a new list - if (var_list == nullptr) - m_variable_list_sp.reset (new VariableList()); - - // Add the global/static variable to this frame - m_variable_list_sp->AddVariable (variable_sp); - - // Now make a value object for it so we can track its changes - valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic); - } - return valobj_sp; + // Check to make sure we aren't already tracking this variable? + ValueObjectSP valobj_sp( + GetValueObjectForFrameVariable(variable_sp, use_dynamic)); + if (!valobj_sp) { + // We aren't already tracking this global + VariableList *var_list = GetVariableList(true); + // If this frame has no variables, create a new list + if (var_list == nullptr) + m_variable_list_sp.reset(new VariableList()); + + // Add the global/static variable to this frame + m_variable_list_sp->AddVariable(variable_sp); + + // Now make a value object for it so we can track its changes + valobj_sp = GetValueObjectForFrameVariable(variable_sp, use_dynamic); + } + return valobj_sp; } -bool -StackFrame::IsInlined () -{ - if (m_sc.block == nullptr) - GetSymbolContext (eSymbolContextBlock); - if (m_sc.block) - return m_sc.block->GetContainingInlinedBlock() != nullptr; - return false; +bool StackFrame::IsInlined() { + if (m_sc.block == nullptr) + GetSymbolContext(eSymbolContextBlock); + if (m_sc.block) + return m_sc.block->GetContainingInlinedBlock() != nullptr; + return false; } -lldb::LanguageType -StackFrame::GetLanguage () -{ - CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit; - if (cu) - return cu->GetLanguage(); - return lldb::eLanguageTypeUnknown; +lldb::LanguageType StackFrame::GetLanguage() { + CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit; + if (cu) + return cu->GetLanguage(); + return lldb::eLanguageTypeUnknown; } -lldb::LanguageType -StackFrame::GuessLanguage () -{ - LanguageType lang_type = GetLanguage(); - - if (lang_type == eLanguageTypeUnknown) - { - Function *f = GetSymbolContext(eSymbolContextFunction).function; - if (f) - { - lang_type = f->GetMangled().GuessLanguage(); - } +lldb::LanguageType StackFrame::GuessLanguage() { + LanguageType lang_type = GetLanguage(); + + if (lang_type == eLanguageTypeUnknown) { + Function *f = GetSymbolContext(eSymbolContextFunction).function; + if (f) { + lang_type = f->GetMangled().GuessLanguage(); } - - return lang_type; + } + + return lang_type; } -namespace -{ - std::pair<const Instruction::Operand *, int64_t> - GetBaseExplainingValue(const Instruction::Operand &operand, - RegisterContext ®ister_context, - lldb::addr_t value) - { - switch(operand.m_type) - { - case Instruction::Operand::Type::Dereference: - case Instruction::Operand::Type::Immediate: - case Instruction::Operand::Type::Invalid: - case Instruction::Operand::Type::Product: - // These are not currently interesting - return std::make_pair(nullptr, 0); - case Instruction::Operand::Type::Sum: - { - const Instruction::Operand *immediate_child = nullptr; - const Instruction::Operand *variable_child = nullptr; - if (operand.m_children[0].m_type == Instruction::Operand::Type::Immediate) - { - immediate_child = &operand.m_children[0]; - variable_child = &operand.m_children[1]; - } - else if (operand.m_children[1].m_type == Instruction::Operand::Type::Immediate) - { - immediate_child = &operand.m_children[1]; - variable_child = &operand.m_children[0]; - } - if (!immediate_child) - { - return std::make_pair(nullptr, 0); - } - lldb::addr_t adjusted_value = value; - if (immediate_child->m_negative) - { - adjusted_value += immediate_child->m_immediate; - } - else - { - adjusted_value -= immediate_child->m_immediate; - } - std::pair<const Instruction::Operand *, int64_t> base_and_offset = GetBaseExplainingValue(*variable_child, register_context, adjusted_value); - if (!base_and_offset.first) - { - return std::make_pair(nullptr, 0); - } - if (immediate_child->m_negative) - { - base_and_offset.second -= immediate_child->m_immediate; - } - else - { - base_and_offset.second += immediate_child->m_immediate; - } - return base_and_offset; - } - case Instruction::Operand::Type::Register: - { - const RegisterInfo *info = register_context.GetRegisterInfoByName(operand.m_register.AsCString()); - if (!info) - { - return std::make_pair(nullptr, 0); - } - RegisterValue reg_value; - if (!register_context.ReadRegister(info, reg_value)) - { - return std::make_pair(nullptr, 0); - } - if (reg_value.GetAsUInt64() == value) - { - return std::make_pair(&operand, 0); - } - else - { - return std::make_pair(nullptr, 0); - } - } - } +namespace { +std::pair<const Instruction::Operand *, int64_t> +GetBaseExplainingValue(const Instruction::Operand &operand, + RegisterContext ®ister_context, lldb::addr_t value) { + switch (operand.m_type) { + case Instruction::Operand::Type::Dereference: + case Instruction::Operand::Type::Immediate: + case Instruction::Operand::Type::Invalid: + case Instruction::Operand::Type::Product: + // These are not currently interesting + return std::make_pair(nullptr, 0); + case Instruction::Operand::Type::Sum: { + const Instruction::Operand *immediate_child = nullptr; + const Instruction::Operand *variable_child = nullptr; + if (operand.m_children[0].m_type == Instruction::Operand::Type::Immediate) { + immediate_child = &operand.m_children[0]; + variable_child = &operand.m_children[1]; + } else if (operand.m_children[1].m_type == + Instruction::Operand::Type::Immediate) { + immediate_child = &operand.m_children[1]; + variable_child = &operand.m_children[0]; } - - std::pair<const Instruction::Operand *, int64_t> - GetBaseExplainingDereference(const Instruction::Operand &operand, - RegisterContext ®ister_context, - lldb::addr_t addr) - { - if (operand.m_type == Instruction::Operand::Type::Dereference) - { - return GetBaseExplainingValue(operand.m_children[0], - register_context, - addr); - } - return std::make_pair(nullptr, 0); + if (!immediate_child) { + return std::make_pair(nullptr, 0); + } + lldb::addr_t adjusted_value = value; + if (immediate_child->m_negative) { + adjusted_value += immediate_child->m_immediate; + } else { + adjusted_value -= immediate_child->m_immediate; + } + std::pair<const Instruction::Operand *, int64_t> base_and_offset = + GetBaseExplainingValue(*variable_child, register_context, + adjusted_value); + if (!base_and_offset.first) { + return std::make_pair(nullptr, 0); + } + if (immediate_child->m_negative) { + base_and_offset.second -= immediate_child->m_immediate; + } else { + base_and_offset.second += immediate_child->m_immediate; + } + return base_and_offset; + } + case Instruction::Operand::Type::Register: { + const RegisterInfo *info = + register_context.GetRegisterInfoByName(operand.m_register.AsCString()); + if (!info) { + return std::make_pair(nullptr, 0); } + RegisterValue reg_value; + if (!register_context.ReadRegister(info, reg_value)) { + return std::make_pair(nullptr, 0); + } + if (reg_value.GetAsUInt64() == value) { + return std::make_pair(&operand, 0); + } else { + return std::make_pair(nullptr, 0); + } + } + } +} + +std::pair<const Instruction::Operand *, int64_t> +GetBaseExplainingDereference(const Instruction::Operand &operand, + RegisterContext ®ister_context, + lldb::addr_t addr) { + if (operand.m_type == Instruction::Operand::Type::Dereference) { + return GetBaseExplainingValue(operand.m_children[0], register_context, + addr); + } + return std::make_pair(nullptr, 0); +} }; -lldb::ValueObjectSP -StackFrame::GuessValueForAddress(lldb::addr_t addr) -{ - TargetSP target_sp = CalculateTarget(); - - const ArchSpec &target_arch = target_sp->GetArchitecture(); - - AddressRange pc_range; - pc_range.GetBaseAddress() = GetFrameCodeAddress(); - pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize()); - - ExecutionContext exe_ctx (shared_from_this()); - - const char *plugin_name = nullptr; - const char *flavor = nullptr; - const bool prefer_file_cache = false; - - DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch, - plugin_name, - flavor, - exe_ctx, - pc_range, - prefer_file_cache); - - if (!disassembler_sp->GetInstructionList().GetSize()) - { - return ValueObjectSP(); +lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) { + TargetSP target_sp = CalculateTarget(); + + const ArchSpec &target_arch = target_sp->GetArchitecture(); + + AddressRange pc_range; + pc_range.GetBaseAddress() = GetFrameCodeAddress(); + pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize()); + + ExecutionContext exe_ctx(shared_from_this()); + + const char *plugin_name = nullptr; + const char *flavor = nullptr; + const bool prefer_file_cache = false; + + DisassemblerSP disassembler_sp = Disassembler::DisassembleRange( + target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache); + + if (!disassembler_sp->GetInstructionList().GetSize()) { + return ValueObjectSP(); + } + + InstructionSP instruction_sp = + disassembler_sp->GetInstructionList().GetInstructionAtIndex(0); + + llvm::SmallVector<Instruction::Operand, 3> operands; + + if (!instruction_sp->ParseOperands(operands)) { + return ValueObjectSP(); + } + + RegisterContextSP register_context_sp = GetRegisterContext(); + + if (!register_context_sp) { + return ValueObjectSP(); + } + + for (const Instruction::Operand &operand : operands) { + std::pair<const Instruction::Operand *, int64_t> base_and_offset = + GetBaseExplainingDereference(operand, *register_context_sp, addr); + + if (!base_and_offset.first) { + continue; } - - InstructionSP instruction_sp = disassembler_sp->GetInstructionList().GetInstructionAtIndex(0); - - llvm::SmallVector<Instruction::Operand, 3> operands; - - if (!instruction_sp->ParseOperands(operands)) - { + + switch (base_and_offset.first->m_type) { + case Instruction::Operand::Type::Immediate: { + lldb_private::Address addr; + if (target_sp->ResolveLoadAddress(base_and_offset.first->m_immediate + + base_and_offset.second, + addr)) { + TypeSystem *c_type_system = + target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC); + if (!c_type_system) { + return ValueObjectSP(); + } else { + CompilerType void_ptr_type = + c_type_system + ->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar) + .GetPointerType(); + return ValueObjectMemory::Create(this, "", addr, void_ptr_type); + } + } else { return ValueObjectSP(); + } + break; } - - RegisterContextSP register_context_sp = GetRegisterContext(); - - if (!register_context_sp) - { - return ValueObjectSP(); + case Instruction::Operand::Type::Register: { + return GuessValueForRegisterAndOffset(base_and_offset.first->m_register, + base_and_offset.second); } - - for (const Instruction::Operand &operand : operands) - { - std::pair<const Instruction::Operand *, int64_t> - base_and_offset = GetBaseExplainingDereference(operand, *register_context_sp, addr); - - if (!base_and_offset.first) - { - continue; - } - - switch (base_and_offset.first->m_type) - { - case Instruction::Operand::Type::Immediate: - { - lldb_private::Address addr; - if (target_sp->ResolveLoadAddress(base_and_offset.first->m_immediate + base_and_offset.second, addr)) - { - TypeSystem *c_type_system = target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC); - if (!c_type_system) - { - return ValueObjectSP(); - } - else - { - CompilerType void_ptr_type = c_type_system->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar).GetPointerType(); - return ValueObjectMemory::Create(this, "", addr, void_ptr_type); - } - } - else - { - return ValueObjectSP(); - } - break; - } - case Instruction::Operand::Type::Register: - { - return GuessValueForRegisterAndOffset(base_and_offset.first->m_register, base_and_offset.second); - } - default: - return ValueObjectSP(); - } - + default: + return ValueObjectSP(); } + } + return ValueObjectSP(); +} + +namespace { +ValueObjectSP GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, + int64_t offset) { + if (offset < 0 || uint64_t(offset) >= parent->GetByteSize()) { return ValueObjectSP(); + } + + if (parent->IsPointerOrReferenceType()) { + return parent; + } + + for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci) { + const bool can_create = true; + ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create); + + if (!child_sp) { + return ValueObjectSP(); + } + + int64_t child_offset = child_sp->GetByteOffset(); + int64_t child_size = child_sp->GetByteSize(); + + if (offset >= child_offset && offset < (child_offset + child_size)) { + return GetValueForOffset(frame, child_sp, offset - child_offset); + } + } + + if (offset == 0) { + return parent; + } else { + return ValueObjectSP(); + } } -namespace -{ - ValueObjectSP - GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, int64_t offset) - { - if (offset < 0 || uint64_t(offset) >= parent->GetByteSize()) - { - return ValueObjectSP(); - } - - if (parent->IsPointerOrReferenceType()) - { - return parent; +ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame, + ValueObjectSP &base, + int64_t offset) { + // base is a pointer to something + // offset is the thing to add to the pointer + // We return the most sensible ValueObject for the result of *(base+offset) + + if (!base->IsPointerOrReferenceType()) { + return ValueObjectSP(); + } + + Error error; + ValueObjectSP pointee = base->Dereference(error); + + if (offset >= pointee->GetByteSize()) { + int64_t index = offset / pointee->GetByteSize(); + offset = offset % pointee->GetByteSize(); + const bool can_create = true; + pointee = base->GetSyntheticArrayMember(index, can_create); + } + + if (!pointee || error.Fail()) { + return ValueObjectSP(); + } + + return GetValueForOffset(frame, pointee, offset); +} + +//------------------------------------------------------------------ +/// Attempt to reconstruct the ValueObject for the address contained in a +/// given register plus an offset. +/// +/// @params [in] frame +/// The current stack frame. +/// +/// @params [in] reg +/// The register. +/// +/// @params [in] offset +/// The offset from the register. +/// +/// @param [in] disassembler +/// A disassembler containing instructions valid up to the current PC. +/// +/// @param [in] variables +/// The variable list from the current frame, +/// +/// @param [in] pc +/// The program counter for the instruction considered the 'user'. +/// +/// @return +/// A string describing the base for the ExpressionPath. This could be a +/// variable, a register value, an argument, or a function return value. +/// The ValueObject if found. If valid, it has a valid ExpressionPath. +//------------------------------------------------------------------ +lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg, + int64_t offset, Disassembler &disassembler, + VariableList &variables, const Address &pc) { + // Example of operation for Intel: + // + // +14: movq -0x8(%rbp), %rdi + // +18: movq 0x8(%rdi), %rdi + // +22: addl 0x4(%rdi), %eax + // + // f, a pointer to a struct, is known to be at -0x8(%rbp). + // + // DoGuessValueAt(frame, rdi, 4, dis, vars, 0x22) finds the instruction at +18 + // that assigns to rdi, and calls itself recursively for that dereference + // DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at + // +14 that assigns to rdi, and calls itself recursively for that + // derefernece + // DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the + // variable list. + // Returns a ValueObject for f. (That's what was stored at rbp-8 at +14) + // Returns a ValueObject for *(f+8) or f->b (That's what was stored at rdi+8 + // at +18) + // Returns a ValueObject for *(f->b+4) or f->b->a (That's what was stored at + // rdi+4 at +22) + + // First, check the variable list to see if anything is at the specified + // location. + for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi) { + VariableSP var_sp = variables.GetVariableAtIndex(vi); + DWARFExpression &dwarf_expression = var_sp->LocationExpression(); + + const RegisterInfo *expression_reg; + int64_t expression_offset; + ExecutionContext exe_ctx; + + if (dwarf_expression.IsDereferenceOfRegister(frame, expression_reg, + expression_offset)) { + if ((reg == ConstString(expression_reg->name) || + reg == ConstString(expression_reg->alt_name)) && + expression_offset == offset) { + return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues); + } + } + } + + bool is_in_return_register = false; + ABISP abi_sp = frame.CalculateProcess()->GetABI(); + RegisterInfo return_register_info; + + if (abi_sp) { + const char *return_register_name; + const RegisterInfo *reg_info = nullptr; + if (abi_sp->GetPointerReturnRegister(return_register_name) && + reg == ConstString(return_register_name) && + (reg_info = frame.GetRegisterContext()->GetRegisterInfoByName( + return_register_name))) { + is_in_return_register = true; + return_register_info = *reg_info; + } + } + + const uint32_t current_inst = + disassembler.GetInstructionList().GetIndexOfInstructionAtAddress(pc); + if (current_inst == UINT32_MAX) { + return ValueObjectSP(); + } + + ValueObjectSP source_path; + + for (uint32_t ii = current_inst - 1; ii != (uint32_t)-1; --ii) { + // This is not an exact algorithm, and it sacrifices accuracy for + // generality. + // Recognizing "mov" and "ld" instructions –– and which are their source and + // destination operands -- is something the disassembler should do for us. + InstructionSP instruction_sp = + disassembler.GetInstructionList().GetInstructionAtIndex(ii); + + if (is_in_return_register && instruction_sp->IsCall()) { + llvm::SmallVector<Instruction::Operand, 1> operands; + if (!instruction_sp->ParseOperands(operands) || operands.size() != 1) { + continue; + } + + switch (operands[0].m_type) { + default: + break; + case Instruction::Operand::Type::Immediate: { + SymbolContext sc; + Address load_address; + if (!frame.CalculateTarget()->ResolveLoadAddress( + operands[0].m_immediate, load_address)) { + break; } - - for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci) - { - const bool can_create = true; - ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create); - - if (!child_sp) - { - return ValueObjectSP(); - } - - int64_t child_offset = child_sp->GetByteOffset(); - int64_t child_size = child_sp->GetByteSize(); - - if (offset >= child_offset && - offset < (child_offset + child_size)) - { - return GetValueForOffset(frame, child_sp, offset - child_offset); - } + frame.CalculateTarget()->GetImages().ResolveSymbolContextForAddress( + load_address, eSymbolContextFunction, sc); + if (!sc.function) { + break; } - - if (offset == 0) - { - return parent; + CompilerType function_type = sc.function->GetCompilerType(); + if (!function_type.IsFunctionType()) { + break; } - else - { - return ValueObjectSP(); + CompilerType return_type = function_type.GetFunctionReturnType(); + RegisterValue return_value; + if (!frame.GetRegisterContext()->ReadRegister(&return_register_info, + return_value)) { + break; } + std::string name_str( + sc.function->GetName().AsCString("<unknown function>")); + name_str.append("()"); + Address return_value_address(return_value.GetAsUInt64()); + ValueObjectSP return_value_sp = ValueObjectMemory::Create( + &frame, name_str.c_str(), return_value_address, return_type); + return GetValueForDereferincingOffset(frame, return_value_sp, offset); + } + } + + continue; } - - ValueObjectSP - GetValueForDereferincingOffset(StackFrame &frame, ValueObjectSP &base, int64_t offset) - { - // base is a pointer to something - // offset is the thing to add to the pointer - // We return the most sensible ValueObject for the result of *(base+offset) - - if (!base->IsPointerOrReferenceType()) - { - return ValueObjectSP(); + + llvm::SmallVector<Instruction::Operand, 2> operands; + if (!instruction_sp->ParseOperands(operands) || operands.size() != 2) { + continue; + } + + Instruction::Operand *register_operand = nullptr; + Instruction::Operand *origin_operand = nullptr; + if (operands[0].m_type == Instruction::Operand::Type::Register && + operands[0].m_clobbered == true && operands[0].m_register == reg) { + register_operand = &operands[0]; + origin_operand = &operands[1]; + } else if (operands[1].m_type == Instruction::Operand::Type::Register && + operands[1].m_clobbered == true && + operands[1].m_register == reg) { + register_operand = &operands[1]; + origin_operand = &operands[0]; + } else { + continue; + } + + // We have an origin operand. Can we track its value down? + switch (origin_operand->m_type) { + default: + break; + case Instruction::Operand::Type::Register: + source_path = + DoGuessValueAt(frame, origin_operand->m_register, 0, disassembler, + variables, instruction_sp->GetAddress()); + break; + case Instruction::Operand::Type::Dereference: { + const Instruction::Operand &pointer = origin_operand->m_children[0]; + switch (pointer.m_type) { + default: + break; + case Instruction::Operand::Type::Register: + source_path = DoGuessValueAt(frame, pointer.m_register, 0, disassembler, + variables, instruction_sp->GetAddress()); + if (source_path) { + Error err; + source_path = source_path->Dereference(err); + if (!err.Success()) { + source_path.reset(); + } } - - Error error; - ValueObjectSP pointee = base->Dereference(error); - - if (offset >= pointee->GetByteSize()) - { - int64_t index = offset / pointee->GetByteSize(); - offset = offset % pointee->GetByteSize(); - const bool can_create = true; - pointee = base->GetSyntheticArrayMember(index, can_create); + break; + case Instruction::Operand::Type::Sum: { + const Instruction::Operand *origin_register = nullptr; + const Instruction::Operand *origin_offset = nullptr; + if (pointer.m_children.size() != 2) { + break; } - - if (!pointee || error.Fail()) - { - return ValueObjectSP(); + if (pointer.m_children[0].m_type == + Instruction::Operand::Type::Register && + pointer.m_children[1].m_type == + Instruction::Operand::Type::Immediate) { + origin_register = &pointer.m_children[0]; + origin_offset = &pointer.m_children[1]; + } else if (pointer.m_children[1].m_type == + Instruction::Operand::Type::Register && + pointer.m_children[0].m_type == + Instruction::Operand::Type::Immediate) { + origin_register = &pointer.m_children[1]; + origin_offset = &pointer.m_children[0]; } - - return GetValueForOffset(frame, pointee, offset); - } - - //------------------------------------------------------------------ - /// Attempt to reconstruct the ValueObject for the address contained in a - /// given register plus an offset. - /// - /// @params [in] frame - /// The current stack frame. - /// - /// @params [in] reg - /// The register. - /// - /// @params [in] offset - /// The offset from the register. - /// - /// @param [in] disassembler - /// A disassembler containing instructions valid up to the current PC. - /// - /// @param [in] variables - /// The variable list from the current frame, - /// - /// @param [in] pc - /// The program counter for the instruction considered the 'user'. - /// - /// @return - /// A string describing the base for the ExpressionPath. This could be a - /// variable, a register value, an argument, or a function return value. - /// The ValueObject if found. If valid, it has a valid ExpressionPath. - //------------------------------------------------------------------ - lldb::ValueObjectSP - DoGuessValueAt(StackFrame &frame, ConstString reg, int64_t offset, Disassembler &disassembler, VariableList &variables, const Address &pc) - { - // Example of operation for Intel: - // - // +14: movq -0x8(%rbp), %rdi - // +18: movq 0x8(%rdi), %rdi - // +22: addl 0x4(%rdi), %eax - // - // f, a pointer to a struct, is known to be at -0x8(%rbp). - // - // DoGuessValueAt(frame, rdi, 4, dis, vars, 0x22) finds the instruction at +18 that assigns to rdi, and calls itself recursively for that dereference - // DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at +14 that assigns to rdi, and calls itself recursively for that derefernece - // DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the variable list. - // Returns a ValueObject for f. (That's what was stored at rbp-8 at +14) - // Returns a ValueObject for *(f+8) or f->b (That's what was stored at rdi+8 at +18) - // Returns a ValueObject for *(f->b+4) or f->b->a (That's what was stored at rdi+4 at +22) - - // First, check the variable list to see if anything is at the specified location. - for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi) - { - VariableSP var_sp = variables.GetVariableAtIndex(vi); - DWARFExpression &dwarf_expression = var_sp->LocationExpression(); - - const RegisterInfo *expression_reg; - int64_t expression_offset; - ExecutionContext exe_ctx; - - if (dwarf_expression.IsDereferenceOfRegister(frame, expression_reg, expression_offset)) - { - if ((reg == ConstString(expression_reg->name) || - reg == ConstString(expression_reg->alt_name)) && - expression_offset == offset) - { - return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues); - } - } + if (!origin_register) { + break; } - - bool is_in_return_register = false; - ABISP abi_sp = frame.CalculateProcess()->GetABI(); - RegisterInfo return_register_info; - - if (abi_sp) - { - const char *return_register_name; - const RegisterInfo *reg_info = nullptr; - if (abi_sp->GetPointerReturnRegister(return_register_name) && - reg == ConstString(return_register_name) && - (reg_info = frame.GetRegisterContext()->GetRegisterInfoByName(return_register_name))) - { - is_in_return_register = true; - return_register_info = *reg_info; - } + int64_t signed_origin_offset = + origin_offset->m_negative ? -((int64_t)origin_offset->m_immediate) + : origin_offset->m_immediate; + source_path = DoGuessValueAt(frame, origin_register->m_register, + signed_origin_offset, disassembler, + variables, instruction_sp->GetAddress()); + if (!source_path) { + break; } - - const uint32_t current_inst = disassembler.GetInstructionList().GetIndexOfInstructionAtAddress(pc); - if (current_inst == UINT32_MAX) - { - return ValueObjectSP(); - } - - ValueObjectSP source_path; - - for (uint32_t ii = current_inst - 1; ii != (uint32_t)-1; --ii) - { - // This is not an exact algorithm, and it sacrifices accuracy for generality. - // Recognizing "mov" and "ld" instructions –– and which are their source and - // destination operands -- is something the disassembler should do for us. - InstructionSP instruction_sp = disassembler.GetInstructionList().GetInstructionAtIndex(ii); - - if (is_in_return_register && instruction_sp->IsCall()) - { - llvm::SmallVector<Instruction::Operand, 1> operands; - if (!instruction_sp->ParseOperands(operands) || operands.size() != 1) - { - continue; - } - - switch (operands[0].m_type) - { - default: - break; - case Instruction::Operand::Type::Immediate: - { - SymbolContext sc; - Address load_address; - if (!frame.CalculateTarget()->ResolveLoadAddress(operands[0].m_immediate, load_address)) - { - break; - } - frame.CalculateTarget()->GetImages().ResolveSymbolContextForAddress(load_address, eSymbolContextFunction, sc); - if (!sc.function) - { - break; - } - CompilerType function_type = sc.function->GetCompilerType(); - if (!function_type.IsFunctionType()) - { - break; - } - CompilerType return_type = function_type.GetFunctionReturnType(); - RegisterValue return_value; - if (!frame.GetRegisterContext()->ReadRegister(&return_register_info, return_value)) - { - break; - } - std::string name_str(sc.function->GetName().AsCString("<unknown function>")); - name_str.append("()"); - Address return_value_address(return_value.GetAsUInt64()); - ValueObjectSP return_value_sp = ValueObjectMemory::Create(&frame, name_str.c_str(), return_value_address, return_type); - return GetValueForDereferincingOffset(frame, return_value_sp, offset); - } - } + source_path = + GetValueForDereferincingOffset(frame, source_path, offset); + break; + } + } + } + } - continue; - } - - llvm::SmallVector<Instruction::Operand, 2> operands; - if (!instruction_sp->ParseOperands(operands) || operands.size() != 2) - { - continue; - } - - Instruction::Operand *register_operand = nullptr; - Instruction::Operand *origin_operand = nullptr; - if (operands[0].m_type == Instruction::Operand::Type::Register && - operands[0].m_clobbered == true && - operands[0].m_register == reg) - { - register_operand = &operands[0]; - origin_operand = &operands[1]; - } - else if (operands[1].m_type == Instruction::Operand::Type::Register && - operands[1].m_clobbered == true && - operands[1].m_register == reg) - { - register_operand = &operands[1]; - origin_operand = &operands[0]; - } - else - { - continue; - } - - // We have an origin operand. Can we track its value down? - switch (origin_operand->m_type) - { - default: - break; - case Instruction::Operand::Type::Register: - source_path = DoGuessValueAt(frame, origin_operand->m_register, 0, disassembler, variables, instruction_sp->GetAddress()); - break; - case Instruction::Operand::Type::Dereference: - { - const Instruction::Operand &pointer = origin_operand->m_children[0]; - switch (pointer.m_type) - { - default: - break; - case Instruction::Operand::Type::Register: - source_path = DoGuessValueAt(frame, pointer.m_register, 0, disassembler, variables, instruction_sp->GetAddress()); - if (source_path) - { - Error err; - source_path = source_path->Dereference(err); - if (!err.Success()) - { - source_path.reset(); - } - } - break; - case Instruction::Operand::Type::Sum: - { - const Instruction::Operand *origin_register = nullptr; - const Instruction::Operand *origin_offset = nullptr; - if (pointer.m_children.size() != 2) - { - break; - } - if (pointer.m_children[0].m_type == Instruction::Operand::Type::Register && - pointer.m_children[1].m_type == Instruction::Operand::Type::Immediate) - { - origin_register = &pointer.m_children[0]; - origin_offset = &pointer.m_children[1]; - } - else if (pointer.m_children[1].m_type == Instruction::Operand::Type::Register && - pointer.m_children[0].m_type == Instruction::Operand::Type::Immediate) - { - origin_register = &pointer.m_children[1]; - origin_offset = &pointer.m_children[0]; - } - if (!origin_register) - { - break; - } - int64_t signed_origin_offset = origin_offset->m_negative ? -((int64_t)origin_offset->m_immediate) : origin_offset->m_immediate; - source_path = DoGuessValueAt(frame, origin_register->m_register, signed_origin_offset, disassembler, variables, instruction_sp->GetAddress()); - if (!source_path) - { - break; - } - source_path = GetValueForDereferincingOffset(frame, source_path, offset); - break; - } - } - } - } - - if (source_path) - { - return source_path; - } - } - - return ValueObjectSP(); + if (source_path) { + return source_path; } + } + + return ValueObjectSP(); +} } -lldb::ValueObjectSP -StackFrame::GuessValueForRegisterAndOffset(ConstString reg, int64_t offset) -{ - TargetSP target_sp = CalculateTarget(); - - const ArchSpec &target_arch = target_sp->GetArchitecture(); +lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg, + int64_t offset) { + TargetSP target_sp = CalculateTarget(); - Block *frame_block = GetFrameBlock(); - - if (!frame_block) - { - return ValueObjectSP(); - } + const ArchSpec &target_arch = target_sp->GetArchitecture(); - Function *function = frame_block->CalculateSymbolContextFunction(); - if (!function) - { - return ValueObjectSP(); - } - - AddressRange pc_range = function->GetAddressRange(); + Block *frame_block = GetFrameBlock(); - if (GetFrameCodeAddress().GetFileAddress() < pc_range.GetBaseAddress().GetFileAddress() || - GetFrameCodeAddress().GetFileAddress() - pc_range.GetBaseAddress().GetFileAddress() >= pc_range.GetByteSize()) - { - return ValueObjectSP(); - } - - ExecutionContext exe_ctx (shared_from_this()); - - const char *plugin_name = nullptr; - const char *flavor = nullptr; - const bool prefer_file_cache = false; - DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch, - plugin_name, - flavor, - exe_ctx, - pc_range, - prefer_file_cache); - - if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) - { - return ValueObjectSP(); - } - - const bool get_file_globals = false; - VariableList *variables = GetVariableList(get_file_globals); - - if (!variables) - { - return ValueObjectSP(); - } - - return DoGuessValueAt(*this, reg, offset, *disassembler_sp, *variables, GetFrameCodeAddress()); -} + if (!frame_block) { + return ValueObjectSP(); + } -TargetSP -StackFrame::CalculateTarget () -{ - TargetSP target_sp; - ThreadSP thread_sp(GetThread()); - if (thread_sp) - { - ProcessSP process_sp (thread_sp->CalculateProcess()); - if (process_sp) - target_sp = process_sp->CalculateTarget(); - } - return target_sp; -} + Function *function = frame_block->CalculateSymbolContextFunction(); + if (!function) { + return ValueObjectSP(); + } -ProcessSP -StackFrame::CalculateProcess () -{ - ProcessSP process_sp; - ThreadSP thread_sp(GetThread()); - if (thread_sp) - process_sp = thread_sp->CalculateProcess(); - return process_sp; -} + AddressRange pc_range = function->GetAddressRange(); + + if (GetFrameCodeAddress().GetFileAddress() < + pc_range.GetBaseAddress().GetFileAddress() || + GetFrameCodeAddress().GetFileAddress() - + pc_range.GetBaseAddress().GetFileAddress() >= + pc_range.GetByteSize()) { + return ValueObjectSP(); + } -ThreadSP -StackFrame::CalculateThread () -{ - return GetThread(); + ExecutionContext exe_ctx(shared_from_this()); + + const char *plugin_name = nullptr; + const char *flavor = nullptr; + const bool prefer_file_cache = false; + DisassemblerSP disassembler_sp = Disassembler::DisassembleRange( + target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache); + + if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) { + return ValueObjectSP(); + } + + const bool get_file_globals = false; + VariableList *variables = GetVariableList(get_file_globals); + + if (!variables) { + return ValueObjectSP(); + } + + return DoGuessValueAt(*this, reg, offset, *disassembler_sp, *variables, + GetFrameCodeAddress()); } -StackFrameSP -StackFrame::CalculateStackFrame () -{ - return shared_from_this(); +TargetSP StackFrame::CalculateTarget() { + TargetSP target_sp; + ThreadSP thread_sp(GetThread()); + if (thread_sp) { + ProcessSP process_sp(thread_sp->CalculateProcess()); + if (process_sp) + target_sp = process_sp->CalculateTarget(); + } + return target_sp; } -void -StackFrame::CalculateExecutionContext (ExecutionContext &exe_ctx) -{ - exe_ctx.SetContext (shared_from_this()); +ProcessSP StackFrame::CalculateProcess() { + ProcessSP process_sp; + ThreadSP thread_sp(GetThread()); + if (thread_sp) + process_sp = thread_sp->CalculateProcess(); + return process_sp; } -void -StackFrame::DumpUsingSettingsFormat (Stream *strm, const char *frame_marker) -{ - if (strm == nullptr) - return; +ThreadSP StackFrame::CalculateThread() { return GetThread(); } - GetSymbolContext(eSymbolContextEverything); - ExecutionContext exe_ctx (shared_from_this()); - StreamString s; - - if (frame_marker) - s.PutCString(frame_marker); +StackFrameSP StackFrame::CalculateStackFrame() { return shared_from_this(); } - const FormatEntity::Entry *frame_format = nullptr; - Target *target = exe_ctx.GetTargetPtr(); - if (target) - frame_format = target->GetDebugger().GetFrameFormat(); - if (frame_format && FormatEntity::Format(*frame_format, s, &m_sc, &exe_ctx, nullptr, nullptr, false, false)) - { - strm->Write(s.GetData(), s.GetSize()); - } - else - { - Dump (strm, true, false); - strm->EOL(); - } +void StackFrame::CalculateExecutionContext(ExecutionContext &exe_ctx) { + exe_ctx.SetContext(shared_from_this()); } -void -StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths) -{ - if (strm == nullptr) - return; - - if (show_frame_index) - strm->Printf("frame #%u: ", m_frame_index); - ExecutionContext exe_ctx (shared_from_this()); - Target *target = exe_ctx.GetTargetPtr(); - strm->Printf("0x%0*" PRIx64 " ", - target ? (target->GetArchitecture().GetAddressByteSize() * 2) : 16, - GetFrameCodeAddress().GetLoadAddress(target)); - GetSymbolContext(eSymbolContextEverything); - const bool show_module = true; - const bool show_inline = true; - const bool show_function_arguments = true; - const bool show_function_name = true; - m_sc.DumpStopContext (strm, - exe_ctx.GetBestExecutionContextScope(), - GetFrameCodeAddress(), - show_fullpaths, - show_module, - show_inline, - show_function_arguments, - show_function_name); +void StackFrame::DumpUsingSettingsFormat(Stream *strm, + const char *frame_marker) { + if (strm == nullptr) + return; + + GetSymbolContext(eSymbolContextEverything); + ExecutionContext exe_ctx(shared_from_this()); + StreamString s; + + if (frame_marker) + s.PutCString(frame_marker); + + const FormatEntity::Entry *frame_format = nullptr; + Target *target = exe_ctx.GetTargetPtr(); + if (target) + frame_format = target->GetDebugger().GetFrameFormat(); + if (frame_format && FormatEntity::Format(*frame_format, s, &m_sc, &exe_ctx, + nullptr, nullptr, false, false)) { + strm->Write(s.GetData(), s.GetSize()); + } else { + Dump(strm, true, false); + strm->EOL(); + } } -void -StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - assert (GetStackID() == prev_frame.GetStackID()); // TODO: remove this after some testing - m_variable_list_sp = prev_frame.m_variable_list_sp; - m_variable_list_value_objects.Swap (prev_frame.m_variable_list_value_objects); - if (!m_disassembly.GetString().empty()) - m_disassembly.GetString().swap (m_disassembly.GetString()); +void StackFrame::Dump(Stream *strm, bool show_frame_index, + bool show_fullpaths) { + if (strm == nullptr) + return; + + if (show_frame_index) + strm->Printf("frame #%u: ", m_frame_index); + ExecutionContext exe_ctx(shared_from_this()); + Target *target = exe_ctx.GetTargetPtr(); + strm->Printf("0x%0*" PRIx64 " ", + target ? (target->GetArchitecture().GetAddressByteSize() * 2) + : 16, + GetFrameCodeAddress().GetLoadAddress(target)); + GetSymbolContext(eSymbolContextEverything); + const bool show_module = true; + const bool show_inline = true; + const bool show_function_arguments = true; + const bool show_function_name = true; + m_sc.DumpStopContext(strm, exe_ctx.GetBestExecutionContextScope(), + GetFrameCodeAddress(), show_fullpaths, show_module, + show_inline, show_function_arguments, + show_function_name); } -void -StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - assert (GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing - m_id.SetPC (curr_frame.m_id.GetPC()); // Update the Stack ID PC value - assert (GetThread() == curr_frame.GetThread()); - m_frame_index = curr_frame.m_frame_index; - m_concrete_frame_index = curr_frame.m_concrete_frame_index; - m_reg_context_sp = curr_frame.m_reg_context_sp; - m_frame_code_addr = curr_frame.m_frame_code_addr; - assert (!m_sc.target_sp || !curr_frame.m_sc.target_sp || m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get()); - assert (!m_sc.module_sp || !curr_frame.m_sc.module_sp || m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get()); - assert (m_sc.comp_unit == nullptr || curr_frame.m_sc.comp_unit == nullptr || m_sc.comp_unit == curr_frame.m_sc.comp_unit); - assert (m_sc.function == nullptr || curr_frame.m_sc.function == nullptr || m_sc.function == curr_frame.m_sc.function); - m_sc = curr_frame.m_sc; - m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything); - m_flags.Set (m_sc.GetResolvedMask()); - m_frame_base.Clear(); - m_frame_base_error.Clear(); +void StackFrame::UpdateCurrentFrameFromPreviousFrame(StackFrame &prev_frame) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + assert(GetStackID() == + prev_frame.GetStackID()); // TODO: remove this after some testing + m_variable_list_sp = prev_frame.m_variable_list_sp; + m_variable_list_value_objects.Swap(prev_frame.m_variable_list_value_objects); + if (!m_disassembly.GetString().empty()) + m_disassembly.GetString().swap(m_disassembly.GetString()); } - -bool -StackFrame::HasCachedData () const -{ - if (m_variable_list_sp) - return true; - if (m_variable_list_value_objects.GetSize() > 0) - return true; - if (!m_disassembly.GetString().empty()) - return true; - return false; + +void StackFrame::UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + assert(GetStackID() == + curr_frame.GetStackID()); // TODO: remove this after some testing + m_id.SetPC(curr_frame.m_id.GetPC()); // Update the Stack ID PC value + assert(GetThread() == curr_frame.GetThread()); + m_frame_index = curr_frame.m_frame_index; + m_concrete_frame_index = curr_frame.m_concrete_frame_index; + m_reg_context_sp = curr_frame.m_reg_context_sp; + m_frame_code_addr = curr_frame.m_frame_code_addr; + assert(!m_sc.target_sp || !curr_frame.m_sc.target_sp || + m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get()); + assert(!m_sc.module_sp || !curr_frame.m_sc.module_sp || + m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get()); + assert(m_sc.comp_unit == nullptr || curr_frame.m_sc.comp_unit == nullptr || + m_sc.comp_unit == curr_frame.m_sc.comp_unit); + assert(m_sc.function == nullptr || curr_frame.m_sc.function == nullptr || + m_sc.function == curr_frame.m_sc.function); + m_sc = curr_frame.m_sc; + m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything); + m_flags.Set(m_sc.GetResolvedMask()); + m_frame_base.Clear(); + m_frame_base_error.Clear(); } -bool -StackFrame::GetStatus (Stream& strm, - bool show_frame_info, - bool show_source, - const char *frame_marker) -{ - - if (show_frame_info) - { - strm.Indent(); - DumpUsingSettingsFormat (&strm, frame_marker); - } - - if (show_source) - { - ExecutionContext exe_ctx (shared_from_this()); - bool have_source = false, have_debuginfo = false; - Debugger::StopDisassemblyType disasm_display = Debugger::eStopDisassemblyTypeNever; - Target *target = exe_ctx.GetTargetPtr(); - if (target) - { - Debugger &debugger = target->GetDebugger(); - const uint32_t source_lines_before = debugger.GetStopSourceLineCount(true); - const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false); - disasm_display = debugger.GetStopDisassemblyDisplay (); - - GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry); - if (m_sc.comp_unit && m_sc.line_entry.IsValid()) - { - have_debuginfo = true; - if (source_lines_before > 0 || source_lines_after > 0) - { - size_t num_lines = target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file, - m_sc.line_entry.line, - source_lines_before, - source_lines_after, - "->", - &strm); - if (num_lines != 0) - have_source = true; - // TODO: Give here a one time warning if source file is missing. - } - } - switch (disasm_display) - { - case Debugger::eStopDisassemblyTypeNever: - break; +bool StackFrame::HasCachedData() const { + if (m_variable_list_sp) + return true; + if (m_variable_list_value_objects.GetSize() > 0) + return true; + if (!m_disassembly.GetString().empty()) + return true; + return false; +} - case Debugger::eStopDisassemblyTypeNoDebugInfo: - if (have_debuginfo) - break; - LLVM_FALLTHROUGH; +bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source, + const char *frame_marker) { - case Debugger::eStopDisassemblyTypeNoSource: - if (have_source) - break; - LLVM_FALLTHROUGH; + if (show_frame_info) { + strm.Indent(); + DumpUsingSettingsFormat(&strm, frame_marker); + } - case Debugger::eStopDisassemblyTypeAlways: - if (target) - { - const uint32_t disasm_lines = debugger.GetDisassemblyLineCount(); - if (disasm_lines > 0) - { - const ArchSpec &target_arch = target->GetArchitecture(); - AddressRange pc_range; - pc_range.GetBaseAddress() = GetFrameCodeAddress(); - pc_range.SetByteSize(disasm_lines * target_arch.GetMaximumOpcodeByteSize()); - const char *plugin_name = nullptr; - const char *flavor = nullptr; - Disassembler::Disassemble (target->GetDebugger(), - target_arch, - plugin_name, - flavor, - exe_ctx, - pc_range, - disasm_lines, - 0, - Disassembler::eOptionMarkPCAddress, - strm); - } - } - break; - } + if (show_source) { + ExecutionContext exe_ctx(shared_from_this()); + bool have_source = false, have_debuginfo = false; + Debugger::StopDisassemblyType disasm_display = + Debugger::eStopDisassemblyTypeNever; + Target *target = exe_ctx.GetTargetPtr(); + if (target) { + Debugger &debugger = target->GetDebugger(); + const uint32_t source_lines_before = + debugger.GetStopSourceLineCount(true); + const uint32_t source_lines_after = + debugger.GetStopSourceLineCount(false); + disasm_display = debugger.GetStopDisassemblyDisplay(); + + GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry); + if (m_sc.comp_unit && m_sc.line_entry.IsValid()) { + have_debuginfo = true; + if (source_lines_before > 0 || source_lines_after > 0) { + size_t num_lines = + target->GetSourceManager().DisplaySourceLinesWithLineNumbers( + m_sc.line_entry.file, m_sc.line_entry.line, + source_lines_before, source_lines_after, "->", &strm); + if (num_lines != 0) + have_source = true; + // TODO: Give here a one time warning if source file is missing. + } + } + switch (disasm_display) { + case Debugger::eStopDisassemblyTypeNever: + break; + + case Debugger::eStopDisassemblyTypeNoDebugInfo: + if (have_debuginfo) + break; + LLVM_FALLTHROUGH; + + case Debugger::eStopDisassemblyTypeNoSource: + if (have_source) + break; + LLVM_FALLTHROUGH; + + case Debugger::eStopDisassemblyTypeAlways: + if (target) { + const uint32_t disasm_lines = debugger.GetDisassemblyLineCount(); + if (disasm_lines > 0) { + const ArchSpec &target_arch = target->GetArchitecture(); + AddressRange pc_range; + pc_range.GetBaseAddress() = GetFrameCodeAddress(); + pc_range.SetByteSize(disasm_lines * + target_arch.GetMaximumOpcodeByteSize()); + const char *plugin_name = nullptr; + const char *flavor = nullptr; + Disassembler::Disassemble(target->GetDebugger(), target_arch, + plugin_name, flavor, exe_ctx, pc_range, + disasm_lines, 0, + Disassembler::eOptionMarkPCAddress, strm); + } } + break; + } } - return true; + } + return true; } diff --git a/lldb/source/Target/StackFrameList.cpp b/lldb/source/Target/StackFrameList.cpp index 8304caf5710..872e153ddb0 100644 --- a/lldb/source/Target/StackFrameList.cpp +++ b/lldb/source/Target/StackFrameList.cpp @@ -12,11 +12,11 @@ // Other libraries and framework includes // Project includes #include "lldb/Target/StackFrameList.h" -#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Log.h" -#include "lldb/Core/StreamFile.h" #include "lldb/Core/SourceManager.h" +#include "lldb/Core/StreamFile.h" #include "lldb/Symbol/Block.h" #include "lldb/Symbol/Function.h" #include "lldb/Symbol/Symbol.h" @@ -36,908 +36,818 @@ using namespace lldb_private; //---------------------------------------------------------------------- // StackFrameList constructor //---------------------------------------------------------------------- -StackFrameList::StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp, bool show_inline_frames) - : m_thread(thread), - m_prev_frames_sp(prev_frames_sp), - m_mutex(), - m_frames(), - m_selected_frame_idx(0), - m_concrete_frames_fetched(0), +StackFrameList::StackFrameList(Thread &thread, + const lldb::StackFrameListSP &prev_frames_sp, + bool show_inline_frames) + : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_mutex(), m_frames(), + m_selected_frame_idx(0), m_concrete_frames_fetched(0), m_current_inlined_depth(UINT32_MAX), m_current_inlined_pc(LLDB_INVALID_ADDRESS), - m_show_inlined_frames(show_inline_frames) -{ - if (prev_frames_sp) - { - m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth; - m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc; - } + m_show_inlined_frames(show_inline_frames) { + if (prev_frames_sp) { + m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth; + m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc; + } } -StackFrameList::~StackFrameList() -{ - // Call clear since this takes a lock and clears the stack frame list - // in case another thread is currently using this stack frame list - Clear(); +StackFrameList::~StackFrameList() { + // Call clear since this takes a lock and clears the stack frame list + // in case another thread is currently using this stack frame list + Clear(); } -void -StackFrameList::CalculateCurrentInlinedDepth() -{ - uint32_t cur_inlined_depth = GetCurrentInlinedDepth(); - if (cur_inlined_depth == UINT32_MAX) - { - ResetCurrentInlinedDepth(); - } +void StackFrameList::CalculateCurrentInlinedDepth() { + uint32_t cur_inlined_depth = GetCurrentInlinedDepth(); + if (cur_inlined_depth == UINT32_MAX) { + ResetCurrentInlinedDepth(); + } } -uint32_t -StackFrameList::GetCurrentInlinedDepth () -{ - if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS) - { - lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); - if (cur_pc != m_current_inlined_pc) - { - m_current_inlined_pc = LLDB_INVALID_ADDRESS; - m_current_inlined_depth = UINT32_MAX; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("GetCurrentInlinedDepth: invalidating current inlined depth.\n"); - } - return m_current_inlined_depth; - } - else - { - return UINT32_MAX; +uint32_t StackFrameList::GetCurrentInlinedDepth() { + if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS) { + lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); + if (cur_pc != m_current_inlined_pc) { + m_current_inlined_pc = LLDB_INVALID_ADDRESS; + m_current_inlined_depth = UINT32_MAX; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf( + "GetCurrentInlinedDepth: invalidating current inlined depth.\n"); } + return m_current_inlined_depth; + } else { + return UINT32_MAX; + } } -void -StackFrameList::ResetCurrentInlinedDepth () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - if (m_show_inlined_frames) - { - GetFramesUpTo(0); - if (m_frames.empty()) - return; - if (!m_frames[0]->IsInlined()) - { - m_current_inlined_depth = UINT32_MAX; - m_current_inlined_pc = LLDB_INVALID_ADDRESS; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("ResetCurrentInlinedDepth: Invalidating current inlined depth.\n"); - } - else - { - // We only need to do something special about inlined blocks when we - // are at the beginning of an inlined function: - // FIXME: We probably also have to do something special if the PC is at the END - // of an inlined function, which coincides with the end of either its containing - // function or another inlined function. - - lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); - Block *block_ptr = m_frames[0]->GetFrameBlock(); - if (block_ptr) - { - Address pc_as_address; - pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget())); - AddressRange containing_range; - if (block_ptr->GetRangeContainingAddress(pc_as_address, containing_range)) - { - if (pc_as_address == containing_range.GetBaseAddress()) - { - // If we got here because of a breakpoint hit, then set the inlined depth depending on where - // the breakpoint was set. - // If we got here because of a crash, then set the inlined depth to the deepest most block. - // Otherwise, we stopped here naturally as the result of a step, so set ourselves in the - // containing frame of the whole set of nested inlines, so the user can then "virtually" - // step into the frames one by one, or next over the whole mess. - // Note: We don't have to handle being somewhere in the middle of the stack here, since - // ResetCurrentInlinedDepth doesn't get called if there is a valid inlined depth set. - StopInfoSP stop_info_sp = m_thread.GetStopInfo(); - if (stop_info_sp) - { - switch (stop_info_sp->GetStopReason()) - { - case eStopReasonWatchpoint: - case eStopReasonException: - case eStopReasonExec: - case eStopReasonSignal: - // In all these cases we want to stop in the deepest most frame. - m_current_inlined_pc = curr_pc; - m_current_inlined_depth = 0; - break; - case eStopReasonBreakpoint: - { - // FIXME: Figure out what this break point is doing, and set the inline depth - // appropriately. Be careful to take into account breakpoints that implement - // step over prologue, since that should do the default calculation. - // For now, if the breakpoints corresponding to this hit are all internal, - // I set the stop location to the top of the inlined stack, since that will make - // things like stepping over prologues work right. But if there are any non-internal - // breakpoints I do to the bottom of the stack, since that was the old behavior. - uint32_t bp_site_id = stop_info_sp->GetValue(); - BreakpointSiteSP bp_site_sp(m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id)); - bool all_internal = true; - if (bp_site_sp) - { - uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); - for (uint32_t i = 0; i < num_owners; i++) - { - Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); - if (!bp_ref.IsInternal()) - { - all_internal = false; - } - } - } - if (!all_internal) - { - m_current_inlined_pc = curr_pc; - m_current_inlined_depth = 0; - break; - } - } - LLVM_FALLTHROUGH; - default: - { - // Otherwise, we should set ourselves at the container of the inlining, so that the - // user can descend into them. - // So first we check whether we have more than one inlined block sharing this PC: - int num_inlined_functions = 0; - - for (Block *container_ptr = block_ptr->GetInlinedParent(); - container_ptr != nullptr; - container_ptr = container_ptr->GetInlinedParent()) - { - if (!container_ptr->GetRangeContainingAddress(pc_as_address, containing_range)) - break; - if (pc_as_address != containing_range.GetBaseAddress()) - break; - - num_inlined_functions++; - } - m_current_inlined_pc = curr_pc; - m_current_inlined_depth = num_inlined_functions + 1; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("ResetCurrentInlinedDepth: setting inlined depth: %d 0x%" PRIx64 ".\n", m_current_inlined_depth, curr_pc); - - } - break; - } - } +void StackFrameList::ResetCurrentInlinedDepth() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + if (m_show_inlined_frames) { + GetFramesUpTo(0); + if (m_frames.empty()) + return; + if (!m_frames[0]->IsInlined()) { + m_current_inlined_depth = UINT32_MAX; + m_current_inlined_pc = LLDB_INVALID_ADDRESS; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf( + "ResetCurrentInlinedDepth: Invalidating current inlined depth.\n"); + } else { + // We only need to do something special about inlined blocks when we + // are at the beginning of an inlined function: + // FIXME: We probably also have to do something special if the PC is at + // the END + // of an inlined function, which coincides with the end of either its + // containing + // function or another inlined function. + + lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); + Block *block_ptr = m_frames[0]->GetFrameBlock(); + if (block_ptr) { + Address pc_as_address; + pc_as_address.SetLoadAddress(curr_pc, + &(m_thread.GetProcess()->GetTarget())); + AddressRange containing_range; + if (block_ptr->GetRangeContainingAddress(pc_as_address, + containing_range)) { + if (pc_as_address == containing_range.GetBaseAddress()) { + // If we got here because of a breakpoint hit, then set the inlined + // depth depending on where + // the breakpoint was set. + // If we got here because of a crash, then set the inlined depth to + // the deepest most block. + // Otherwise, we stopped here naturally as the result of a step, so + // set ourselves in the + // containing frame of the whole set of nested inlines, so the user + // can then "virtually" + // step into the frames one by one, or next over the whole mess. + // Note: We don't have to handle being somewhere in the middle of + // the stack here, since + // ResetCurrentInlinedDepth doesn't get called if there is a valid + // inlined depth set. + StopInfoSP stop_info_sp = m_thread.GetStopInfo(); + if (stop_info_sp) { + switch (stop_info_sp->GetStopReason()) { + case eStopReasonWatchpoint: + case eStopReasonException: + case eStopReasonExec: + case eStopReasonSignal: + // In all these cases we want to stop in the deepest most frame. + m_current_inlined_pc = curr_pc; + m_current_inlined_depth = 0; + break; + case eStopReasonBreakpoint: { + // FIXME: Figure out what this break point is doing, and set the + // inline depth + // appropriately. Be careful to take into account breakpoints + // that implement + // step over prologue, since that should do the default + // calculation. + // For now, if the breakpoints corresponding to this hit are all + // internal, + // I set the stop location to the top of the inlined stack, + // since that will make + // things like stepping over prologues work right. But if there + // are any non-internal + // breakpoints I do to the bottom of the stack, since that was + // the old behavior. + uint32_t bp_site_id = stop_info_sp->GetValue(); + BreakpointSiteSP bp_site_sp( + m_thread.GetProcess()->GetBreakpointSiteList().FindByID( + bp_site_id)); + bool all_internal = true; + if (bp_site_sp) { + uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); + for (uint32_t i = 0; i < num_owners; i++) { + Breakpoint &bp_ref = + bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); + if (!bp_ref.IsInternal()) { + all_internal = false; } + } + } + if (!all_internal) { + m_current_inlined_pc = curr_pc; + m_current_inlined_depth = 0; + break; + } + } + LLVM_FALLTHROUGH; + default: { + // Otherwise, we should set ourselves at the container of the + // inlining, so that the + // user can descend into them. + // So first we check whether we have more than one inlined block + // sharing this PC: + int num_inlined_functions = 0; + + for (Block *container_ptr = block_ptr->GetInlinedParent(); + container_ptr != nullptr; + container_ptr = container_ptr->GetInlinedParent()) { + if (!container_ptr->GetRangeContainingAddress( + pc_as_address, containing_range)) + break; + if (pc_as_address != containing_range.GetBaseAddress()) + break; + + num_inlined_functions++; } + m_current_inlined_pc = curr_pc; + m_current_inlined_depth = num_inlined_functions + 1; + Log *log( + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf("ResetCurrentInlinedDepth: setting inlined " + "depth: %d 0x%" PRIx64 ".\n", + m_current_inlined_depth, curr_pc); + + } break; + } } + } } + } } + } } -bool -StackFrameList::DecrementCurrentInlinedDepth () -{ - if (m_show_inlined_frames) - { - uint32_t current_inlined_depth = GetCurrentInlinedDepth(); - if (current_inlined_depth != UINT32_MAX) - { - if (current_inlined_depth > 0) - { - m_current_inlined_depth--; - return true; - } - } +bool StackFrameList::DecrementCurrentInlinedDepth() { + if (m_show_inlined_frames) { + uint32_t current_inlined_depth = GetCurrentInlinedDepth(); + if (current_inlined_depth != UINT32_MAX) { + if (current_inlined_depth > 0) { + m_current_inlined_depth--; + return true; + } } - return false; + } + return false; } -void -StackFrameList::SetCurrentInlinedDepth (uint32_t new_depth) -{ - m_current_inlined_depth = new_depth; - if (new_depth == UINT32_MAX) - m_current_inlined_pc = LLDB_INVALID_ADDRESS; - else - m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC(); +void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) { + m_current_inlined_depth = new_depth; + if (new_depth == UINT32_MAX) + m_current_inlined_pc = LLDB_INVALID_ADDRESS; + else + m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC(); } -void -StackFrameList::GetFramesUpTo(uint32_t end_idx) -{ - // this makes sure we do not fetch frames for an invalid thread - if (!m_thread.IsValid()) - return; - - // We've already gotten more frames than asked for, or we've already finished unwinding, return. - if (m_frames.size() > end_idx || GetAllFramesFetched()) - return; - - Unwind *unwinder = m_thread.GetUnwinder (); - - if (m_show_inlined_frames) - { -#if defined (DEBUG_STACK_FRAMES) - StreamFile s(stdout, false); +void StackFrameList::GetFramesUpTo(uint32_t end_idx) { + // this makes sure we do not fetch frames for an invalid thread + if (!m_thread.IsValid()) + return; + + // We've already gotten more frames than asked for, or we've already finished + // unwinding, return. + if (m_frames.size() > end_idx || GetAllFramesFetched()) + return; + + Unwind *unwinder = m_thread.GetUnwinder(); + + if (m_show_inlined_frames) { +#if defined(DEBUG_STACK_FRAMES) + StreamFile s(stdout, false); #endif - // If we are hiding some frames from the outside world, we need to add those onto the total count of - // frames to fetch. However, we don't need to do that if end_idx is 0 since in that case we always - // get the first concrete frame and all the inlined frames below it... And of course, if end_idx is - // UINT32_MAX that means get all, so just do that... - - uint32_t inlined_depth = 0; - if (end_idx > 0 && end_idx != UINT32_MAX) - { - inlined_depth = GetCurrentInlinedDepth(); - if (inlined_depth != UINT32_MAX) - { - if (end_idx > 0) - end_idx += inlined_depth; + // If we are hiding some frames from the outside world, we need to add those + // onto the total count of + // frames to fetch. However, we don't need to do that if end_idx is 0 since + // in that case we always + // get the first concrete frame and all the inlined frames below it... And + // of course, if end_idx is + // UINT32_MAX that means get all, so just do that... + + uint32_t inlined_depth = 0; + if (end_idx > 0 && end_idx != UINT32_MAX) { + inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth != UINT32_MAX) { + if (end_idx > 0) + end_idx += inlined_depth; + } + } + + StackFrameSP unwind_frame_sp; + do { + uint32_t idx = m_concrete_frames_fetched++; + lldb::addr_t pc = LLDB_INVALID_ADDRESS; + lldb::addr_t cfa = LLDB_INVALID_ADDRESS; + if (idx == 0) { + // We might have already created frame zero, only create it + // if we need to + if (m_frames.empty()) { + RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext()); + + if (reg_ctx_sp) { + const bool success = + unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); + // There shouldn't be any way not to get the frame info for frame 0. + // But if the unwinder can't make one, lets make one by hand with + // the + // SP as the CFA and see if that gets any further. + if (!success) { + cfa = reg_ctx_sp->GetSP(); + pc = reg_ctx_sp->GetPC(); } + + unwind_frame_sp.reset(new StackFrame(m_thread.shared_from_this(), + m_frames.size(), idx, + reg_ctx_sp, cfa, pc, nullptr)); + m_frames.push_back(unwind_frame_sp); + } + } else { + unwind_frame_sp = m_frames.front(); + cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); } - - StackFrameSP unwind_frame_sp; - do - { - uint32_t idx = m_concrete_frames_fetched++; - lldb::addr_t pc = LLDB_INVALID_ADDRESS; - lldb::addr_t cfa = LLDB_INVALID_ADDRESS; - if (idx == 0) - { - // We might have already created frame zero, only create it - // if we need to - if (m_frames.empty()) - { - RegisterContextSP reg_ctx_sp (m_thread.GetRegisterContext()); - - if (reg_ctx_sp) - { - const bool success = unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); - // There shouldn't be any way not to get the frame info for frame 0. - // But if the unwinder can't make one, lets make one by hand with the - // SP as the CFA and see if that gets any further. - if (!success) - { - cfa = reg_ctx_sp->GetSP(); - pc = reg_ctx_sp->GetPC(); - } - - unwind_frame_sp.reset(new StackFrame(m_thread.shared_from_this(), - m_frames.size(), - idx, - reg_ctx_sp, - cfa, - pc, - nullptr)); - m_frames.push_back (unwind_frame_sp); - } - } - else - { - unwind_frame_sp = m_frames.front(); - cfa = unwind_frame_sp->m_id.GetCallFrameAddress(); - } - } - else - { - const bool success = unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); - if (!success) - { - // We've gotten to the end of the stack. - SetAllFramesFetched(); - break; - } - const bool cfa_is_valid = true; - const bool stop_id_is_valid = false; - const bool is_history_frame = false; - unwind_frame_sp.reset(new StackFrame(m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid, pc, - 0, stop_id_is_valid, is_history_frame, nullptr)); - m_frames.push_back (unwind_frame_sp); - } - - assert(unwind_frame_sp); - SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction); - Block *unwind_block = unwind_sc.block; - if (unwind_block) - { - Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress()); - TargetSP target_sp = m_thread.CalculateTarget(); - // Be sure to adjust the frame address to match the address - // that was used to lookup the symbol context above. If we are - // in the first concrete frame, then we lookup using the current - // address, else we decrement the address by one to get the correct - // location. - if (idx > 0) - { - if (curr_frame_address.GetOffset() == 0) - { - // If curr_frame_address points to the first address in a section then after - // adjustment it will point to an other section. In that case resolve the - // address again to the correct section plus offset form. - addr_t load_addr = curr_frame_address.GetOpcodeLoadAddress(target_sp.get(), eAddressClassCode); - curr_frame_address.SetOpcodeLoadAddress(load_addr - 1, target_sp.get(), eAddressClassCode); - } - else - { - curr_frame_address.Slide(-1); - } - } - - SymbolContext next_frame_sc; - Address next_frame_address; - - while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address)) - { - next_frame_sc.line_entry.ApplyFileMappings(target_sp);
- StackFrameSP frame_sp(new StackFrame(m_thread.shared_from_this(), - m_frames.size(), - idx, - unwind_frame_sp->GetRegisterContextSP (), - cfa, - next_frame_address, - &next_frame_sc)); - - m_frames.push_back (frame_sp); - unwind_sc = next_frame_sc; - curr_frame_address = next_frame_address; - } - } - } while (m_frames.size() - 1 < end_idx); - - // Don't try to merge till you've calculated all the frames in this stack. - if (GetAllFramesFetched() && m_prev_frames_sp) - { - StackFrameList *prev_frames = m_prev_frames_sp.get(); - StackFrameList *curr_frames = this; - - //curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth; - //curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc; - //printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n", curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc); - -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("\nprev_frames:\n"); - prev_frames->Dump (&s); - s.PutCString("\ncurr_frames:\n"); - curr_frames->Dump (&s); - s.EOL(); + } else { + const bool success = + unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc); + if (!success) { + // We've gotten to the end of the stack. + SetAllFramesFetched(); + break; + } + const bool cfa_is_valid = true; + const bool stop_id_is_valid = false; + const bool is_history_frame = false; + unwind_frame_sp.reset(new StackFrame( + m_thread.shared_from_this(), m_frames.size(), idx, cfa, + cfa_is_valid, pc, 0, stop_id_is_valid, is_history_frame, nullptr)); + m_frames.push_back(unwind_frame_sp); + } + + assert(unwind_frame_sp); + SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext( + eSymbolContextBlock | eSymbolContextFunction); + Block *unwind_block = unwind_sc.block; + if (unwind_block) { + Address curr_frame_address(unwind_frame_sp->GetFrameCodeAddress()); + TargetSP target_sp = m_thread.CalculateTarget(); + // Be sure to adjust the frame address to match the address + // that was used to lookup the symbol context above. If we are + // in the first concrete frame, then we lookup using the current + // address, else we decrement the address by one to get the correct + // location. + if (idx > 0) { + if (curr_frame_address.GetOffset() == 0) { + // If curr_frame_address points to the first address in a section + // then after + // adjustment it will point to an other section. In that case + // resolve the + // address again to the correct section plus offset form. + addr_t load_addr = curr_frame_address.GetOpcodeLoadAddress( + target_sp.get(), eAddressClassCode); + curr_frame_address.SetOpcodeLoadAddress( + load_addr - 1, target_sp.get(), eAddressClassCode); + } else { + curr_frame_address.Slide(-1); + } + } + + SymbolContext next_frame_sc; + Address next_frame_address; + + while (unwind_sc.GetParentOfInlinedScope( + curr_frame_address, next_frame_sc, next_frame_address)) { + next_frame_sc.line_entry.ApplyFileMappings(target_sp); + StackFrameSP frame_sp( + new StackFrame(m_thread.shared_from_this(), m_frames.size(), idx, + unwind_frame_sp->GetRegisterContextSP(), cfa, + next_frame_address, &next_frame_sc)); + + m_frames.push_back(frame_sp); + unwind_sc = next_frame_sc; + curr_frame_address = next_frame_address; + } + } + } while (m_frames.size() - 1 < end_idx); + + // Don't try to merge till you've calculated all the frames in this stack. + if (GetAllFramesFetched() && m_prev_frames_sp) { + StackFrameList *prev_frames = m_prev_frames_sp.get(); + StackFrameList *curr_frames = this; + +// curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth; +// curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc; +// printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n", +// curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc); + +#if defined(DEBUG_STACK_FRAMES) + s.PutCString("\nprev_frames:\n"); + prev_frames->Dump(&s); + s.PutCString("\ncurr_frames:\n"); + curr_frames->Dump(&s); + s.EOL(); #endif - size_t curr_frame_num, prev_frame_num; - - for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size(); - curr_frame_num > 0 && prev_frame_num > 0; - --curr_frame_num, --prev_frame_num) - { - const size_t curr_frame_idx = curr_frame_num-1; - const size_t prev_frame_idx = prev_frame_num-1; - StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]); - StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]); - -#if defined (DEBUG_STACK_FRAMES) - s.Printf("\n\nCurr frame #%u ", curr_frame_idx); - if (curr_frame_sp) - curr_frame_sp->Dump (&s, true, false); - else - s.PutCString("NULL"); - s.Printf("\nPrev frame #%u ", prev_frame_idx); - if (prev_frame_sp) - prev_frame_sp->Dump (&s, true, false); - else - s.PutCString("NULL"); + size_t curr_frame_num, prev_frame_num; + + for (curr_frame_num = curr_frames->m_frames.size(), + prev_frame_num = prev_frames->m_frames.size(); + curr_frame_num > 0 && prev_frame_num > 0; + --curr_frame_num, --prev_frame_num) { + const size_t curr_frame_idx = curr_frame_num - 1; + const size_t prev_frame_idx = prev_frame_num - 1; + StackFrameSP curr_frame_sp(curr_frames->m_frames[curr_frame_idx]); + StackFrameSP prev_frame_sp(prev_frames->m_frames[prev_frame_idx]); + +#if defined(DEBUG_STACK_FRAMES) + s.Printf("\n\nCurr frame #%u ", curr_frame_idx); + if (curr_frame_sp) + curr_frame_sp->Dump(&s, true, false); + else + s.PutCString("NULL"); + s.Printf("\nPrev frame #%u ", prev_frame_idx); + if (prev_frame_sp) + prev_frame_sp->Dump(&s, true, false); + else + s.PutCString("NULL"); #endif - StackFrame *curr_frame = curr_frame_sp.get(); - StackFrame *prev_frame = prev_frame_sp.get(); - - if (curr_frame == nullptr || prev_frame == nullptr) - break; + StackFrame *curr_frame = curr_frame_sp.get(); + StackFrame *prev_frame = prev_frame_sp.get(); - // Check the stack ID to make sure they are equal - if (curr_frame->GetStackID() != prev_frame->GetStackID()) - break; + if (curr_frame == nullptr || prev_frame == nullptr) + break; - prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame); - // Now copy the fixed up previous frame into the current frames - // so the pointer doesn't change - m_frames[curr_frame_idx] = prev_frame_sp; - //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame); - -#if defined (DEBUG_STACK_FRAMES) - s.Printf("\n Copying previous frame to current frame"); -#endif - } - // We are done with the old stack frame list, we can release it now - m_prev_frames_sp.reset(); - } - -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("\n\nNew frames:\n"); - Dump (&s); - s.EOL(); + // Check the stack ID to make sure they are equal + if (curr_frame->GetStackID() != prev_frame->GetStackID()) + break; + + prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame); + // Now copy the fixed up previous frame into the current frames + // so the pointer doesn't change + m_frames[curr_frame_idx] = prev_frame_sp; +// curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame); + +#if defined(DEBUG_STACK_FRAMES) + s.Printf("\n Copying previous frame to current frame"); #endif + } + // We are done with the old stack frame list, we can release it now + m_prev_frames_sp.reset(); } - else - { - if (end_idx < m_concrete_frames_fetched) - return; - - if (unwinder) - { - uint32_t num_frames = unwinder->GetFramesUpTo(end_idx); - if (num_frames <= end_idx + 1) - { - //Done unwinding. - m_concrete_frames_fetched = UINT32_MAX; - } - m_frames.resize(num_frames); - } + +#if defined(DEBUG_STACK_FRAMES) + s.PutCString("\n\nNew frames:\n"); + Dump(&s); + s.EOL(); +#endif + } else { + if (end_idx < m_concrete_frames_fetched) + return; + + if (unwinder) { + uint32_t num_frames = unwinder->GetFramesUpTo(end_idx); + if (num_frames <= end_idx + 1) { + // Done unwinding. + m_concrete_frames_fetched = UINT32_MAX; + } + m_frames.resize(num_frames); } + } } -uint32_t -StackFrameList::GetNumFrames (bool can_create) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); +uint32_t StackFrameList::GetNumFrames(bool can_create) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (can_create) - GetFramesUpTo (UINT32_MAX); + if (can_create) + GetFramesUpTo(UINT32_MAX); - uint32_t inlined_depth = GetCurrentInlinedDepth(); - if (inlined_depth == UINT32_MAX) - return m_frames.size(); - else - return m_frames.size() - inlined_depth; + uint32_t inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth == UINT32_MAX) + return m_frames.size(); + else + return m_frames.size() - inlined_depth; } -void -StackFrameList::Dump (Stream *s) -{ - if (s == nullptr) - return; - - std::lock_guard<std::recursive_mutex> guard(m_mutex); - - const_iterator pos, begin = m_frames.begin(), end = m_frames.end(); - for (pos = begin; pos != end; ++pos) - { - StackFrame *frame = (*pos).get(); - s->Printf("%p: ", static_cast<void*>(frame)); - if (frame) - { - frame->GetStackID().Dump (s); - frame->DumpUsingSettingsFormat (s); - } - else - s->Printf("frame #%u", (uint32_t)std::distance (begin, pos)); - s->EOL(); - } +void StackFrameList::Dump(Stream *s) { + if (s == nullptr) + return; + + std::lock_guard<std::recursive_mutex> guard(m_mutex); + + const_iterator pos, begin = m_frames.begin(), end = m_frames.end(); + for (pos = begin; pos != end; ++pos) { + StackFrame *frame = (*pos).get(); + s->Printf("%p: ", static_cast<void *>(frame)); + if (frame) { + frame->GetStackID().Dump(s); + frame->DumpUsingSettingsFormat(s); + } else + s->Printf("frame #%u", (uint32_t)std::distance(begin, pos)); s->EOL(); + } + s->EOL(); } -StackFrameSP -StackFrameList::GetFrameAtIndex (uint32_t idx) -{ - StackFrameSP frame_sp; - std::lock_guard<std::recursive_mutex> guard(m_mutex); - uint32_t original_idx = idx; - - uint32_t inlined_depth = GetCurrentInlinedDepth(); - if (inlined_depth != UINT32_MAX) - idx += inlined_depth; - - if (idx < m_frames.size()) - frame_sp = m_frames[idx]; - - if (frame_sp) - return frame_sp; - - // GetFramesUpTo will fill m_frames with as many frames as you asked for, - // if there are that many. If there weren't then you asked for too many - // frames. - GetFramesUpTo (idx); - if (idx < m_frames.size()) - { - if (m_show_inlined_frames) - { - // When inline frames are enabled we actually create all the frames in GetFramesUpTo. - frame_sp = m_frames[idx]; - } - else - { - Unwind *unwinder = m_thread.GetUnwinder (); - if (unwinder) - { - addr_t pc, cfa; - if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) - { - const bool cfa_is_valid = true; - const bool stop_id_is_valid = false; - const bool is_history_frame = false; - frame_sp.reset(new StackFrame(m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 0, - stop_id_is_valid, is_history_frame, nullptr)); - - Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function; - if (function) - { - // When we aren't showing inline functions we always use - // the top most function block as the scope. - frame_sp->SetSymbolContextScope (&function->GetBlock(false)); - } - else - { - // Set the symbol scope from the symbol regardless if it is nullptr or valid. - frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol); - } - SetFrameAtIndex(idx, frame_sp); - } - } +StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) { + StackFrameSP frame_sp; + std::lock_guard<std::recursive_mutex> guard(m_mutex); + uint32_t original_idx = idx; + + uint32_t inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth != UINT32_MAX) + idx += inlined_depth; + + if (idx < m_frames.size()) + frame_sp = m_frames[idx]; + + if (frame_sp) + return frame_sp; + + // GetFramesUpTo will fill m_frames with as many frames as you asked for, + // if there are that many. If there weren't then you asked for too many + // frames. + GetFramesUpTo(idx); + if (idx < m_frames.size()) { + if (m_show_inlined_frames) { + // When inline frames are enabled we actually create all the frames in + // GetFramesUpTo. + frame_sp = m_frames[idx]; + } else { + Unwind *unwinder = m_thread.GetUnwinder(); + if (unwinder) { + addr_t pc, cfa; + if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) { + const bool cfa_is_valid = true; + const bool stop_id_is_valid = false; + const bool is_history_frame = false; + frame_sp.reset(new StackFrame( + m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 0, + stop_id_is_valid, is_history_frame, nullptr)); + + Function *function = + frame_sp->GetSymbolContext(eSymbolContextFunction).function; + if (function) { + // When we aren't showing inline functions we always use + // the top most function block as the scope. + frame_sp->SetSymbolContextScope(&function->GetBlock(false)); + } else { + // Set the symbol scope from the symbol regardless if it is nullptr + // or valid. + frame_sp->SetSymbolContextScope( + frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol); + } + SetFrameAtIndex(idx, frame_sp); } + } } - else if (original_idx == 0) - { - // There should ALWAYS be a frame at index 0. If something went wrong with the CurrentInlinedDepth such that - // there weren't as many frames as we thought taking that into account, then reset the current inlined depth - // and return the real zeroth frame. - if (m_frames.empty()) - { - // Why do we have a thread with zero frames, that should not ever happen... - if (m_thread.IsValid()) - assert ("A valid thread has no frames."); - } - else - { - ResetCurrentInlinedDepth(); - frame_sp = m_frames[original_idx]; - } + } else if (original_idx == 0) { + // There should ALWAYS be a frame at index 0. If something went wrong with + // the CurrentInlinedDepth such that + // there weren't as many frames as we thought taking that into account, then + // reset the current inlined depth + // and return the real zeroth frame. + if (m_frames.empty()) { + // Why do we have a thread with zero frames, that should not ever + // happen... + if (m_thread.IsValid()) + assert("A valid thread has no frames."); + } else { + ResetCurrentInlinedDepth(); + frame_sp = m_frames[original_idx]; } - - return frame_sp; + } + + return frame_sp; } StackFrameSP -StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx) -{ - // First try assuming the unwind index is the same as the frame index. The - // unwind index is always greater than or equal to the frame index, so it - // is a good place to start. If we have inlined frames we might have 5 - // concrete frames (frame unwind indexes go from 0-4), but we might have 15 - // frames after we make all the inlined frames. Most of the time the unwind - // frame index (or the concrete frame index) is the same as the frame index. - uint32_t frame_idx = unwind_idx; - StackFrameSP frame_sp (GetFrameAtIndex (frame_idx)); - while (frame_sp) - { - if (frame_sp->GetFrameIndex() == unwind_idx) - break; - frame_sp = GetFrameAtIndex (++frame_idx); - } - return frame_sp; +StackFrameList::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) { + // First try assuming the unwind index is the same as the frame index. The + // unwind index is always greater than or equal to the frame index, so it + // is a good place to start. If we have inlined frames we might have 5 + // concrete frames (frame unwind indexes go from 0-4), but we might have 15 + // frames after we make all the inlined frames. Most of the time the unwind + // frame index (or the concrete frame index) is the same as the frame index. + uint32_t frame_idx = unwind_idx; + StackFrameSP frame_sp(GetFrameAtIndex(frame_idx)); + while (frame_sp) { + if (frame_sp->GetFrameIndex() == unwind_idx) + break; + frame_sp = GetFrameAtIndex(++frame_idx); + } + return frame_sp; } -static bool -CompareStackID (const StackFrameSP &stack_sp, const StackID &stack_id) -{ - return stack_sp->GetStackID() < stack_id; +static bool CompareStackID(const StackFrameSP &stack_sp, + const StackID &stack_id) { + return stack_sp->GetStackID() < stack_id; } -StackFrameSP -StackFrameList::GetFrameWithStackID (const StackID &stack_id) -{ - StackFrameSP frame_sp; - - if (stack_id.IsValid()) - { - std::lock_guard<std::recursive_mutex> guard(m_mutex); - uint32_t frame_idx = 0; - // Do a binary search in case the stack frame is already in our cache - collection::const_iterator begin = m_frames.begin(); - collection::const_iterator end = m_frames.end(); - if (begin != end) - { - collection::const_iterator pos = std::lower_bound (begin, end, stack_id, CompareStackID); - if (pos != end) - { - if ((*pos)->GetStackID() == stack_id) - return *pos; - } - -// if (m_frames.back()->GetStackID() < stack_id) -// frame_idx = m_frames.size(); - } - do - { - frame_sp = GetFrameAtIndex (frame_idx); - if (frame_sp && frame_sp->GetStackID() == stack_id) - break; - frame_idx++; - } - while (frame_sp); +StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) { + StackFrameSP frame_sp; + + if (stack_id.IsValid()) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + uint32_t frame_idx = 0; + // Do a binary search in case the stack frame is already in our cache + collection::const_iterator begin = m_frames.begin(); + collection::const_iterator end = m_frames.end(); + if (begin != end) { + collection::const_iterator pos = + std::lower_bound(begin, end, stack_id, CompareStackID); + if (pos != end) { + if ((*pos)->GetStackID() == stack_id) + return *pos; + } + + // if (m_frames.back()->GetStackID() < stack_id) + // frame_idx = m_frames.size(); } - return frame_sp; + do { + frame_sp = GetFrameAtIndex(frame_idx); + if (frame_sp && frame_sp->GetStackID() == stack_id) + break; + frame_idx++; + } while (frame_sp); + } + return frame_sp; } -bool -StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp) -{ - if (idx >= m_frames.size()) - m_frames.resize(idx + 1); - // Make sure allocation succeeded by checking bounds again - if (idx < m_frames.size()) - { - m_frames[idx] = frame_sp; - return true; - } - return false; // resize failed, out of memory? +bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) { + if (idx >= m_frames.size()) + m_frames.resize(idx + 1); + // Make sure allocation succeeded by checking bounds again + if (idx < m_frames.size()) { + m_frames[idx] = frame_sp; + return true; + } + return false; // resize failed, out of memory? } -uint32_t -StackFrameList::GetSelectedFrameIndex () const -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - return m_selected_frame_idx; +uint32_t StackFrameList::GetSelectedFrameIndex() const { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + return m_selected_frame_idx; } -uint32_t -StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - const_iterator pos; - const_iterator begin = m_frames.begin(); - const_iterator end = m_frames.end(); - m_selected_frame_idx = 0; - for (pos = begin; pos != end; ++pos) - { - if (pos->get() == frame) - { - m_selected_frame_idx = std::distance (begin, pos); - uint32_t inlined_depth = GetCurrentInlinedDepth(); - if (inlined_depth != UINT32_MAX) - m_selected_frame_idx -= inlined_depth; - break; - } +uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + const_iterator pos; + const_iterator begin = m_frames.begin(); + const_iterator end = m_frames.end(); + m_selected_frame_idx = 0; + for (pos = begin; pos != end; ++pos) { + if (pos->get() == frame) { + m_selected_frame_idx = std::distance(begin, pos); + uint32_t inlined_depth = GetCurrentInlinedDepth(); + if (inlined_depth != UINT32_MAX) + m_selected_frame_idx -= inlined_depth; + break; } - SetDefaultFileAndLineToSelectedFrame(); - return m_selected_frame_idx; + } + SetDefaultFileAndLineToSelectedFrame(); + return m_selected_frame_idx; } // Mark a stack frame as the current frame using the frame index -bool -StackFrameList::SetSelectedFrameByIndex (uint32_t idx) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - StackFrameSP frame_sp (GetFrameAtIndex (idx)); - if (frame_sp) - { - SetSelectedFrame(frame_sp.get()); - return true; - } - else - return false; +bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + StackFrameSP frame_sp(GetFrameAtIndex(idx)); + if (frame_sp) { + SetSelectedFrame(frame_sp.get()); + return true; + } else + return false; } -void -StackFrameList::SetDefaultFileAndLineToSelectedFrame() -{ - if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) - { - StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex())); - if (frame_sp) - { - SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); - if (sc.line_entry.file) - m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file, - sc.line_entry.line); - } +void StackFrameList::SetDefaultFileAndLineToSelectedFrame() { + if (m_thread.GetID() == + m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) { + StackFrameSP frame_sp(GetFrameAtIndex(GetSelectedFrameIndex())); + if (frame_sp) { + SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry); + if (sc.line_entry.file) + m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine( + sc.line_entry.file, sc.line_entry.line); } + } } // The thread has been run, reset the number stack frames to zero so we can // determine how many frames we have lazily. -void -StackFrameList::Clear () -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_frames.clear(); - m_concrete_frames_fetched = 0; +void StackFrameList::Clear() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_frames.clear(); + m_concrete_frames_fetched = 0; } -void -StackFrameList::InvalidateFrames (uint32_t start_idx) -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - if (m_show_inlined_frames) - { - Clear(); - } - else - { - const size_t num_frames = m_frames.size(); - while (start_idx < num_frames) - { - m_frames[start_idx].reset(); - ++start_idx; - } +void StackFrameList::InvalidateFrames(uint32_t start_idx) { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + if (m_show_inlined_frames) { + Clear(); + } else { + const size_t num_frames = m_frames.size(); + while (start_idx < num_frames) { + m_frames[start_idx].reset(); + ++start_idx; } + } } -void -StackFrameList::Merge (std::unique_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp) -{ - std::unique_lock<std::recursive_mutex> current_lock, previous_lock; - if (curr_ap) - current_lock = std::unique_lock<std::recursive_mutex>(curr_ap->m_mutex); - if (prev_sp) - previous_lock = std::unique_lock<std::recursive_mutex>(prev_sp->m_mutex); - -#if defined (DEBUG_STACK_FRAMES) - StreamFile s(stdout, false); - s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n"); - if (prev_sp) - prev_sp->Dump (&s); - else - s.PutCString ("NULL"); - s.PutCString("\nCurr:\n"); - if (curr_ap) - curr_ap->Dump (&s); - else - s.PutCString ("NULL"); - s.EOL(); +void StackFrameList::Merge(std::unique_ptr<StackFrameList> &curr_ap, + lldb::StackFrameListSP &prev_sp) { + std::unique_lock<std::recursive_mutex> current_lock, previous_lock; + if (curr_ap) + current_lock = std::unique_lock<std::recursive_mutex>(curr_ap->m_mutex); + if (prev_sp) + previous_lock = std::unique_lock<std::recursive_mutex>(prev_sp->m_mutex); + +#if defined(DEBUG_STACK_FRAMES) + StreamFile s(stdout, false); + s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n"); + if (prev_sp) + prev_sp->Dump(&s); + else + s.PutCString("NULL"); + s.PutCString("\nCurr:\n"); + if (curr_ap) + curr_ap->Dump(&s); + else + s.PutCString("NULL"); + s.EOL(); #endif - if (!curr_ap || curr_ap->GetNumFrames(false) == 0) - { -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("No current frames, leave previous frames alone...\n"); + if (!curr_ap || curr_ap->GetNumFrames(false) == 0) { +#if defined(DEBUG_STACK_FRAMES) + s.PutCString("No current frames, leave previous frames alone...\n"); #endif - curr_ap.release(); - return; - } + curr_ap.release(); + return; + } - if (!prev_sp || prev_sp->GetNumFrames(false) == 0) - { -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("No previous frames, so use current frames...\n"); + if (!prev_sp || prev_sp->GetNumFrames(false) == 0) { +#if defined(DEBUG_STACK_FRAMES) + s.PutCString("No previous frames, so use current frames...\n"); #endif - // We either don't have any previous frames, or since we have more than - // one current frames it means we have all the frames and can safely - // replace our previous frames. - prev_sp.reset (curr_ap.release()); - return; - } - - const uint32_t num_curr_frames = curr_ap->GetNumFrames (false); - - if (num_curr_frames > 1) - { -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("We have more than one current frame, so use current frames...\n"); + // We either don't have any previous frames, or since we have more than + // one current frames it means we have all the frames and can safely + // replace our previous frames. + prev_sp.reset(curr_ap.release()); + return; + } + + const uint32_t num_curr_frames = curr_ap->GetNumFrames(false); + + if (num_curr_frames > 1) { +#if defined(DEBUG_STACK_FRAMES) + s.PutCString( + "We have more than one current frame, so use current frames...\n"); #endif - // We have more than one current frames it means we have all the frames - // and can safely replace our previous frames. - prev_sp.reset (curr_ap.release()); + // We have more than one current frames it means we have all the frames + // and can safely replace our previous frames. + prev_sp.reset(curr_ap.release()); -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("\nMerged:\n"); - prev_sp->Dump (&s); +#if defined(DEBUG_STACK_FRAMES) + s.PutCString("\nMerged:\n"); + prev_sp->Dump(&s); #endif - return; - } + return; + } - StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0)); - StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0)); - StackID curr_stack_id (curr_frame_zero_sp->GetStackID()); - StackID prev_stack_id (prev_frame_zero_sp->GetStackID()); + StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex(0)); + StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex(0)); + StackID curr_stack_id(curr_frame_zero_sp->GetStackID()); + StackID prev_stack_id(prev_frame_zero_sp->GetStackID()); -#if defined (DEBUG_STACK_FRAMES) - const uint32_t num_prev_frames = prev_sp->GetNumFrames (false); - s.Printf("\n%u previous frames with one current frame\n", num_prev_frames); +#if defined(DEBUG_STACK_FRAMES) + const uint32_t num_prev_frames = prev_sp->GetNumFrames(false); + s.Printf("\n%u previous frames with one current frame\n", num_prev_frames); #endif - // We have only a single current frame - // Our previous stack frames only had a single frame as well... - if (curr_stack_id == prev_stack_id) - { -#if defined (DEBUG_STACK_FRAMES) - s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n"); + // We have only a single current frame + // Our previous stack frames only had a single frame as well... + if (curr_stack_id == prev_stack_id) { +#if defined(DEBUG_STACK_FRAMES) + s.Printf("\nPrevious frame #0 is same as current frame #0, merge the " + "cached data\n"); #endif - curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp); -// prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp); -// prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp); - } - else if (curr_stack_id < prev_stack_id) - { -#if defined (DEBUG_STACK_FRAMES) - s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous frame #0, insert current frame zero in front of previous\n"); + curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame( + *prev_frame_zero_sp); + // prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame + // (*curr_frame_zero_sp); + // prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp); + } else if (curr_stack_id < prev_stack_id) { +#if defined(DEBUG_STACK_FRAMES) + s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous " + "frame #0, insert current frame zero in front of previous\n"); #endif - prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp); - } - - curr_ap.release(); + prev_sp->m_frames.insert(prev_sp->m_frames.begin(), curr_frame_zero_sp); + } -#if defined (DEBUG_STACK_FRAMES) - s.PutCString("\nMerged:\n"); - prev_sp->Dump (&s); + curr_ap.release(); + +#if defined(DEBUG_STACK_FRAMES) + s.PutCString("\nMerged:\n"); + prev_sp->Dump(&s); #endif } lldb::StackFrameSP -StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr) -{ - const_iterator pos; - const_iterator begin = m_frames.begin(); - const_iterator end = m_frames.end(); - lldb::StackFrameSP ret_sp; - - for (pos = begin; pos != end; ++pos) - { - if (pos->get() == stack_frame_ptr) - { - ret_sp = (*pos); - break; - } +StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) { + const_iterator pos; + const_iterator begin = m_frames.begin(); + const_iterator end = m_frames.end(); + lldb::StackFrameSP ret_sp; + + for (pos = begin; pos != end; ++pos) { + if (pos->get() == stack_frame_ptr) { + ret_sp = (*pos); + break; } - return ret_sp; + } + return ret_sp; } -size_t -StackFrameList::GetStatus (Stream& strm, - uint32_t first_frame, - uint32_t num_frames, - bool show_frame_info, - uint32_t num_frames_with_source, - const char *selected_frame_marker) -{ - size_t num_frames_displayed = 0; - - if (num_frames == 0) - return 0; - - StackFrameSP frame_sp; - uint32_t frame_idx = 0; - uint32_t last_frame; - - // Don't let the last frame wrap around... - if (num_frames == UINT32_MAX) - last_frame = UINT32_MAX; - else - last_frame = first_frame + num_frames; - - StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame(); - const char *unselected_marker = nullptr; - std::string buffer; - if (selected_frame_marker) - { - size_t len = strlen(selected_frame_marker); - buffer.insert(buffer.begin(), len, ' '); - unselected_marker = buffer.c_str(); +size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame, + uint32_t num_frames, bool show_frame_info, + uint32_t num_frames_with_source, + const char *selected_frame_marker) { + size_t num_frames_displayed = 0; + + if (num_frames == 0) + return 0; + + StackFrameSP frame_sp; + uint32_t frame_idx = 0; + uint32_t last_frame; + + // Don't let the last frame wrap around... + if (num_frames == UINT32_MAX) + last_frame = UINT32_MAX; + else + last_frame = first_frame + num_frames; + + StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame(); + const char *unselected_marker = nullptr; + std::string buffer; + if (selected_frame_marker) { + size_t len = strlen(selected_frame_marker); + buffer.insert(buffer.begin(), len, ' '); + unselected_marker = buffer.c_str(); + } + const char *marker = nullptr; + + for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) { + frame_sp = GetFrameAtIndex(frame_idx); + if (!frame_sp) + break; + + if (selected_frame_marker != nullptr) { + if (frame_sp == selected_frame_sp) + marker = selected_frame_marker; + else + marker = unselected_marker; } - const char *marker = nullptr; - - for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) - { - frame_sp = GetFrameAtIndex(frame_idx); - if (!frame_sp) - break; - - if (selected_frame_marker != nullptr) - { - if (frame_sp == selected_frame_sp) - marker = selected_frame_marker; - else - marker = unselected_marker; - } - - if (!frame_sp->GetStatus (strm, - show_frame_info, - num_frames_with_source > (first_frame - frame_idx), marker)) - break; - ++num_frames_displayed; - } - - strm.IndentLess(); - return num_frames_displayed; + + if (!frame_sp->GetStatus(strm, show_frame_info, + num_frames_with_source > (first_frame - frame_idx), + marker)) + break; + ++num_frames_displayed; + } + + strm.IndentLess(); + return num_frames_displayed; } diff --git a/lldb/source/Target/StackID.cpp b/lldb/source/Target/StackID.cpp index 222b2d3f2aa..0d215ed5c9c 100644 --- a/lldb/source/Target/StackID.cpp +++ b/lldb/source/Target/StackID.cpp @@ -19,91 +19,85 @@ using namespace lldb_private; -void -StackID::Dump (Stream *s) -{ - s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p", - m_pc, m_cfa, static_cast<void*>(m_symbol_scope)); - if (m_symbol_scope) - { - SymbolContext sc; - - m_symbol_scope->CalculateSymbolContext (&sc); - if (sc.block) - s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID()); - else if (sc.symbol) - s->Printf(" (Symbol{0x%8.8x})", sc.symbol->GetID()); - } - s->PutCString(") "); +void StackID::Dump(Stream *s) { + s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 + ", symbol_scope = %p", + m_pc, m_cfa, static_cast<void *>(m_symbol_scope)); + if (m_symbol_scope) { + SymbolContext sc; + + m_symbol_scope->CalculateSymbolContext(&sc); + if (sc.block) + s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID()); + else if (sc.symbol) + s->Printf(" (Symbol{0x%8.8x})", sc.symbol->GetID()); + } + s->PutCString(") "); } -bool -lldb_private::operator== (const StackID& lhs, const StackID& rhs) -{ - if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress()) - return false; +bool lldb_private::operator==(const StackID &lhs, const StackID &rhs) { + if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress()) + return false; + + SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope(); + SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope(); - SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope(); - SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope(); + // Only compare the PC values if both symbol context scopes are nullptr + if (lhs_scope == nullptr && rhs_scope == nullptr) + return lhs.GetPC() == rhs.GetPC(); - // Only compare the PC values if both symbol context scopes are nullptr - if (lhs_scope == nullptr && rhs_scope == nullptr) - return lhs.GetPC() == rhs.GetPC(); - - return lhs_scope == rhs_scope; + return lhs_scope == rhs_scope; } -bool -lldb_private::operator!= (const StackID& lhs, const StackID& rhs) -{ - if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress()) - return true; +bool lldb_private::operator!=(const StackID &lhs, const StackID &rhs) { + if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress()) + return true; - SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope(); - SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope(); + SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope(); + SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope(); - if (lhs_scope == nullptr && rhs_scope == nullptr) - return lhs.GetPC() != rhs.GetPC(); + if (lhs_scope == nullptr && rhs_scope == nullptr) + return lhs.GetPC() != rhs.GetPC(); - return lhs_scope != rhs_scope; + return lhs_scope != rhs_scope; } -bool -lldb_private::operator< (const StackID& lhs, const StackID& rhs) -{ - const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress(); - const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress(); - - // FIXME: We are assuming that the stacks grow downward in memory. That's not necessary, but true on - // all the machines we care about at present. If this changes, we'll have to deal with that. The ABI is the - // agent who knows this ordering, but the StackID has no access to the ABI. The most straightforward way - // to handle this is to add a "m_grows_downward" bool to the StackID, and set it in the constructor. - // But I'm not going to waste a bool per StackID on this till we need it. - - if (lhs_cfa != rhs_cfa) - return lhs_cfa < rhs_cfa; - - SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope(); - SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope(); - - if (lhs_scope != nullptr && rhs_scope != nullptr) - { - // Same exact scope, lhs is not less than (younger than rhs) - if (lhs_scope == rhs_scope) - return false; - - SymbolContext lhs_sc; - SymbolContext rhs_sc; - lhs_scope->CalculateSymbolContext (&lhs_sc); - rhs_scope->CalculateSymbolContext (&rhs_sc); - - // Items with the same function can only be compared - if (lhs_sc.function == rhs_sc.function && - lhs_sc.function != nullptr && lhs_sc.block != nullptr && - rhs_sc.function != nullptr && rhs_sc.block != nullptr) - { - return rhs_sc.block->Contains (lhs_sc.block); - } +bool lldb_private::operator<(const StackID &lhs, const StackID &rhs) { + const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress(); + const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress(); + + // FIXME: We are assuming that the stacks grow downward in memory. That's not + // necessary, but true on + // all the machines we care about at present. If this changes, we'll have to + // deal with that. The ABI is the + // agent who knows this ordering, but the StackID has no access to the ABI. + // The most straightforward way + // to handle this is to add a "m_grows_downward" bool to the StackID, and set + // it in the constructor. + // But I'm not going to waste a bool per StackID on this till we need it. + + if (lhs_cfa != rhs_cfa) + return lhs_cfa < rhs_cfa; + + SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope(); + SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope(); + + if (lhs_scope != nullptr && rhs_scope != nullptr) { + // Same exact scope, lhs is not less than (younger than rhs) + if (lhs_scope == rhs_scope) + return false; + + SymbolContext lhs_sc; + SymbolContext rhs_sc; + lhs_scope->CalculateSymbolContext(&lhs_sc); + rhs_scope->CalculateSymbolContext(&rhs_sc); + + // Items with the same function can only be compared + if (lhs_sc.function == rhs_sc.function && lhs_sc.function != nullptr && + lhs_sc.block != nullptr && rhs_sc.function != nullptr && + rhs_sc.block != nullptr) { + return rhs_sc.block->Contains(lhs_sc.block); } - return false; + } + return false; } diff --git a/lldb/source/Target/StopInfo.cpp b/lldb/source/Target/StopInfo.cpp index 68db6654d5d..294ccf366ca 100644 --- a/lldb/source/Target/StopInfo.cpp +++ b/lldb/source/Target/StopInfo.cpp @@ -13,1255 +13,1131 @@ // Other libraries and framework includes // Project includes -#include "lldb/Target/StopInfo.h" -#include "lldb/Core/Log.h" #include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Breakpoint/Watchpoint.h" #include "lldb/Core/Debugger.h" +#include "lldb/Core/Log.h" #include "lldb/Core/StreamString.h" #include "lldb/Core/ValueObject.h" #include "lldb/Expression/UserExpression.h" +#include "lldb/Target/Process.h" +#include "lldb/Target/StopInfo.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" -#include "lldb/Target/Process.h" #include "lldb/Target/UnixSignals.h" using namespace lldb; using namespace lldb_private; -StopInfo::StopInfo (Thread &thread, uint64_t value) : - m_thread_wp (thread.shared_from_this()), - m_stop_id (thread.GetProcess()->GetStopID()), - m_resume_id (thread.GetProcess()->GetResumeID()), - m_value (value), - m_description (), - m_override_should_notify (eLazyBoolCalculate), - m_override_should_stop (eLazyBoolCalculate), - m_extended_info() -{ +StopInfo::StopInfo(Thread &thread, uint64_t value) + : m_thread_wp(thread.shared_from_this()), + m_stop_id(thread.GetProcess()->GetStopID()), + m_resume_id(thread.GetProcess()->GetResumeID()), m_value(value), + m_description(), m_override_should_notify(eLazyBoolCalculate), + m_override_should_stop(eLazyBoolCalculate), m_extended_info() {} + +bool StopInfo::IsValid() const { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + return thread_sp->GetProcess()->GetStopID() == m_stop_id; + return false; } -bool -StopInfo::IsValid () const -{ - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - return thread_sp->GetProcess()->GetStopID() == m_stop_id; - return false; -} - -void -StopInfo::MakeStopInfoValid () -{ - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - m_stop_id = thread_sp->GetProcess()->GetStopID(); - m_resume_id = thread_sp->GetProcess()->GetResumeID(); - } +void StopInfo::MakeStopInfoValid() { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + m_stop_id = thread_sp->GetProcess()->GetStopID(); + m_resume_id = thread_sp->GetProcess()->GetResumeID(); + } } -bool -StopInfo::HasTargetRunSinceMe () -{ - ThreadSP thread_sp (m_thread_wp.lock()); - - if (thread_sp) - { - lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState(); - if (ret_type == eStateRunning) - { - return true; - } - else if (ret_type == eStateStopped) - { - // This is a little tricky. We want to count "run and stopped again before you could - // ask this question as a "TRUE" answer to HasTargetRunSinceMe. But we don't want to - // include any running of the target done for expressions. So we track both resumes, - // and resumes caused by expressions, and check if there are any resumes NOT caused - // by expressions. - - uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID(); - uint32_t last_user_expression_id = thread_sp->GetProcess()->GetLastUserExpressionResumeID (); - if (curr_resume_id == m_resume_id) - { - return false; - } - else if (curr_resume_id > last_user_expression_id) - { - return true; - } - } +bool StopInfo::HasTargetRunSinceMe() { + ThreadSP thread_sp(m_thread_wp.lock()); + + if (thread_sp) { + lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState(); + if (ret_type == eStateRunning) { + return true; + } else if (ret_type == eStateStopped) { + // This is a little tricky. We want to count "run and stopped again + // before you could + // ask this question as a "TRUE" answer to HasTargetRunSinceMe. But we + // don't want to + // include any running of the target done for expressions. So we track + // both resumes, + // and resumes caused by expressions, and check if there are any resumes + // NOT caused + // by expressions. + + uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID(); + uint32_t last_user_expression_id = + thread_sp->GetProcess()->GetLastUserExpressionResumeID(); + if (curr_resume_id == m_resume_id) { + return false; + } else if (curr_resume_id > last_user_expression_id) { + return true; + } } - return false; + } + return false; } //---------------------------------------------------------------------- // StopInfoBreakpoint //---------------------------------------------------------------------- -namespace lldb_private -{ -class StopInfoBreakpoint : public StopInfo -{ +namespace lldb_private { +class StopInfoBreakpoint : public StopInfo { public: - StopInfoBreakpoint (Thread &thread, break_id_t break_id) : - StopInfo (thread, break_id), - m_should_stop (false), - m_should_stop_is_valid (false), - m_should_perform_action (true), - m_address (LLDB_INVALID_ADDRESS), - m_break_id(LLDB_INVALID_BREAK_ID), - m_was_one_shot (false) - { - StoreBPInfo(); + StopInfoBreakpoint(Thread &thread, break_id_t break_id) + : StopInfo(thread, break_id), m_should_stop(false), + m_should_stop_is_valid(false), m_should_perform_action(true), + m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), + m_was_one_shot(false) { + StoreBPInfo(); + } + + StopInfoBreakpoint(Thread &thread, break_id_t break_id, bool should_stop) + : StopInfo(thread, break_id), m_should_stop(should_stop), + m_should_stop_is_valid(true), m_should_perform_action(true), + m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID), + m_was_one_shot(false) { + StoreBPInfo(); + } + + ~StopInfoBreakpoint() override = default; + + void StoreBPInfo() { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + BreakpointSiteSP bp_site_sp( + thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); + if (bp_site_sp) { + if (bp_site_sp->GetNumberOfOwners() == 1) { + BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0); + if (bp_loc_sp) { + m_break_id = bp_loc_sp->GetBreakpoint().GetID(); + m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot(); + } + } + m_address = bp_site_sp->GetLoadAddress(); + } } - - StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) : - StopInfo (thread, break_id), - m_should_stop (should_stop), - m_should_stop_is_valid (true), - m_should_perform_action (true), - m_address (LLDB_INVALID_ADDRESS), - m_break_id(LLDB_INVALID_BREAK_ID), - m_was_one_shot (false) - { - StoreBPInfo(); + } + + bool IsValidForOperatingSystemThread(Thread &thread) override { + ProcessSP process_sp(thread.GetProcess()); + if (process_sp) { + BreakpointSiteSP bp_site_sp( + process_sp->GetBreakpointSiteList().FindByID(m_value)); + if (bp_site_sp) + return bp_site_sp->ValidForThisThread(&thread); } - - ~StopInfoBreakpoint() override = default; - - void - StoreBPInfo () - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value)); - if (bp_site_sp) - { - if (bp_site_sp->GetNumberOfOwners() == 1) - { - BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0); - if (bp_loc_sp) - { - m_break_id = bp_loc_sp->GetBreakpoint().GetID(); - m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot(); - } - } - m_address = bp_site_sp->GetLoadAddress(); - } + return false; + } + + StopReason GetStopReason() const override { return eStopReasonBreakpoint; } + + bool ShouldStopSynchronous(Event *event_ptr) override { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + if (!m_should_stop_is_valid) { + // Only check once if we should stop at a breakpoint + BreakpointSiteSP bp_site_sp( + thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); + if (bp_site_sp) { + ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); + StoppointCallbackContext context(event_ptr, exe_ctx, true); + bp_site_sp->BumpHitCounts(); + m_should_stop = bp_site_sp->ShouldStop(&context); + } else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (log) + log->Printf( + "Process::%s could not find breakpoint site id: %" PRId64 "...", + __FUNCTION__, m_value); + + m_should_stop = true; } + m_should_stop_is_valid = true; + } + return m_should_stop; } - - bool - IsValidForOperatingSystemThread(Thread &thread) override - { - ProcessSP process_sp (thread.GetProcess()); - if (process_sp) - { - BreakpointSiteSP bp_site_sp (process_sp->GetBreakpointSiteList().FindByID (m_value)); - if (bp_site_sp) - return bp_site_sp->ValidForThisThread (&thread); + return false; + } + + bool DoShouldNotify(Event *event_ptr) override { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + BreakpointSiteSP bp_site_sp( + thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); + if (bp_site_sp) { + bool all_internal = true; + + for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++) { + if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { + all_internal = false; + break; + } } - return false; + return !all_internal; + } } - - StopReason - GetStopReason() const override - { - return eStopReasonBreakpoint; - } - - bool - ShouldStopSynchronous(Event *event_ptr) override - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - if (!m_should_stop_is_valid) - { - // Only check once if we should stop at a breakpoint - BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value)); - if (bp_site_sp) - { - ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0)); - StoppointCallbackContext context (event_ptr, exe_ctx, true); - bp_site_sp->BumpHitCounts(); - m_should_stop = bp_site_sp->ShouldStop (&context); - } + return true; + } + + const char *GetDescription() override { + if (m_description.empty()) { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + BreakpointSiteSP bp_site_sp( + thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); + if (bp_site_sp) { + StreamString strm; + // If we have just hit an internal breakpoint, and it has a kind + // description, print that instead of the + // full breakpoint printing: + if (bp_site_sp->IsInternal()) { + size_t num_owners = bp_site_sp->GetNumberOfOwners(); + for (size_t idx = 0; idx < num_owners; idx++) { + const char *kind = bp_site_sp->GetOwnerAtIndex(idx) + ->GetBreakpoint() + .GetBreakpointKind(); + if (kind != nullptr) { + m_description.assign(kind); + return kind; + } + } + } + + strm.Printf("breakpoint "); + bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief); + m_description.swap(strm.GetString()); + } else { + StreamString strm; + if (m_break_id != LLDB_INVALID_BREAK_ID) { + BreakpointSP break_sp = + thread_sp->GetProcess()->GetTarget().GetBreakpointByID( + m_break_id); + if (break_sp) { + if (break_sp->IsInternal()) { + const char *kind = break_sp->GetBreakpointKind(); + if (kind) + strm.Printf("internal %s breakpoint(%d).", kind, m_break_id); else - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - - if (log) - log->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value); - - m_should_stop = true; - } - m_should_stop_is_valid = true; + strm.Printf("internal breakpoint(%d).", m_break_id); + } else { + strm.Printf("breakpoint %d.", m_break_id); + } + } else { + if (m_was_one_shot) + strm.Printf("one-shot breakpoint %d", m_break_id); + else + strm.Printf("breakpoint %d which has been deleted.", + m_break_id); } - return m_should_stop; + } else if (m_address == LLDB_INVALID_ADDRESS) + strm.Printf("breakpoint site %" PRIi64 + " which has been deleted - unknown address", + m_value); + else + strm.Printf("breakpoint site %" PRIi64 + " which has been deleted - was at 0x%" PRIx64, + m_value, m_address); + + m_description.swap(strm.GetString()); } - return false; + } } + return m_description.c_str(); + } - bool - DoShouldNotify(Event *event_ptr) override - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value)); - if (bp_site_sp) - { - bool all_internal = true; - - for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++) - { - if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) - { - all_internal = false; - break; - } +protected: + bool ShouldStop(Event *event_ptr) override { + // This just reports the work done by PerformAction or the synchronous stop. + // It should + // only ever get called after they have had a chance to run. + assert(m_should_stop_is_valid); + return m_should_stop; + } + + void PerformAction(Event *event_ptr) override { + if (!m_should_perform_action) + return; + m_should_perform_action = false; + + ThreadSP thread_sp(m_thread_wp.lock()); + + if (thread_sp) { + Log *log = lldb_private::GetLogIfAnyCategoriesSet( + LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP); + + if (!thread_sp->IsValid()) { + // This shouldn't ever happen, but just in case, don't do more harm. + if (log) { + log->Printf("PerformAction got called with an invalid thread."); + } + m_should_stop = true; + m_should_stop_is_valid = true; + return; + } + + BreakpointSiteSP bp_site_sp( + thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value)); + std::unordered_set<break_id_t> precondition_breakpoints; + + if (bp_site_sp) { + // Let's copy the owners list out of the site and store them in a local + // list. That way if + // one of the breakpoint actions changes the site, then we won't be + // operating on a bad list. + BreakpointLocationCollection site_locations; + size_t num_owners = bp_site_sp->CopyOwnersList(site_locations); + + if (num_owners == 0) { + m_should_stop = true; + } else { + // We go through each location, and test first its precondition - this + // overrides everything. Note, + // we only do this once per breakpoint - not once per location... + // Then check the condition. If the condition says to stop, + // then we run the callback for that location. If that callback says + // to stop as well, then + // we set m_should_stop to true; we are going to stop. + // But we still want to give all the breakpoints whose conditions say + // we are going to stop a + // chance to run their callbacks. + // Of course if any callback restarts the target by putting "continue" + // in the callback, then + // we're going to restart, without running the rest of the callbacks. + // And in this case we will + // end up not stopping even if another location said we should stop. + // But that's better than not + // running all the callbacks. + + m_should_stop = false; + + // We don't select threads as we go through them testing breakpoint + // conditions and running commands. + // So we need to set the thread for expression evaluation here: + ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp); + + ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); + Process *process = exe_ctx.GetProcessPtr(); + if (process->GetModIDRef().IsLastResumeForUserExpression()) { + // If we are in the middle of evaluating an expression, don't run + // asynchronous breakpoint commands or + // expressions. That could lead to infinite recursion if the + // command or condition re-calls the function + // with this breakpoint. + // TODO: We can keep a list of the breakpoints we've seen while + // running expressions in the nested + // PerformAction calls that can arise when the action runs a + // function that hits another breakpoint, + // and only stop running commands when we see the same breakpoint + // hit a second time. + + m_should_stop_is_valid = true; + if (log) + log->Printf("StopInfoBreakpoint::PerformAction - Hit a " + "breakpoint while running an expression," + " not running commands to avoid recursion."); + bool ignoring_breakpoints = + process->GetIgnoreBreakpointsInExpressions(); + if (ignoring_breakpoints) { + m_should_stop = false; + // Internal breakpoints will always stop. + for (size_t j = 0; j < num_owners; j++) { + lldb::BreakpointLocationSP bp_loc_sp = + bp_site_sp->GetOwnerAtIndex(j); + if (bp_loc_sp->GetBreakpoint().IsInternal()) { + m_should_stop = true; + break; } - return !all_internal; + } + } else { + m_should_stop = true; + } + if (log) + log->Printf("StopInfoBreakpoint::PerformAction - in expression, " + "continuing: %s.", + m_should_stop ? "true" : "false"); + process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf( + "Warning: hit breakpoint while " + "running function, skipping commands and conditions to prevent " + "recursion."); + return; + } + + StoppointCallbackContext context(event_ptr, exe_ctx, false); + + // For safety's sake let's also grab an extra reference to the + // breakpoint owners of the locations we're + // going to examine, since the locations are going to have to get back + // to their breakpoints, and the + // locations don't keep their owners alive. I'm just sticking the + // BreakpointSP's in a vector since + // I'm only using it to locally increment their retain counts. + + std::vector<lldb::BreakpointSP> location_owners; + + for (size_t j = 0; j < num_owners; j++) { + BreakpointLocationSP loc(site_locations.GetByIndex(j)); + location_owners.push_back(loc->GetBreakpoint().shared_from_this()); + } + + for (size_t j = 0; j < num_owners; j++) { + lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j); + + // If another action disabled this breakpoint or its location, then + // don't run the actions. + if (!bp_loc_sp->IsEnabled() || + !bp_loc_sp->GetBreakpoint().IsEnabled()) + continue; + + // The breakpoint site may have many locations associated with it, + // not all of them valid for + // this thread. Skip the ones that aren't: + if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) { + if (log) { + StreamString s; + bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); + log->Printf("Breakpoint %s hit on thread 0x%llx but it was not " + "for this thread, continuing.", + s.GetData(), static_cast<unsigned long long>( + thread_sp->GetID())); + } + continue; } - } - return true; - } - const char * - GetDescription() override - { - if (m_description.empty()) - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value)); - if (bp_site_sp) - { - StreamString strm; - // If we have just hit an internal breakpoint, and it has a kind description, print that instead of the - // full breakpoint printing: - if (bp_site_sp->IsInternal()) - { - size_t num_owners = bp_site_sp->GetNumberOfOwners(); - for (size_t idx = 0; idx < num_owners; idx++) - { - const char *kind = bp_site_sp->GetOwnerAtIndex(idx)->GetBreakpoint().GetBreakpointKind(); - if (kind != nullptr) - { - m_description.assign (kind); - return kind; - } - } - } - - strm.Printf("breakpoint "); - bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief); - m_description.swap (strm.GetString()); + // First run the precondition, but since the precondition is per + // breakpoint, only run it once + // per breakpoint. + std::pair<std::unordered_set<break_id_t>::iterator, bool> result = + precondition_breakpoints.insert( + bp_loc_sp->GetBreakpoint().GetID()); + if (!result.second) + continue; + + bool precondition_result = + bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context); + if (!precondition_result) + continue; + + // Next run the condition for the breakpoint. If that says we + // should stop, then we'll run + // the callback for the breakpoint. If the callback says we + // shouldn't stop that will win. + + if (bp_loc_sp->GetConditionText() != nullptr) { + Error condition_error; + bool condition_says_stop = + bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error); + + if (!condition_error.Success()) { + Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); + StreamSP error_sp = debugger.GetAsyncErrorStream(); + error_sp->Printf("Stopped due to an error evaluating condition " + "of breakpoint "); + bp_loc_sp->GetDescription(error_sp.get(), + eDescriptionLevelBrief); + error_sp->Printf(": \"%s\"", bp_loc_sp->GetConditionText()); + error_sp->EOL(); + const char *err_str = + condition_error.AsCString("<Unknown Error>"); + if (log) + log->Printf("Error evaluating condition: \"%s\"\n", err_str); + + error_sp->PutCString(err_str); + error_sp->EOL(); + error_sp->Flush(); + } else { + if (log) { + StreamString s; + bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); + log->Printf("Condition evaluated for breakpoint %s on thread " + "0x%llx conditon_says_stop: %i.", + s.GetData(), static_cast<unsigned long long>( + thread_sp->GetID()), + condition_says_stop); } - else - { - StreamString strm; - if (m_break_id != LLDB_INVALID_BREAK_ID) - { - BreakpointSP break_sp = thread_sp->GetProcess()->GetTarget().GetBreakpointByID(m_break_id); - if (break_sp) - { - if (break_sp->IsInternal()) - { - const char *kind = break_sp->GetBreakpointKind(); - if (kind) - strm.Printf ("internal %s breakpoint(%d).", kind, m_break_id); - else - strm.Printf ("internal breakpoint(%d).", m_break_id); - } - else - { - strm.Printf ("breakpoint %d.", m_break_id); - } - } - else - { - if (m_was_one_shot) - strm.Printf ("one-shot breakpoint %d", m_break_id); - else - strm.Printf ("breakpoint %d which has been deleted.", m_break_id); - } - } - else if (m_address == LLDB_INVALID_ADDRESS) - strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value); - else - strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address); - - m_description.swap (strm.GetString()); + if (!condition_says_stop) { + // We don't want to increment the hit count of breakpoints if + // the condition fails. + // We've already bumped it by the time we get here, so undo + // the bump: + bp_loc_sp->UndoBumpHitCount(); + continue; } + } } - } - return m_description.c_str(); - } -protected: - bool - ShouldStop(Event *event_ptr) override - { - // This just reports the work done by PerformAction or the synchronous stop. It should - // only ever get called after they have had a chance to run. - assert (m_should_stop_is_valid); - return m_should_stop; - } + bool callback_says_stop; - void - PerformAction(Event *event_ptr) override - { - if (!m_should_perform_action) - return; - m_should_perform_action = false; + // FIXME: For now the callbacks have to run in async mode - the + // first time we restart we need + // to get out of there. So set it here. + // When we figure out how to nest breakpoint hits then this will + // change. - ThreadSP thread_sp (m_thread_wp.lock()); + Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger(); + bool old_async = debugger.GetAsyncExecution(); + debugger.SetAsyncExecution(true); - if (thread_sp) - { - Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP); + callback_says_stop = bp_loc_sp->InvokeCallback(&context); - if (!thread_sp->IsValid()) - { - // This shouldn't ever happen, but just in case, don't do more harm. - if (log) - { - log->Printf ("PerformAction got called with an invalid thread."); - } - m_should_stop = true; - m_should_stop_is_valid = true; - return; - } - - BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value)); - std::unordered_set<break_id_t> precondition_breakpoints; + debugger.SetAsyncExecution(old_async); - if (bp_site_sp) - { - // Let's copy the owners list out of the site and store them in a local list. That way if - // one of the breakpoint actions changes the site, then we won't be operating on a bad list. - BreakpointLocationCollection site_locations; - size_t num_owners = bp_site_sp->CopyOwnersList(site_locations); + if (callback_says_stop) + m_should_stop = true; - if (num_owners == 0) - { - m_should_stop = true; - } - else - { - // We go through each location, and test first its precondition - this overrides everything. Note, - // we only do this once per breakpoint - not once per location... - // Then check the condition. If the condition says to stop, - // then we run the callback for that location. If that callback says to stop as well, then - // we set m_should_stop to true; we are going to stop. - // But we still want to give all the breakpoints whose conditions say we are going to stop a - // chance to run their callbacks. - // Of course if any callback restarts the target by putting "continue" in the callback, then - // we're going to restart, without running the rest of the callbacks. And in this case we will - // end up not stopping even if another location said we should stop. But that's better than not - // running all the callbacks. - - m_should_stop = false; - - // We don't select threads as we go through them testing breakpoint conditions and running commands. - // So we need to set the thread for expression evaluation here: - ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp); - - ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0)); - Process *process = exe_ctx.GetProcessPtr(); - if (process->GetModIDRef().IsLastResumeForUserExpression()) - { - // If we are in the middle of evaluating an expression, don't run asynchronous breakpoint commands or - // expressions. That could lead to infinite recursion if the command or condition re-calls the function - // with this breakpoint. - // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested - // PerformAction calls that can arise when the action runs a function that hits another breakpoint, - // and only stop running commands when we see the same breakpoint hit a second time. - - m_should_stop_is_valid = true; - if (log) - log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression," - " not running commands to avoid recursion."); - bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions(); - if (ignoring_breakpoints) - { - m_should_stop = false; - // Internal breakpoints will always stop. - for (size_t j = 0; j < num_owners; j++) - { - lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j); - if (bp_loc_sp->GetBreakpoint().IsInternal()) - { - m_should_stop = true; - break; - } - } - } - else - { - m_should_stop = true; - } - if (log) - log->Printf ("StopInfoBreakpoint::PerformAction - in expression, continuing: %s.", - m_should_stop ? "true" : "false"); - process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: hit breakpoint while " - "running function, skipping commands and conditions to prevent recursion."); - return; - } - - StoppointCallbackContext context (event_ptr, exe_ctx, false); - - // For safety's sake let's also grab an extra reference to the breakpoint owners of the locations we're - // going to examine, since the locations are going to have to get back to their breakpoints, and the - // locations don't keep their owners alive. I'm just sticking the BreakpointSP's in a vector since - // I'm only using it to locally increment their retain counts. - - std::vector<lldb::BreakpointSP> location_owners; - - for (size_t j = 0; j < num_owners; j++) - { - BreakpointLocationSP loc(site_locations.GetByIndex(j)); - location_owners.push_back(loc->GetBreakpoint().shared_from_this()); - - } - - for (size_t j = 0; j < num_owners; j++) - { - lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j); - - // If another action disabled this breakpoint or its location, then don't run the actions. - if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled()) - continue; - - // The breakpoint site may have many locations associated with it, not all of them valid for - // this thread. Skip the ones that aren't: - if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) - { - if (log) - { - StreamString s; - bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); - log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.", - s.GetData(), - static_cast<unsigned long long>(thread_sp->GetID())); - } - continue; - } - - // First run the precondition, but since the precondition is per breakpoint, only run it once - // per breakpoint. - std::pair<std::unordered_set<break_id_t>::iterator, bool> result - = precondition_breakpoints.insert(bp_loc_sp->GetBreakpoint().GetID()); - if (!result.second) - continue; - - bool precondition_result = bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context); - if (!precondition_result) - continue; - - // Next run the condition for the breakpoint. If that says we should stop, then we'll run - // the callback for the breakpoint. If the callback says we shouldn't stop that will win. - - if (bp_loc_sp->GetConditionText() != nullptr) - { - Error condition_error; - bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error); - - if (!condition_error.Success()) - { - Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); - StreamSP error_sp = debugger.GetAsyncErrorStream (); - error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint "); - bp_loc_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief); - error_sp->Printf (": \"%s\"", - bp_loc_sp->GetConditionText()); - error_sp->EOL(); - const char *err_str = condition_error.AsCString("<Unknown Error>"); - if (log) - log->Printf("Error evaluating condition: \"%s\"\n", err_str); - - error_sp->PutCString (err_str); - error_sp->EOL(); - error_sp->Flush(); - } - else - { - if (log) - { - StreamString s; - bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief); - log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.", - s.GetData(), - static_cast<unsigned long long>(thread_sp->GetID()), - condition_says_stop); - } - if (!condition_says_stop) - { - // We don't want to increment the hit count of breakpoints if the condition fails. - // We've already bumped it by the time we get here, so undo the bump: - bp_loc_sp->UndoBumpHitCount(); - continue; - } - } - } - - bool callback_says_stop; - - // FIXME: For now the callbacks have to run in async mode - the first time we restart we need - // to get out of there. So set it here. - // When we figure out how to nest breakpoint hits then this will change. - - Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger(); - bool old_async = debugger.GetAsyncExecution(); - debugger.SetAsyncExecution (true); - - callback_says_stop = bp_loc_sp->InvokeCallback (&context); - - debugger.SetAsyncExecution (old_async); - - if (callback_says_stop) - m_should_stop = true; - - // If we are going to stop for this breakpoint, then remove the breakpoint. - if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot()) - { - thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID()); - } - - // Also make sure that the callback hasn't continued the target. - // If it did, when we'll set m_should_start to false and get out of here. - if (HasTargetRunSinceMe ()) - { - m_should_stop = false; - break; - } - } - } - // We've figured out what this stop wants to do, so mark it as valid so we don't compute it again. - m_should_stop_is_valid = true; + // If we are going to stop for this breakpoint, then remove the + // breakpoint. + if (callback_says_stop && bp_loc_sp && + bp_loc_sp->GetBreakpoint().IsOneShot()) { + thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID( + bp_loc_sp->GetBreakpoint().GetID()); } - else - { - m_should_stop = true; - m_should_stop_is_valid = true; - Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); - if (log_process) - log_process->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value); + // Also make sure that the callback hasn't continued the target. + // If it did, when we'll set m_should_start to false and get out of + // here. + if (HasTargetRunSinceMe()) { + m_should_stop = false; + break; } - if (log) - log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop); + } } + // We've figured out what this stop wants to do, so mark it as valid so + // we don't compute it again. + m_should_stop_is_valid = true; + } else { + m_should_stop = true; + m_should_stop_is_valid = true; + Log *log_process( + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (log_process) + log_process->Printf( + "Process::%s could not find breakpoint site id: %" PRId64 "...", + __FUNCTION__, m_value); + } + if (log) + log->Printf("Process::%s returning from action with m_should_stop: %d.", + __FUNCTION__, m_should_stop); } + } private: - bool m_should_stop; - bool m_should_stop_is_valid; - bool m_should_perform_action; // Since we are trying to preserve the "state" of the system even if we run functions - // etc. behind the users backs, we need to make sure we only REALLY perform the action once. - lldb::addr_t m_address; // We use this to capture the breakpoint site address when we create the StopInfo, - // in case somebody deletes it between the time the StopInfo is made and the - // description is asked for. - lldb::break_id_t m_break_id; - bool m_was_one_shot; + bool m_should_stop; + bool m_should_stop_is_valid; + bool m_should_perform_action; // Since we are trying to preserve the "state" + // of the system even if we run functions + // etc. behind the users backs, we need to make sure we only REALLY perform + // the action once. + lldb::addr_t m_address; // We use this to capture the breakpoint site address + // when we create the StopInfo, + // in case somebody deletes it between the time the StopInfo is made and the + // description is asked for. + lldb::break_id_t m_break_id; + bool m_was_one_shot; }; //---------------------------------------------------------------------- // StopInfoWatchpoint //---------------------------------------------------------------------- -class StopInfoWatchpoint : public StopInfo -{ +class StopInfoWatchpoint : public StopInfo { public: - // Make sure watchpoint is properly disabled and subsequently enabled while performing watchpoint actions. - class WatchpointSentry { - public: - WatchpointSentry(Process *p, Watchpoint *w): - process(p), - watchpoint(w) - { - if (process && watchpoint) - { - const bool notify = false; - watchpoint->TurnOnEphemeralMode(); - process->DisableWatchpoint(watchpoint, notify); - } - } + // Make sure watchpoint is properly disabled and subsequently enabled while + // performing watchpoint actions. + class WatchpointSentry { + public: + WatchpointSentry(Process *p, Watchpoint *w) : process(p), watchpoint(w) { + if (process && watchpoint) { + const bool notify = false; + watchpoint->TurnOnEphemeralMode(); + process->DisableWatchpoint(watchpoint, notify); + } + } - ~WatchpointSentry() - { - if (process && watchpoint) - { - if (!watchpoint->IsDisabledDuringEphemeralMode()) - { - const bool notify = false; - process->EnableWatchpoint(watchpoint, notify); - } - watchpoint->TurnOffEphemeralMode(); - } + ~WatchpointSentry() { + if (process && watchpoint) { + if (!watchpoint->IsDisabledDuringEphemeralMode()) { + const bool notify = false; + process->EnableWatchpoint(watchpoint, notify); } - - private: - Process *process; - Watchpoint *watchpoint; - }; - - StopInfoWatchpoint (Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr) : - StopInfo(thread, watch_id), - m_should_stop(false), - m_should_stop_is_valid(false), - m_watch_hit_addr(watch_hit_addr) - { + watchpoint->TurnOffEphemeralMode(); + } } - ~StopInfoWatchpoint() override = default; + private: + Process *process; + Watchpoint *watchpoint; + }; - StopReason - GetStopReason() const override - { - return eStopReasonWatchpoint; - } + StopInfoWatchpoint(Thread &thread, break_id_t watch_id, + lldb::addr_t watch_hit_addr) + : StopInfo(thread, watch_id), m_should_stop(false), + m_should_stop_is_valid(false), m_watch_hit_addr(watch_hit_addr) {} - const char * - GetDescription() override - { - if (m_description.empty()) - { - StreamString strm; - strm.Printf("watchpoint %" PRIi64, m_value); - m_description.swap (strm.GetString()); - } - return m_description.c_str(); + ~StopInfoWatchpoint() override = default; + + StopReason GetStopReason() const override { return eStopReasonWatchpoint; } + + const char *GetDescription() override { + if (m_description.empty()) { + StreamString strm; + strm.Printf("watchpoint %" PRIi64, m_value); + m_description.swap(strm.GetString()); } + return m_description.c_str(); + } protected: - bool - ShouldStopSynchronous(Event *event_ptr) override - { - // ShouldStop() method is idempotent and should not affect hit count. - // See Process::RunPrivateStateThread()->Process()->HandlePrivateEvent() - // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()-> - // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()-> - // StopInfoWatchpoint::ShouldStop() and - // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()-> - // StopInfoWatchpoint::PerformAction(). - if (m_should_stop_is_valid) - return m_should_stop; - - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) + bool ShouldStopSynchronous(Event *event_ptr) override { + // ShouldStop() method is idempotent and should not affect hit count. + // See Process::RunPrivateStateThread()->Process()->HandlePrivateEvent() + // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()-> + // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()-> + // StopInfoWatchpoint::ShouldStop() and + // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()-> + // StopInfoWatchpoint::PerformAction(). + if (m_should_stop_is_valid) + return m_should_stop; + + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + WatchpointSP wp_sp( + thread_sp->CalculateTarget()->GetWatchpointList().FindByID( + GetValue())); + if (wp_sp) { + // Check if we should stop at a watchpoint. + ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); + StoppointCallbackContext context(event_ptr, exe_ctx, true); + m_should_stop = wp_sp->ShouldStop(&context); + } else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); + + if (log) + log->Printf( + "Process::%s could not find watchpoint location id: %" PRId64 + "...", + __FUNCTION__, GetValue()); + + m_should_stop = true; + } + } + m_should_stop_is_valid = true; + return m_should_stop; + } + + bool ShouldStop(Event *event_ptr) override { + // This just reports the work done by PerformAction or the synchronous stop. + // It should + // only ever get called after they have had a chance to run. + assert(m_should_stop_is_valid); + return m_should_stop; + } + + void PerformAction(Event *event_ptr) override { + Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS); + // We're going to calculate if we should stop or not in some way during the + // course of + // this code. Also by default we're going to stop, so set that here. + m_should_stop = true; + + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + + WatchpointSP wp_sp( + thread_sp->CalculateTarget()->GetWatchpointList().FindByID( + GetValue())); + if (wp_sp) { + ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0)); + Process *process = exe_ctx.GetProcessPtr(); + + // This sentry object makes sure the current watchpoint is disabled + // while performing watchpoint actions, + // and it is then enabled after we are finished. + WatchpointSentry sentry(process, wp_sp.get()); + { - WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue())); - if (wp_sp) - { - // Check if we should stop at a watchpoint. - ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0)); - StoppointCallbackContext context (event_ptr, exe_ctx, true); - m_should_stop = wp_sp->ShouldStop (&context); + // check if this process is running on an architecture where + // watchpoints trigger + // before the associated instruction runs. if so, disable the WP, + // single-step and then + // re-enable the watchpoint + if (process) { + uint32_t num; + bool wp_triggers_after; + if (process->GetWatchpointSupportInfo(num, wp_triggers_after) + .Success()) { + if (!wp_triggers_after) { + StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo(); + assert(stored_stop_info_sp.get() == this); + + ThreadPlanSP new_plan_sp( + thread_sp->QueueThreadPlanForStepSingleInstruction( + false, // step-over + false, // abort_other_plans + true)); // stop_other_threads + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + new_plan_sp->SetPrivate(true); + process->GetThreadList().SetSelectedThreadByID( + thread_sp->GetID()); + process->ResumeSynchronous(nullptr); + process->GetThreadList().SetSelectedThreadByID( + thread_sp->GetID()); + thread_sp->SetStopInfo(stored_stop_info_sp); + } } - else - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + } + } - if (log) - log->Printf ("Process::%s could not find watchpoint location id: %" PRId64 "...", - __FUNCTION__, GetValue()); + /* + * MIPS: Last 3bits of the watchpoint address are masked by the kernel. + * For example: + * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is + * set at 'm', then + * watch exception is generated even when 'n' is read/written. To handle + * this case, + * server emulates the instruction at PC and finds the base address of + * the load/store + * instruction and appends it in the description of the stop-info + * packet. If watchpoint + * is not set on this address by user then this do not stop. + */ + if (m_watch_hit_addr != LLDB_INVALID_ADDRESS) { + WatchpointSP wp_hit_sp = + thread_sp->CalculateTarget()->GetWatchpointList().FindByAddress( + m_watch_hit_addr); + if (!wp_hit_sp) { + m_should_stop = false; + wp_sp->IncrementFalseAlarmsAndReviseHitCount(); + } + } + // TODO: This condition should be checked in the synchronous part of the + // watchpoint code + // (Watchpoint::ShouldStop), so that we avoid pulling an event even if + // the watchpoint fails + // the ignore count condition. It is moved here temporarily, because for + // archs with + // watchpoint_exceptions_received=before, the code in the previous lines + // takes care of moving + // the inferior to next PC. We have to check the ignore count condition + // after this is done, + // otherwise we will hit same watchpoint multiple times until we pass + // ignore condition, but we + // won't actually be ignoring them. + if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) + m_should_stop = false; + + if (m_should_stop && wp_sp->GetConditionText() != nullptr) { + // We need to make sure the user sees any parse errors in their + // condition, so we'll hook the + // constructor errors up to the debugger's Async I/O. + ExpressionResults result_code; + EvaluateExpressionOptions expr_options; + expr_options.SetUnwindOnError(true); + expr_options.SetIgnoreBreakpoints(true); + ValueObjectSP result_value_sp; + Error error; + result_code = UserExpression::Evaluate( + exe_ctx, expr_options, wp_sp->GetConditionText(), nullptr, + result_value_sp, error); + + if (result_code == eExpressionCompleted) { + if (result_value_sp) { + Scalar scalar_value; + if (result_value_sp->ResolveValue(scalar_value)) { + if (scalar_value.ULongLong(1) == 0) { + // We have been vetoed. This takes precedence over querying + // the watchpoint whether it should stop (aka ignore count and + // friends). See also StopInfoWatchpoint::ShouldStop() as + // well + // as Process::ProcessEventData::DoOnRemoval(). + m_should_stop = false; + } else + m_should_stop = true; + if (log) + log->Printf( + "Condition successfully evaluated, result is %s.\n", + m_should_stop ? "true" : "false"); + } else { m_should_stop = true; + if (log) + log->Printf( + "Failed to get an integer result from the expression."); + } } + } else { + Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); + StreamSP error_sp = debugger.GetAsyncErrorStream(); + error_sp->Printf( + "Stopped due to an error evaluating condition of watchpoint "); + wp_sp->GetDescription(error_sp.get(), eDescriptionLevelBrief); + error_sp->Printf(": \"%s\"", wp_sp->GetConditionText()); + error_sp->EOL(); + const char *err_str = error.AsCString("<Unknown Error>"); + if (log) + log->Printf("Error evaluating condition: \"%s\"\n", err_str); + + error_sp->PutCString(err_str); + error_sp->EOL(); + error_sp->Flush(); + // If the condition fails to be parsed or run, we should stop. + m_should_stop = true; + } } - m_should_stop_is_valid = true; - return m_should_stop; - } - - bool - ShouldStop(Event *event_ptr) override - { - // This just reports the work done by PerformAction or the synchronous stop. It should - // only ever get called after they have had a chance to run. - assert (m_should_stop_is_valid); - return m_should_stop; - } - - void - PerformAction(Event *event_ptr) override - { - Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS); - // We're going to calculate if we should stop or not in some way during the course of - // this code. Also by default we're going to stop, so set that here. - m_should_stop = true; - - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue())); - if (wp_sp) - { - ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0)); - Process* process = exe_ctx.GetProcessPtr(); - - // This sentry object makes sure the current watchpoint is disabled while performing watchpoint actions, - // and it is then enabled after we are finished. - WatchpointSentry sentry(process, wp_sp.get()); - - { - // check if this process is running on an architecture where watchpoints trigger - // before the associated instruction runs. if so, disable the WP, single-step and then - // re-enable the watchpoint - if (process) - { - uint32_t num; - bool wp_triggers_after; - if (process->GetWatchpointSupportInfo(num, wp_triggers_after).Success()) - { - if (!wp_triggers_after) - { - StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo(); - assert (stored_stop_info_sp.get() == this); - - ThreadPlanSP new_plan_sp(thread_sp->QueueThreadPlanForStepSingleInstruction(false, // step-over - false, // abort_other_plans - true)); // stop_other_threads - new_plan_sp->SetIsMasterPlan (true); - new_plan_sp->SetOkayToDiscard (false); - new_plan_sp->SetPrivate (true); - process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID()); - process->ResumeSynchronous(nullptr); - process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID()); - thread_sp->SetStopInfo(stored_stop_info_sp); - } - } - } - } - - /* - * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For example: - * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at 'm', then - * watch exception is generated even when 'n' is read/written. To handle this case, - * server emulates the instruction at PC and finds the base address of the load/store - * instruction and appends it in the description of the stop-info packet. If watchpoint - * is not set on this address by user then this do not stop. - */ - if (m_watch_hit_addr != LLDB_INVALID_ADDRESS) - { - WatchpointSP wp_hit_sp = thread_sp->CalculateTarget()->GetWatchpointList().FindByAddress(m_watch_hit_addr); - if (!wp_hit_sp) - { - m_should_stop = false; - wp_sp->IncrementFalseAlarmsAndReviseHitCount(); - } - } + // If the condition says to stop, we run the callback to further decide + // whether to stop. + if (m_should_stop) { + StoppointCallbackContext context(event_ptr, exe_ctx, false); + bool stop_requested = wp_sp->InvokeCallback(&context); + // Also make sure that the callback hasn't continued the target. + // If it did, when we'll set m_should_stop to false and get out of + // here. + if (HasTargetRunSinceMe()) + m_should_stop = false; + + if (m_should_stop && !stop_requested) { + // We have been vetoed by the callback mechanism. + m_should_stop = false; + } + } + // Finally, if we are going to stop, print out the new & old values: + if (m_should_stop) { + wp_sp->CaptureWatchedValue(exe_ctx); + + Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); + StreamSP output_sp = debugger.GetAsyncOutputStream(); + wp_sp->DumpSnapshots(output_sp.get()); + output_sp->EOL(); + output_sp->Flush(); + } - // TODO: This condition should be checked in the synchronous part of the watchpoint code - // (Watchpoint::ShouldStop), so that we avoid pulling an event even if the watchpoint fails - // the ignore count condition. It is moved here temporarily, because for archs with - // watchpoint_exceptions_received=before, the code in the previous lines takes care of moving - // the inferior to next PC. We have to check the ignore count condition after this is done, - // otherwise we will hit same watchpoint multiple times until we pass ignore condition, but we - // won't actually be ignoring them. - if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount()) - m_should_stop = false; - - if (m_should_stop && wp_sp->GetConditionText() != nullptr) - { - // We need to make sure the user sees any parse errors in their condition, so we'll hook the - // constructor errors up to the debugger's Async I/O. - ExpressionResults result_code; - EvaluateExpressionOptions expr_options; - expr_options.SetUnwindOnError(true); - expr_options.SetIgnoreBreakpoints(true); - ValueObjectSP result_value_sp; - Error error; - result_code = UserExpression::Evaluate(exe_ctx, - expr_options, - wp_sp->GetConditionText(), - nullptr, - result_value_sp, - error); - - if (result_code == eExpressionCompleted) - { - if (result_value_sp) - { - Scalar scalar_value; - if (result_value_sp->ResolveValue (scalar_value)) - { - if (scalar_value.ULongLong(1) == 0) - { - // We have been vetoed. This takes precedence over querying - // the watchpoint whether it should stop (aka ignore count and - // friends). See also StopInfoWatchpoint::ShouldStop() as well - // as Process::ProcessEventData::DoOnRemoval(). - m_should_stop = false; - } - else - m_should_stop = true; - if (log) - log->Printf("Condition successfully evaluated, result is %s.\n", - m_should_stop ? "true" : "false"); - } - else - { - m_should_stop = true; - if (log) - log->Printf("Failed to get an integer result from the expression."); - } - } - } - else - { - Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); - StreamSP error_sp = debugger.GetAsyncErrorStream (); - error_sp->Printf ("Stopped due to an error evaluating condition of watchpoint "); - wp_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief); - error_sp->Printf (": \"%s\"", - wp_sp->GetConditionText()); - error_sp->EOL(); - const char *err_str = error.AsCString("<Unknown Error>"); - if (log) - log->Printf("Error evaluating condition: \"%s\"\n", err_str); - - error_sp->PutCString (err_str); - error_sp->EOL(); - error_sp->Flush(); - // If the condition fails to be parsed or run, we should stop. - m_should_stop = true; - } - } + } else { + Log *log_process( + lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS)); - // If the condition says to stop, we run the callback to further decide whether to stop. - if (m_should_stop) - { - StoppointCallbackContext context (event_ptr, exe_ctx, false); - bool stop_requested = wp_sp->InvokeCallback (&context); - // Also make sure that the callback hasn't continued the target. - // If it did, when we'll set m_should_stop to false and get out of here. - if (HasTargetRunSinceMe ()) - m_should_stop = false; - - if (m_should_stop && !stop_requested) - { - // We have been vetoed by the callback mechanism. - m_should_stop = false; - } - } - // Finally, if we are going to stop, print out the new & old values: - if (m_should_stop) - { - wp_sp->CaptureWatchedValue(exe_ctx); - - Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger(); - StreamSP output_sp = debugger.GetAsyncOutputStream (); - wp_sp->DumpSnapshots(output_sp.get()); - output_sp->EOL(); - output_sp->Flush(); - } - - } - else - { - Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS)); + if (log_process) + log_process->Printf( + "Process::%s could not find watchpoint id: %" PRId64 "...", + __FUNCTION__, m_value); + } + if (log) + log->Printf("Process::%s returning from action with m_should_stop: %d.", + __FUNCTION__, m_should_stop); - if (log_process) - log_process->Printf ("Process::%s could not find watchpoint id: %" PRId64 "...", __FUNCTION__, m_value); - } - if (log) - log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop); - - m_should_stop_is_valid = true; - } + m_should_stop_is_valid = true; } - + } + private: - bool m_should_stop; - bool m_should_stop_is_valid; - lldb::addr_t m_watch_hit_addr; + bool m_should_stop; + bool m_should_stop_is_valid; + lldb::addr_t m_watch_hit_addr; }; //---------------------------------------------------------------------- // StopInfoUnixSignal //---------------------------------------------------------------------- -class StopInfoUnixSignal : public StopInfo -{ +class StopInfoUnixSignal : public StopInfo { public: - StopInfoUnixSignal (Thread &thread, int signo, const char *description) : - StopInfo (thread, signo) - { - SetDescription (description); - } - - ~StopInfoUnixSignal() override = default; + StopInfoUnixSignal(Thread &thread, int signo, const char *description) + : StopInfo(thread, signo) { + SetDescription(description); + } - StopReason - GetStopReason() const override - { - return eStopReasonSignal; - } + ~StopInfoUnixSignal() override = default; - bool - ShouldStopSynchronous(Event *event_ptr) override - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); - return false; - } + StopReason GetStopReason() const override { return eStopReasonSignal; } - bool - ShouldStop(Event *event_ptr) override - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); - return false; - } + bool ShouldStopSynchronous(Event *event_ptr) override { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); + return false; + } - // If should stop returns false, check if we should notify of this event - bool - DoShouldNotify(Event *event_ptr) override - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - bool should_notify = thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value); - if (should_notify) - { - StreamString strm; - strm.Printf ("thread %d received signal: %s", - thread_sp->GetIndexID(), - thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(m_value)); - Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData()); - } - return should_notify; - } - return true; + bool ShouldStop(Event *event_ptr) override { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value); + return false; + } + + // If should stop returns false, check if we should notify of this event + bool DoShouldNotify(Event *event_ptr) override { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + bool should_notify = + thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value); + if (should_notify) { + StreamString strm; + strm.Printf( + "thread %d received signal: %s", thread_sp->GetIndexID(), + thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString( + m_value)); + Process::ProcessEventData::AddRestartedReason(event_ptr, + strm.GetData()); + } + return should_notify; } - - void - WillResume(lldb::StateType resume_state) override - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress(m_value)) - thread_sp->SetResumeSignal(m_value); - } + return true; + } + + void WillResume(lldb::StateType resume_state) override { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress( + m_value)) + thread_sp->SetResumeSignal(m_value); } - - const char * - GetDescription() override - { - if (m_description.empty()) - { - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - { - StreamString strm; - const char *signal_name = thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(m_value); - if (signal_name) - strm.Printf("signal %s", signal_name); - else - strm.Printf("signal %" PRIi64, m_value); - m_description.swap (strm.GetString()); - } - } - return m_description.c_str(); + } + + const char *GetDescription() override { + if (m_description.empty()) { + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) { + StreamString strm; + const char *signal_name = + thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString( + m_value); + if (signal_name) + strm.Printf("signal %s", signal_name); + else + strm.Printf("signal %" PRIi64, m_value); + m_description.swap(strm.GetString()); + } } + return m_description.c_str(); + } }; //---------------------------------------------------------------------- // StopInfoTrace //---------------------------------------------------------------------- -class StopInfoTrace : public StopInfo -{ +class StopInfoTrace : public StopInfo { public: - StopInfoTrace (Thread &thread) : - StopInfo (thread, LLDB_INVALID_UID) - { - } + StopInfoTrace(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {} - ~StopInfoTrace() override = default; + ~StopInfoTrace() override = default; - StopReason - GetStopReason() const override - { - return eStopReasonTrace; - } + StopReason GetStopReason() const override { return eStopReasonTrace; } - const char * - GetDescription() override - { - if (m_description.empty()) - return "trace"; - else - return m_description.c_str(); - } + const char *GetDescription() override { + if (m_description.empty()) + return "trace"; + else + return m_description.c_str(); + } }; //---------------------------------------------------------------------- // StopInfoException //---------------------------------------------------------------------- -class StopInfoException : public StopInfo -{ +class StopInfoException : public StopInfo { public: - StopInfoException (Thread &thread, const char *description) : - StopInfo (thread, LLDB_INVALID_UID) - { - if (description) - SetDescription (description); - } + StopInfoException(Thread &thread, const char *description) + : StopInfo(thread, LLDB_INVALID_UID) { + if (description) + SetDescription(description); + } - ~StopInfoException() override = default; + ~StopInfoException() override = default; - StopReason - GetStopReason() const override - { - return eStopReasonException; - } - - const char * - GetDescription() override - { - if (m_description.empty()) - return "exception"; - else - return m_description.c_str(); - } + StopReason GetStopReason() const override { return eStopReasonException; } + + const char *GetDescription() override { + if (m_description.empty()) + return "exception"; + else + return m_description.c_str(); + } }; //---------------------------------------------------------------------- // StopInfoThreadPlan //---------------------------------------------------------------------- -class StopInfoThreadPlan : public StopInfo -{ +class StopInfoThreadPlan : public StopInfo { public: - StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, ExpressionVariableSP &expression_variable_sp) : - StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID), - m_plan_sp (plan_sp), - m_return_valobj_sp (return_valobj_sp), - m_expression_variable_sp (expression_variable_sp) - { - } + StopInfoThreadPlan(ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, + ExpressionVariableSP &expression_variable_sp) + : StopInfo(plan_sp->GetThread(), LLDB_INVALID_UID), m_plan_sp(plan_sp), + m_return_valobj_sp(return_valobj_sp), + m_expression_variable_sp(expression_variable_sp) {} - ~StopInfoThreadPlan() override = default; + ~StopInfoThreadPlan() override = default; - StopReason - GetStopReason() const override - { - return eStopReasonPlanComplete; - } + StopReason GetStopReason() const override { return eStopReasonPlanComplete; } - const char * - GetDescription() override - { - if (m_description.empty()) - { - StreamString strm; - m_plan_sp->GetDescription (&strm, eDescriptionLevelBrief); - m_description.swap (strm.GetString()); - } - return m_description.c_str(); - } - - ValueObjectSP - GetReturnValueObject() - { - return m_return_valobj_sp; + const char *GetDescription() override { + if (m_description.empty()) { + StreamString strm; + m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief); + m_description.swap(strm.GetString()); } - - ExpressionVariableSP - GetExpressionVariable() - { - return m_expression_variable_sp; - } - + return m_description.c_str(); + } + + ValueObjectSP GetReturnValueObject() { return m_return_valobj_sp; } + + ExpressionVariableSP GetExpressionVariable() { + return m_expression_variable_sp; + } + protected: - bool - ShouldStop(Event *event_ptr) override - { - if (m_plan_sp) - return m_plan_sp->ShouldStop(event_ptr); - else - return StopInfo::ShouldStop(event_ptr); - } + bool ShouldStop(Event *event_ptr) override { + if (m_plan_sp) + return m_plan_sp->ShouldStop(event_ptr); + else + return StopInfo::ShouldStop(event_ptr); + } private: - ThreadPlanSP m_plan_sp; - ValueObjectSP m_return_valobj_sp; - ExpressionVariableSP m_expression_variable_sp; + ThreadPlanSP m_plan_sp; + ValueObjectSP m_return_valobj_sp; + ExpressionVariableSP m_expression_variable_sp; }; - -class StopInfoExec : public StopInfo -{ + +class StopInfoExec : public StopInfo { public: - StopInfoExec (Thread &thread) : - StopInfo (thread, LLDB_INVALID_UID), - m_performed_action (false) - { - } + StopInfoExec(Thread &thread) + : StopInfo(thread, LLDB_INVALID_UID), m_performed_action(false) {} - ~StopInfoExec() override = default; + ~StopInfoExec() override = default; - StopReason - GetStopReason() const override - { - return eStopReasonExec; - } - - const char * - GetDescription() override - { - return "exec"; - } + StopReason GetStopReason() const override { return eStopReasonExec; } + + const char *GetDescription() override { return "exec"; } protected: - void - PerformAction(Event *event_ptr) override - { - // Only perform the action once - if (m_performed_action) - return; - m_performed_action = true; - ThreadSP thread_sp (m_thread_wp.lock()); - if (thread_sp) - thread_sp->GetProcess()->DidExec(); - } - - bool m_performed_action; + void PerformAction(Event *event_ptr) override { + // Only perform the action once + if (m_performed_action) + return; + m_performed_action = true; + ThreadSP thread_sp(m_thread_wp.lock()); + if (thread_sp) + thread_sp->GetProcess()->DidExec(); + } + + bool m_performed_action; }; } // namespace lldb_private -StopInfoSP -StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id) -{ - return StopInfoSP (new StopInfoBreakpoint (thread, break_id)); +StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, + break_id_t break_id) { + return StopInfoSP(new StopInfoBreakpoint(thread, break_id)); } -StopInfoSP -StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id, bool should_stop) -{ - return StopInfoSP (new StopInfoBreakpoint (thread, break_id, should_stop)); +StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread, + break_id_t break_id, + bool should_stop) { + return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop)); } StopInfoSP -StopInfo::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr) -{ - return StopInfoSP (new StopInfoWatchpoint (thread, watch_id, watch_hit_addr)); +StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id, + lldb::addr_t watch_hit_addr) { + return StopInfoSP(new StopInfoWatchpoint(thread, watch_id, watch_hit_addr)); } -StopInfoSP -StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo, const char *description) -{ - return StopInfoSP (new StopInfoUnixSignal (thread, signo, description)); +StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo, + const char *description) { + return StopInfoSP(new StopInfoUnixSignal(thread, signo, description)); } -StopInfoSP -StopInfo::CreateStopReasonToTrace (Thread &thread) -{ - return StopInfoSP (new StopInfoTrace (thread)); +StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) { + return StopInfoSP(new StopInfoTrace(thread)); } -StopInfoSP -StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, - ValueObjectSP return_valobj_sp, - ExpressionVariableSP expression_variable_sp) -{ - return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp, expression_variable_sp)); +StopInfoSP StopInfo::CreateStopReasonWithPlan( + ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp, + ExpressionVariableSP expression_variable_sp) { + return StopInfoSP(new StopInfoThreadPlan(plan_sp, return_valobj_sp, + expression_variable_sp)); } -StopInfoSP -StopInfo::CreateStopReasonWithException (Thread &thread, const char *description) -{ - return StopInfoSP (new StopInfoException (thread, description)); +StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread, + const char *description) { + return StopInfoSP(new StopInfoException(thread, description)); } -StopInfoSP -StopInfo::CreateStopReasonWithExec (Thread &thread) -{ - return StopInfoSP (new StopInfoExec (thread)); +StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) { + return StopInfoSP(new StopInfoExec(thread)); } -ValueObjectSP -StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) -{ - if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete) - { - StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); - return plan_stop_info->GetReturnValueObject(); - } - else - return ValueObjectSP(); +ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) { + if (stop_info_sp && + stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { + StopInfoThreadPlan *plan_stop_info = + static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); + return plan_stop_info->GetReturnValueObject(); + } else + return ValueObjectSP(); } -ExpressionVariableSP -StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) -{ - if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete) - { - StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); - return plan_stop_info->GetExpressionVariable(); - } - else - return ExpressionVariableSP(); +ExpressionVariableSP StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) { + if (stop_info_sp && + stop_info_sp->GetStopReason() == eStopReasonPlanComplete) { + StopInfoThreadPlan *plan_stop_info = + static_cast<StopInfoThreadPlan *>(stop_info_sp.get()); + return plan_stop_info->GetExpressionVariable(); + } else + return ExpressionVariableSP(); } lldb::ValueObjectSP -StopInfo::GetCrashingDereference (StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address) -{ - if (!stop_info_sp) - { - return ValueObjectSP(); - } - - const char *description = stop_info_sp->GetDescription(); - if (!description) - { - return ValueObjectSP(); - } - - ThreadSP thread_sp = stop_info_sp->GetThread(); - if (!thread_sp) - { - return ValueObjectSP(); - } - - StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); - - if (!frame_sp) - { - return ValueObjectSP(); - } +StopInfo::GetCrashingDereference(StopInfoSP &stop_info_sp, + lldb::addr_t *crashing_address) { + if (!stop_info_sp) { + return ValueObjectSP(); + } - const char address_string[] = "address="; - - const char *address_loc = strstr(description, address_string); - if (!address_loc) - { - return ValueObjectSP(); - } - - address_loc += (sizeof(address_string) - 1); - - uint64_t address = strtoull(address_loc, 0, 0); - if (crashing_address) - { - *crashing_address = address; - } - - return frame_sp->GuessValueForAddress(address); + const char *description = stop_info_sp->GetDescription(); + if (!description) { + return ValueObjectSP(); + } + + ThreadSP thread_sp = stop_info_sp->GetThread(); + if (!thread_sp) { + return ValueObjectSP(); + } + + StackFrameSP frame_sp = thread_sp->GetSelectedFrame(); + + if (!frame_sp) { + return ValueObjectSP(); + } + + const char address_string[] = "address="; + + const char *address_loc = strstr(description, address_string); + if (!address_loc) { + return ValueObjectSP(); + } + + address_loc += (sizeof(address_string) - 1); + + uint64_t address = strtoull(address_loc, 0, 0); + if (crashing_address) { + *crashing_address = address; + } + + return frame_sp->GuessValueForAddress(address); } diff --git a/lldb/source/Target/StructuredDataPlugin.cpp b/lldb/source/Target/StructuredDataPlugin.cpp index 6cc5ed1792b..fe267e5e45a 100644 --- a/lldb/source/Target/StructuredDataPlugin.cpp +++ b/lldb/source/Target/StructuredDataPlugin.cpp @@ -16,75 +16,53 @@ using namespace lldb; using namespace lldb_private; -namespace -{ - class CommandStructuredData : public CommandObjectMultiword - { - public: - CommandStructuredData(CommandInterpreter &interpreter) : - CommandObjectMultiword(interpreter, - "structured-data", +namespace { +class CommandStructuredData : public CommandObjectMultiword { +public: + CommandStructuredData(CommandInterpreter &interpreter) + : CommandObjectMultiword(interpreter, "structured-data", "Parent for per-plugin structured data commands", - "plugin structured-data <plugin>") - { - } + "plugin structured-data <plugin>") {} - ~CommandStructuredData() - { - } - }; + ~CommandStructuredData() {} +}; } -StructuredDataPlugin::StructuredDataPlugin(const ProcessWP &process_wp) : - PluginInterface(), - m_process_wp(process_wp) -{ -} +StructuredDataPlugin::StructuredDataPlugin(const ProcessWP &process_wp) + : PluginInterface(), m_process_wp(process_wp) {} -StructuredDataPlugin::~StructuredDataPlugin() -{ -} +StructuredDataPlugin::~StructuredDataPlugin() {} -bool -StructuredDataPlugin::GetEnabled(const ConstString &type_name) const -{ - // By default, plugins are always enabled. Plugin authors should override - // this if there is an enabled/disabled state for their plugin. - return true; +bool StructuredDataPlugin::GetEnabled(const ConstString &type_name) const { + // By default, plugins are always enabled. Plugin authors should override + // this if there is an enabled/disabled state for their plugin. + return true; } -ProcessSP -StructuredDataPlugin::GetProcess() const -{ - return m_process_wp.lock(); +ProcessSP StructuredDataPlugin::GetProcess() const { + return m_process_wp.lock(); } -void -StructuredDataPlugin::InitializeBasePluginForDebugger(Debugger &debugger) -{ - // Create our mutliword command anchor if it doesn't already exist. - auto &interpreter = debugger.GetCommandInterpreter(); - if (!interpreter.GetCommandObject("plugin structured-data")) - { - // Find the parent command. - auto parent_command = - debugger.GetCommandInterpreter().GetCommandObject("plugin"); - if (!parent_command) - return; +void StructuredDataPlugin::InitializeBasePluginForDebugger(Debugger &debugger) { + // Create our mutliword command anchor if it doesn't already exist. + auto &interpreter = debugger.GetCommandInterpreter(); + if (!interpreter.GetCommandObject("plugin structured-data")) { + // Find the parent command. + auto parent_command = + debugger.GetCommandInterpreter().GetCommandObject("plugin"); + if (!parent_command) + return; - // Create the structured-data ommand object. - auto command_name = "structured-data"; - auto command_sp = - CommandObjectSP(new CommandStructuredData(interpreter)); + // Create the structured-data ommand object. + auto command_name = "structured-data"; + auto command_sp = CommandObjectSP(new CommandStructuredData(interpreter)); - // Hook it up under the top-level plugin command. - parent_command->LoadSubCommand(command_name, - command_sp); - } + // Hook it up under the top-level plugin command. + parent_command->LoadSubCommand(command_name, command_sp); + } } -void -StructuredDataPlugin::ModulesDidLoad(Process &process, ModuleList &module_list) -{ - // Default implementation does nothing. +void StructuredDataPlugin::ModulesDidLoad(Process &process, + ModuleList &module_list) { + // Default implementation does nothing. } diff --git a/lldb/source/Target/SystemRuntime.cpp b/lldb/source/Target/SystemRuntime.cpp index 522b535039f..3fdf6daa6af 100644 --- a/lldb/source/Target/SystemRuntime.cpp +++ b/lldb/source/Target/SystemRuntime.cpp @@ -11,66 +11,48 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" #include "lldb/Target/SystemRuntime.h" -#include "lldb/Target/Process.h" #include "lldb/Core/PluginManager.h" +#include "lldb/Target/Process.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; -SystemRuntime* -SystemRuntime::FindPlugin (Process *process) -{ - SystemRuntimeCreateInstance create_callback = nullptr; - for (uint32_t idx = 0; (create_callback = PluginManager::GetSystemRuntimeCreateCallbackAtIndex(idx)) != nullptr; ++idx) - { - std::unique_ptr<SystemRuntime> instance_ap(create_callback(process)); - if (instance_ap) - return instance_ap.release(); - } - return nullptr; +SystemRuntime *SystemRuntime::FindPlugin(Process *process) { + SystemRuntimeCreateInstance create_callback = nullptr; + for (uint32_t idx = 0; + (create_callback = PluginManager::GetSystemRuntimeCreateCallbackAtIndex( + idx)) != nullptr; + ++idx) { + std::unique_ptr<SystemRuntime> instance_ap(create_callback(process)); + if (instance_ap) + return instance_ap.release(); + } + return nullptr; } //---------------------------------------------------------------------- // SystemRuntime constructor //---------------------------------------------------------------------- -SystemRuntime::SystemRuntime(Process *process) : - m_process (process), - m_types () -{ -} +SystemRuntime::SystemRuntime(Process *process) + : m_process(process), m_types() {} SystemRuntime::~SystemRuntime() = default; -void -SystemRuntime::DidAttach () -{ -} +void SystemRuntime::DidAttach() {} -void -SystemRuntime::DidLaunch() -{ -} +void SystemRuntime::DidLaunch() {} -void -SystemRuntime::Detach() -{ -} +void SystemRuntime::Detach() {} -void -SystemRuntime::ModulesDidLoad (ModuleList &module_list) -{ -} +void SystemRuntime::ModulesDidLoad(ModuleList &module_list) {} -const std::vector<ConstString> & -SystemRuntime::GetExtendedBacktraceTypes () -{ - return m_types; +const std::vector<ConstString> &SystemRuntime::GetExtendedBacktraceTypes() { + return m_types; } -ThreadSP -SystemRuntime::GetExtendedBacktraceThread (ThreadSP thread, ConstString type) -{ - return ThreadSP(); +ThreadSP SystemRuntime::GetExtendedBacktraceThread(ThreadSP thread, + ConstString type) { + return ThreadSP(); } diff --git a/lldb/source/Target/Target.cpp b/lldb/source/Target/Target.cpp index ead555a757e..bd8ae563319 100644 --- a/lldb/source/Target/Target.cpp +++ b/lldb/source/Target/Target.cpp @@ -12,7 +12,9 @@ #include <mutex> // Other libraries and framework includes // Project includes -#include "lldb/Target/Target.h" +#include "Plugins/ExpressionParser/Clang/ClangASTSource.h" +#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" +#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" #include "lldb/Breakpoint/BreakpointResolver.h" #include "lldb/Breakpoint/BreakpointResolverAddress.h" #include "lldb/Breakpoint/BreakpointResolverFileLine.h" @@ -33,9 +35,6 @@ #include "lldb/Core/ValueObject.h" #include "lldb/Expression/REPL.h" #include "lldb/Expression/UserExpression.h" -#include "Plugins/ExpressionParser/Clang/ClangASTSource.h" -#include "Plugins/ExpressionParser/Clang/ClangPersistentVariables.h" -#include "Plugins/ExpressionParser/Clang/ClangModulesDeclVendor.h" #include "lldb/Host/FileSpec.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/CommandInterpreter.h" @@ -44,8 +43,8 @@ #include "lldb/Interpreter/OptionValues.h" #include "lldb/Interpreter/Property.h" #include "lldb/Symbol/ClangASTContext.h" -#include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Function.h" +#include "lldb/Symbol/ObjectFile.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/Language.h" #include "lldb/Target/LanguageRuntime.h" @@ -54,6 +53,7 @@ #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/StackFrame.h" #include "lldb/Target/SystemRuntime.h" +#include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadSpec.h" #include "lldb/Utility/LLDBAssert.h" @@ -61,862 +61,737 @@ using namespace lldb; using namespace lldb_private; -ConstString & -Target::GetStaticBroadcasterClass () -{ - static ConstString class_name ("lldb.target"); - return class_name; +ConstString &Target::GetStaticBroadcasterClass() { + static ConstString class_name("lldb.target"); + return class_name; } -Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp, - bool is_dummy_target) +Target::Target(Debugger &debugger, const ArchSpec &target_arch, + const lldb::PlatformSP &platform_sp, bool is_dummy_target) : TargetProperties(this), - Broadcaster(debugger.GetBroadcasterManager(), Target::GetStaticBroadcasterClass().AsCString()), - ExecutionContextScope(), - m_debugger(debugger), - m_platform_sp(platform_sp), - m_mutex(), - m_arch(target_arch), - m_images(this), - m_section_load_history(), - m_breakpoint_list(false), - m_internal_breakpoint_list(true), - m_watchpoint_list(), - m_process_sp(), - m_search_filter_sp(), - m_image_search_paths(ImageSearchPathsChanged, this), - m_ast_importer_sp(), - m_source_manager_ap(), - m_stop_hooks(), - m_stop_hook_next_id(0), - m_valid(true), - m_suppress_stop_hooks(false), + Broadcaster(debugger.GetBroadcasterManager(), + Target::GetStaticBroadcasterClass().AsCString()), + ExecutionContextScope(), m_debugger(debugger), m_platform_sp(platform_sp), + m_mutex(), m_arch(target_arch), m_images(this), m_section_load_history(), + m_breakpoint_list(false), m_internal_breakpoint_list(true), + m_watchpoint_list(), m_process_sp(), m_search_filter_sp(), + m_image_search_paths(ImageSearchPathsChanged, this), m_ast_importer_sp(), + m_source_manager_ap(), m_stop_hooks(), m_stop_hook_next_id(0), + m_valid(true), m_suppress_stop_hooks(false), m_is_dummy_target(is_dummy_target) { - SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed"); - SetEventName(eBroadcastBitModulesLoaded, "modules-loaded"); - SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded"); - SetEventName(eBroadcastBitWatchpointChanged, "watchpoint-changed"); - SetEventName(eBroadcastBitSymbolsLoaded, "symbols-loaded"); + SetEventName(eBroadcastBitBreakpointChanged, "breakpoint-changed"); + SetEventName(eBroadcastBitModulesLoaded, "modules-loaded"); + SetEventName(eBroadcastBitModulesUnloaded, "modules-unloaded"); + SetEventName(eBroadcastBitWatchpointChanged, "watchpoint-changed"); + SetEventName(eBroadcastBitSymbolsLoaded, "symbols-loaded"); + + CheckInWithManager(); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Target::Target()", static_cast<void *>(this)); + if (m_arch.IsValid()) { + LogIfAnyCategoriesSet( + LIBLLDB_LOG_TARGET, "Target::Target created with architecture %s (%s)", + m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str()); + } +} + +Target::~Target() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Target::~Target()", static_cast<void *>(this)); + DeleteCurrentProcess(); +} + +void Target::PrimeFromDummyTarget(Target *target) { + if (!target) + return; + + m_stop_hooks = target->m_stop_hooks; + + for (BreakpointSP breakpoint_sp : target->m_breakpoint_list.Breakpoints()) { + if (breakpoint_sp->IsInternal()) + continue; + + BreakpointSP new_bp(new Breakpoint(*this, *breakpoint_sp.get())); + AddBreakpoint(new_bp, false); + } +} + +void Target::Dump(Stream *s, lldb::DescriptionLevel description_level) { + // s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); + if (description_level != lldb::eDescriptionLevelBrief) { + s->Indent(); + s->PutCString("Target\n"); + s->IndentMore(); + m_images.Dump(s); + m_breakpoint_list.Dump(s); + m_internal_breakpoint_list.Dump(s); + s->IndentLess(); + } else { + Module *exe_module = GetExecutableModulePointer(); + if (exe_module) + s->PutCString(exe_module->GetFileSpec().GetFilename().GetCString()); + else + s->PutCString("No executable module."); + } +} + +void Target::CleanupProcess() { + // Do any cleanup of the target we need to do between process instances. + // NB It is better to do this before destroying the process in case the + // clean up needs some help from the process. + m_breakpoint_list.ClearAllBreakpointSites(); + m_internal_breakpoint_list.ClearAllBreakpointSites(); + // Disable watchpoints just on the debugger side. + std::unique_lock<std::recursive_mutex> lock; + this->GetWatchpointList().GetListMutex(lock); + DisableAllWatchpoints(false); + ClearAllWatchpointHitCounts(); + ClearAllWatchpointHistoricValues(); +} + +void Target::DeleteCurrentProcess() { + if (m_process_sp) { + m_section_load_history.Clear(); + if (m_process_sp->IsAlive()) + m_process_sp->Destroy(false); - CheckInWithManager(); + m_process_sp->Finalize(); - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p Target::Target()", static_cast<void *>(this)); - if (m_arch.IsValid()) - { - LogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET, "Target::Target created with architecture %s (%s)", - m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str()); - } -} + CleanupProcess(); -Target::~Target() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf ("%p Target::~Target()", static_cast<void*>(this)); - DeleteCurrentProcess (); + m_process_sp.reset(); + } } -void -Target::PrimeFromDummyTarget(Target *target) -{ - if (!target) - return; - - m_stop_hooks = target->m_stop_hooks; - - for (BreakpointSP breakpoint_sp : target->m_breakpoint_list.Breakpoints()) - { - if (breakpoint_sp->IsInternal()) - continue; - - BreakpointSP new_bp (new Breakpoint (*this, *breakpoint_sp.get())); - AddBreakpoint (new_bp, false); - } +const lldb::ProcessSP &Target::CreateProcess(ListenerSP listener_sp, + const char *plugin_name, + const FileSpec *crash_file) { + DeleteCurrentProcess(); + m_process_sp = Process::FindPlugin(shared_from_this(), plugin_name, + listener_sp, crash_file); + return m_process_sp; } -void -Target::Dump (Stream *s, lldb::DescriptionLevel description_level) -{ -// s->Printf("%.*p: ", (int)sizeof(void*) * 2, this); - if (description_level != lldb::eDescriptionLevelBrief) - { - s->Indent(); - s->PutCString("Target\n"); - s->IndentMore(); - m_images.Dump(s); - m_breakpoint_list.Dump(s); - m_internal_breakpoint_list.Dump(s); - s->IndentLess(); - } - else - { - Module *exe_module = GetExecutableModulePointer(); - if (exe_module) - s->PutCString (exe_module->GetFileSpec().GetFilename().GetCString()); - else - s->PutCString ("No executable module."); - } -} +const lldb::ProcessSP &Target::GetProcessSP() const { return m_process_sp; } -void -Target::CleanupProcess () -{ - // Do any cleanup of the target we need to do between process instances. - // NB It is better to do this before destroying the process in case the - // clean up needs some help from the process. - m_breakpoint_list.ClearAllBreakpointSites(); - m_internal_breakpoint_list.ClearAllBreakpointSites(); - // Disable watchpoints just on the debugger side. - std::unique_lock<std::recursive_mutex> lock; - this->GetWatchpointList().GetListMutex(lock); - DisableAllWatchpoints(false); - ClearAllWatchpointHitCounts(); - ClearAllWatchpointHistoricValues(); -} - -void -Target::DeleteCurrentProcess () -{ - if (m_process_sp) - { - m_section_load_history.Clear(); - if (m_process_sp->IsAlive()) - m_process_sp->Destroy(false); - - m_process_sp->Finalize(); +lldb::REPLSP Target::GetREPL(Error &err, lldb::LanguageType language, + const char *repl_options, bool can_create) { + if (language == eLanguageTypeUnknown) { + std::set<LanguageType> repl_languages; - CleanupProcess (); + Language::GetLanguagesSupportingREPLs(repl_languages); - m_process_sp.reset(); + if (repl_languages.size() == 1) { + language = *repl_languages.begin(); + } else if (repl_languages.size() == 0) { + err.SetErrorStringWithFormat( + "LLDB isn't configured with REPL support for any languages."); + return REPLSP(); + } else { + err.SetErrorStringWithFormat( + "Multiple possible REPL languages. Please specify a language."); + return REPLSP(); } -} + } -const lldb::ProcessSP & -Target::CreateProcess (ListenerSP listener_sp, const char *plugin_name, const FileSpec *crash_file) -{ - DeleteCurrentProcess (); - m_process_sp = Process::FindPlugin(shared_from_this(), plugin_name, listener_sp, crash_file); - return m_process_sp; -} + REPLMap::iterator pos = m_repl_map.find(language); -const lldb::ProcessSP & -Target::GetProcessSP () const -{ - return m_process_sp; -} + if (pos != m_repl_map.end()) { + return pos->second; + } -lldb::REPLSP -Target::GetREPL (Error &err, lldb::LanguageType language, const char *repl_options, bool can_create) -{ - if (language == eLanguageTypeUnknown) - { - std::set<LanguageType> repl_languages; - - Language::GetLanguagesSupportingREPLs(repl_languages); - - if (repl_languages.size() == 1) - { - language = *repl_languages.begin(); - } - else if (repl_languages.size() == 0) - { - err.SetErrorStringWithFormat("LLDB isn't configured with REPL support for any languages."); - return REPLSP(); - } - else - { - err.SetErrorStringWithFormat("Multiple possible REPL languages. Please specify a language."); - return REPLSP(); - } - } - - REPLMap::iterator pos = m_repl_map.find(language); - - if (pos != m_repl_map.end()) - { - return pos->second; - } - - if (!can_create) - { - err.SetErrorStringWithFormat("Couldn't find an existing REPL for %s, and can't create a new one", Language::GetNameForLanguageType(language)); - return lldb::REPLSP(); - } - - Debugger *const debugger = nullptr; - lldb::REPLSP ret = REPL::Create(err, language, debugger, this, repl_options); - - if (ret) - { - m_repl_map[language] = ret; - return m_repl_map[language]; - } - - if (err.Success()) - { - err.SetErrorStringWithFormat("Couldn't create a REPL for %s", Language::GetNameForLanguageType(language)); - } - + if (!can_create) { + err.SetErrorStringWithFormat( + "Couldn't find an existing REPL for %s, and can't create a new one", + Language::GetNameForLanguageType(language)); return lldb::REPLSP(); + } + + Debugger *const debugger = nullptr; + lldb::REPLSP ret = REPL::Create(err, language, debugger, this, repl_options); + + if (ret) { + m_repl_map[language] = ret; + return m_repl_map[language]; + } + + if (err.Success()) { + err.SetErrorStringWithFormat("Couldn't create a REPL for %s", + Language::GetNameForLanguageType(language)); + } + + return lldb::REPLSP(); +} + +void Target::SetREPL(lldb::LanguageType language, lldb::REPLSP repl_sp) { + lldbassert(!m_repl_map.count(language)); + + m_repl_map[language] = repl_sp; +} + +void Target::Destroy() { + std::lock_guard<std::recursive_mutex> guard(m_mutex); + m_valid = false; + DeleteCurrentProcess(); + m_platform_sp.reset(); + m_arch.Clear(); + ClearModules(true); + m_section_load_history.Clear(); + const bool notify = false; + m_breakpoint_list.RemoveAll(notify); + m_internal_breakpoint_list.RemoveAll(notify); + m_last_created_breakpoint.reset(); + m_last_created_watchpoint.reset(); + m_search_filter_sp.reset(); + m_image_search_paths.Clear(notify); + m_stop_hooks.clear(); + m_stop_hook_next_id = 0; + m_suppress_stop_hooks = false; +} + +BreakpointList &Target::GetBreakpointList(bool internal) { + if (internal) + return m_internal_breakpoint_list; + else + return m_breakpoint_list; +} + +const BreakpointList &Target::GetBreakpointList(bool internal) const { + if (internal) + return m_internal_breakpoint_list; + else + return m_breakpoint_list; +} + +BreakpointSP Target::GetBreakpointByID(break_id_t break_id) { + BreakpointSP bp_sp; + + if (LLDB_BREAK_ID_IS_INTERNAL(break_id)) + bp_sp = m_internal_breakpoint_list.FindBreakpointByID(break_id); + else + bp_sp = m_breakpoint_list.FindBreakpointByID(break_id); + + return bp_sp; +} + +BreakpointSP Target::CreateSourceRegexBreakpoint( + const FileSpecList *containingModules, + const FileSpecList *source_file_spec_list, + const std::unordered_set<std::string> &function_names, + RegularExpression &source_regex, bool internal, bool hardware, + LazyBool move_to_nearest_code) { + SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( + containingModules, source_file_spec_list)); + if (move_to_nearest_code == eLazyBoolCalculate) + move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; + BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex( + nullptr, source_regex, function_names, + !static_cast<bool>(move_to_nearest_code))); + + return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); +} + +BreakpointSP Target::CreateBreakpoint(const FileSpecList *containingModules, + const FileSpec &file, uint32_t line_no, + lldb::addr_t offset, + LazyBool check_inlines, + LazyBool skip_prologue, bool internal, + bool hardware, + LazyBool move_to_nearest_code) { + FileSpec remapped_file; + ConstString remapped_path; + if (GetSourcePathMap().ReverseRemapPath(ConstString(file.GetPath().c_str()), + remapped_path)) + remapped_file.SetFile(remapped_path.AsCString(), true); + else + remapped_file = file; + + if (check_inlines == eLazyBoolCalculate) { + const InlineStrategy inline_strategy = GetInlineStrategy(); + switch (inline_strategy) { + case eInlineBreakpointsNever: + check_inlines = eLazyBoolNo; + break; + + case eInlineBreakpointsHeaders: + if (remapped_file.IsSourceImplementationFile()) + check_inlines = eLazyBoolNo; + else + check_inlines = eLazyBoolYes; + break; + + case eInlineBreakpointsAlways: + check_inlines = eLazyBoolYes; + break; + } + } + SearchFilterSP filter_sp; + if (check_inlines == eLazyBoolNo) { + // Not checking for inlines, we are looking only for matching compile units + FileSpecList compile_unit_list; + compile_unit_list.Append(remapped_file); + filter_sp = GetSearchFilterForModuleAndCUList(containingModules, + &compile_unit_list); + } else { + filter_sp = GetSearchFilterForModuleList(containingModules); + } + if (skip_prologue == eLazyBoolCalculate) + skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; + if (move_to_nearest_code == eLazyBoolCalculate) + move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; + + BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine( + nullptr, remapped_file, line_no, offset, check_inlines, skip_prologue, + !static_cast<bool>(move_to_nearest_code))); + return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); +} + +BreakpointSP Target::CreateBreakpoint(lldb::addr_t addr, bool internal, + bool hardware) { + Address so_addr; + + // Check for any reason we want to move this breakpoint to other address. + addr = GetBreakableLoadAddress(addr); + + // Attempt to resolve our load address if possible, though it is ok if + // it doesn't resolve to section/offset. + + // Try and resolve as a load address if possible + GetSectionLoadList().ResolveLoadAddress(addr, so_addr); + if (!so_addr.IsValid()) { + // The address didn't resolve, so just set this as an absolute address + so_addr.SetOffset(addr); + } + BreakpointSP bp_sp(CreateBreakpoint(so_addr, internal, hardware)); + return bp_sp; +} + +BreakpointSP Target::CreateBreakpoint(const Address &addr, bool internal, + bool hardware) { + SearchFilterSP filter_sp( + new SearchFilterForUnconstrainedSearches(shared_from_this())); + BreakpointResolverSP resolver_sp( + new BreakpointResolverAddress(nullptr, addr)); + return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, false); } -void -Target::SetREPL (lldb::LanguageType language, lldb::REPLSP repl_sp) -{ - lldbassert(!m_repl_map.count(language)); - - m_repl_map[language] = repl_sp; -} - -void -Target::Destroy() -{ - std::lock_guard<std::recursive_mutex> guard(m_mutex); - m_valid = false; - DeleteCurrentProcess (); - m_platform_sp.reset(); - m_arch.Clear(); - ClearModules(true); - m_section_load_history.Clear(); - const bool notify = false; - m_breakpoint_list.RemoveAll(notify); - m_internal_breakpoint_list.RemoveAll(notify); - m_last_created_breakpoint.reset(); - m_last_created_watchpoint.reset(); - m_search_filter_sp.reset(); - m_image_search_paths.Clear(notify); - m_stop_hooks.clear(); - m_stop_hook_next_id = 0; - m_suppress_stop_hooks = false; -} - -BreakpointList & -Target::GetBreakpointList(bool internal) -{ - if (internal) - return m_internal_breakpoint_list; - else - return m_breakpoint_list; -} - -const BreakpointList & -Target::GetBreakpointList(bool internal) const -{ - if (internal) - return m_internal_breakpoint_list; - else - return m_breakpoint_list; -} - -BreakpointSP -Target::GetBreakpointByID (break_id_t break_id) -{ - BreakpointSP bp_sp; - - if (LLDB_BREAK_ID_IS_INTERNAL (break_id)) - bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id); - else - bp_sp = m_breakpoint_list.FindBreakpointByID (break_id); - - return bp_sp; +lldb::BreakpointSP +Target::CreateAddressInModuleBreakpoint(lldb::addr_t file_addr, bool internal, + const FileSpec *file_spec, + bool request_hardware) { + SearchFilterSP filter_sp( + new SearchFilterForUnconstrainedSearches(shared_from_this())); + BreakpointResolverSP resolver_sp( + new BreakpointResolverAddress(nullptr, file_addr, file_spec)); + return CreateBreakpoint(filter_sp, resolver_sp, internal, request_hardware, + false); } BreakpointSP -Target::CreateSourceRegexBreakpoint (const FileSpecList *containingModules, - const FileSpecList *source_file_spec_list, - const std::unordered_set<std::string> &function_names, - RegularExpression &source_regex, - bool internal, - bool hardware, - LazyBool move_to_nearest_code) -{ - SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, source_file_spec_list)); - if (move_to_nearest_code == eLazyBoolCalculate) - move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; - BreakpointResolverSP resolver_sp(new BreakpointResolverFileRegex(nullptr, - source_regex, - function_names, - !static_cast<bool>(move_to_nearest_code))); - - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); -} +Target::CreateBreakpoint(const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, + const char *func_name, uint32_t func_name_type_mask, + LanguageType language, lldb::addr_t offset, + LazyBool skip_prologue, bool internal, bool hardware) { + BreakpointSP bp_sp; + if (func_name) { + SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( + containingModules, containingSourceFiles)); -BreakpointSP -Target::CreateBreakpoint (const FileSpecList *containingModules, - const FileSpec &file, - uint32_t line_no, - lldb::addr_t offset, - LazyBool check_inlines, - LazyBool skip_prologue, - bool internal, - bool hardware, - LazyBool move_to_nearest_code) -{ - FileSpec remapped_file; - ConstString remapped_path; - if (GetSourcePathMap().ReverseRemapPath(ConstString(file.GetPath().c_str()), remapped_path)) - remapped_file.SetFile(remapped_path.AsCString(), true); - else - remapped_file = file; - - if (check_inlines == eLazyBoolCalculate) - { - const InlineStrategy inline_strategy = GetInlineStrategy(); - switch (inline_strategy) - { - case eInlineBreakpointsNever: - check_inlines = eLazyBoolNo; - break; - - case eInlineBreakpointsHeaders: - if (remapped_file.IsSourceImplementationFile()) - check_inlines = eLazyBoolNo; - else - check_inlines = eLazyBoolYes; - break; - - case eInlineBreakpointsAlways: - check_inlines = eLazyBoolYes; - break; - } - } - SearchFilterSP filter_sp; - if (check_inlines == eLazyBoolNo) - { - // Not checking for inlines, we are looking only for matching compile units - FileSpecList compile_unit_list; - compile_unit_list.Append (remapped_file); - filter_sp = GetSearchFilterForModuleAndCUList (containingModules, &compile_unit_list); - } - else - { - filter_sp = GetSearchFilterForModuleList (containingModules); - } if (skip_prologue == eLazyBoolCalculate) - skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; - if (move_to_nearest_code == eLazyBoolCalculate) - move_to_nearest_code = GetMoveToNearestCode() ? eLazyBoolYes : eLazyBoolNo; - - BreakpointResolverSP resolver_sp(new BreakpointResolverFileLine (nullptr, - remapped_file, - line_no, - offset, - check_inlines, - skip_prologue, - !static_cast<bool>(move_to_nearest_code))); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); -} + skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; + if (language == lldb::eLanguageTypeUnknown) + language = GetLanguage(); -BreakpointSP -Target::CreateBreakpoint (lldb::addr_t addr, bool internal, bool hardware) -{ - Address so_addr; - - // Check for any reason we want to move this breakpoint to other address. - addr = GetBreakableLoadAddress(addr); - - // Attempt to resolve our load address if possible, though it is ok if - // it doesn't resolve to section/offset. - - // Try and resolve as a load address if possible - GetSectionLoadList().ResolveLoadAddress(addr, so_addr); - if (!so_addr.IsValid()) - { - // The address didn't resolve, so just set this as an absolute address - so_addr.SetOffset (addr); - } - BreakpointSP bp_sp (CreateBreakpoint(so_addr, internal, hardware)); - return bp_sp; -} - -BreakpointSP -Target::CreateBreakpoint (const Address &addr, bool internal, bool hardware) -{ - SearchFilterSP filter_sp(new SearchFilterForUnconstrainedSearches (shared_from_this())); - BreakpointResolverSP resolver_sp(new BreakpointResolverAddress(nullptr, addr)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false); -} - -lldb::BreakpointSP -Target::CreateAddressInModuleBreakpoint (lldb::addr_t file_addr, - bool internal, - const FileSpec *file_spec, - bool request_hardware) -{ - SearchFilterSP filter_sp(new SearchFilterForUnconstrainedSearches (shared_from_this())); - BreakpointResolverSP resolver_sp(new BreakpointResolverAddress(nullptr, file_addr, file_spec)); - return CreateBreakpoint (filter_sp, resolver_sp, internal, request_hardware, false); -} - -BreakpointSP -Target::CreateBreakpoint (const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles, - const char *func_name, - uint32_t func_name_type_mask, - LanguageType language, - lldb::addr_t offset, - LazyBool skip_prologue, - bool internal, - bool hardware) -{ - BreakpointSP bp_sp; - if (func_name) - { - SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles)); - - if (skip_prologue == eLazyBoolCalculate) - skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; - if (language == lldb::eLanguageTypeUnknown) - language = GetLanguage(); - - BreakpointResolverSP resolver_sp (new BreakpointResolverName (nullptr, - func_name, - func_name_type_mask, - language, - Breakpoint::Exact, - offset, - skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); - } - return bp_sp; + BreakpointResolverSP resolver_sp(new BreakpointResolverName( + nullptr, func_name, func_name_type_mask, language, Breakpoint::Exact, + offset, skip_prologue)); + bp_sp = CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); + } + return bp_sp; } lldb::BreakpointSP -Target::CreateBreakpoint (const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles, - const std::vector<std::string> &func_names, - uint32_t func_name_type_mask, - LanguageType language, - lldb::addr_t offset, - LazyBool skip_prologue, - bool internal, - bool hardware) -{ - BreakpointSP bp_sp; - size_t num_names = func_names.size(); - if (num_names > 0) - { - SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles)); - - if (skip_prologue == eLazyBoolCalculate) - skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; - if (language == lldb::eLanguageTypeUnknown) - language = GetLanguage(); - - - BreakpointResolverSP resolver_sp (new BreakpointResolverName (nullptr, - func_names, - func_name_type_mask, - language, - offset, - skip_prologue)); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); - } - return bp_sp; -} +Target::CreateBreakpoint(const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, + const std::vector<std::string> &func_names, + uint32_t func_name_type_mask, LanguageType language, + lldb::addr_t offset, LazyBool skip_prologue, + bool internal, bool hardware) { + BreakpointSP bp_sp; + size_t num_names = func_names.size(); + if (num_names > 0) { + SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( + containingModules, containingSourceFiles)); -BreakpointSP -Target::CreateBreakpoint (const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles, - const char *func_names[], - size_t num_names, - uint32_t func_name_type_mask, - LanguageType language, - lldb::addr_t offset, - LazyBool skip_prologue, - bool internal, - bool hardware) -{ - BreakpointSP bp_sp; - if (num_names > 0) - { - SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles)); - - if (skip_prologue == eLazyBoolCalculate) - { - if (offset == 0) - skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; - else - skip_prologue = eLazyBoolNo; - } - if (language == lldb::eLanguageTypeUnknown) - language = GetLanguage(); - - BreakpointResolverSP resolver_sp (new BreakpointResolverName (nullptr, - func_names, - num_names, - func_name_type_mask, - language, - offset, - skip_prologue)); - resolver_sp->SetOffset(offset); - bp_sp = CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); + if (skip_prologue == eLazyBoolCalculate) + skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; + if (language == lldb::eLanguageTypeUnknown) + language = GetLanguage(); + + BreakpointResolverSP resolver_sp( + new BreakpointResolverName(nullptr, func_names, func_name_type_mask, + language, offset, skip_prologue)); + bp_sp = CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); + } + return bp_sp; +} + +BreakpointSP Target::CreateBreakpoint( + const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, const char *func_names[], + size_t num_names, uint32_t func_name_type_mask, LanguageType language, + lldb::addr_t offset, LazyBool skip_prologue, bool internal, bool hardware) { + BreakpointSP bp_sp; + if (num_names > 0) { + SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( + containingModules, containingSourceFiles)); + + if (skip_prologue == eLazyBoolCalculate) { + if (offset == 0) + skip_prologue = GetSkipPrologue() ? eLazyBoolYes : eLazyBoolNo; + else + skip_prologue = eLazyBoolNo; } - return bp_sp; -} + if (language == lldb::eLanguageTypeUnknown) + language = GetLanguage(); -SearchFilterSP -Target::GetSearchFilterForModule (const FileSpec *containingModule) -{ - SearchFilterSP filter_sp; - if (containingModule != nullptr) - { - // TODO: We should look into sharing module based search filters - // across many breakpoints like we do for the simple target based one - filter_sp.reset (new SearchFilterByModule (shared_from_this(), *containingModule)); - } - else - { - if (!m_search_filter_sp) - m_search_filter_sp.reset (new SearchFilterForUnconstrainedSearches (shared_from_this())); - filter_sp = m_search_filter_sp; - } - return filter_sp; + BreakpointResolverSP resolver_sp(new BreakpointResolverName( + nullptr, func_names, num_names, func_name_type_mask, language, offset, + skip_prologue)); + resolver_sp->SetOffset(offset); + bp_sp = CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); + } + return bp_sp; } SearchFilterSP -Target::GetSearchFilterForModuleList (const FileSpecList *containingModules) -{ - SearchFilterSP filter_sp; - if (containingModules && containingModules->GetSize() != 0) - { - // TODO: We should look into sharing module based search filters - // across many breakpoints like we do for the simple target based one - filter_sp.reset (new SearchFilterByModuleList (shared_from_this(), *containingModules)); - } - else - { - if (!m_search_filter_sp) - m_search_filter_sp.reset (new SearchFilterForUnconstrainedSearches (shared_from_this())); - filter_sp = m_search_filter_sp; - } - return filter_sp; +Target::GetSearchFilterForModule(const FileSpec *containingModule) { + SearchFilterSP filter_sp; + if (containingModule != nullptr) { + // TODO: We should look into sharing module based search filters + // across many breakpoints like we do for the simple target based one + filter_sp.reset( + new SearchFilterByModule(shared_from_this(), *containingModule)); + } else { + if (!m_search_filter_sp) + m_search_filter_sp.reset( + new SearchFilterForUnconstrainedSearches(shared_from_this())); + filter_sp = m_search_filter_sp; + } + return filter_sp; } SearchFilterSP -Target::GetSearchFilterForModuleAndCUList (const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles) -{ - if (containingSourceFiles == nullptr || containingSourceFiles->GetSize() == 0) - return GetSearchFilterForModuleList(containingModules); - - SearchFilterSP filter_sp; - if (containingModules == nullptr) - { - // We could make a special "CU List only SearchFilter". Better yet was if these could be composable, - // but that will take a little reworking. - - filter_sp.reset (new SearchFilterByModuleListAndCU (shared_from_this(), FileSpecList(), *containingSourceFiles)); - } - else - { - filter_sp.reset (new SearchFilterByModuleListAndCU (shared_from_this(), *containingModules, *containingSourceFiles)); - } - return filter_sp; -} - -BreakpointSP -Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules, - const FileSpecList *containingSourceFiles, - RegularExpression &func_regex, - lldb::LanguageType requested_language, - LazyBool skip_prologue, - bool internal, - bool hardware) -{ - SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles)); - bool skip = - (skip_prologue == eLazyBoolCalculate) ? GetSkipPrologue() - : static_cast<bool>(skip_prologue); - BreakpointResolverSP resolver_sp(new BreakpointResolverName (nullptr, - func_regex, - requested_language, - 0, - skip)); - - return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true); +Target::GetSearchFilterForModuleList(const FileSpecList *containingModules) { + SearchFilterSP filter_sp; + if (containingModules && containingModules->GetSize() != 0) { + // TODO: We should look into sharing module based search filters + // across many breakpoints like we do for the simple target based one + filter_sp.reset( + new SearchFilterByModuleList(shared_from_this(), *containingModules)); + } else { + if (!m_search_filter_sp) + m_search_filter_sp.reset( + new SearchFilterForUnconstrainedSearches(shared_from_this())); + filter_sp = m_search_filter_sp; + } + return filter_sp; +} + +SearchFilterSP Target::GetSearchFilterForModuleAndCUList( + const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles) { + if (containingSourceFiles == nullptr || containingSourceFiles->GetSize() == 0) + return GetSearchFilterForModuleList(containingModules); + + SearchFilterSP filter_sp; + if (containingModules == nullptr) { + // We could make a special "CU List only SearchFilter". Better yet was if + // these could be composable, + // but that will take a little reworking. + + filter_sp.reset(new SearchFilterByModuleListAndCU( + shared_from_this(), FileSpecList(), *containingSourceFiles)); + } else { + filter_sp.reset(new SearchFilterByModuleListAndCU( + shared_from_this(), *containingModules, *containingSourceFiles)); + } + return filter_sp; +} + +BreakpointSP Target::CreateFuncRegexBreakpoint( + const FileSpecList *containingModules, + const FileSpecList *containingSourceFiles, RegularExpression &func_regex, + lldb::LanguageType requested_language, LazyBool skip_prologue, + bool internal, bool hardware) { + SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList( + containingModules, containingSourceFiles)); + bool skip = (skip_prologue == eLazyBoolCalculate) + ? GetSkipPrologue() + : static_cast<bool>(skip_prologue); + BreakpointResolverSP resolver_sp(new BreakpointResolverName( + nullptr, func_regex, requested_language, 0, skip)); + + return CreateBreakpoint(filter_sp, resolver_sp, internal, hardware, true); } lldb::BreakpointSP -Target::CreateExceptionBreakpoint (enum lldb::LanguageType language, bool catch_bp, bool throw_bp, bool internal, Args *additional_args, Error *error) -{ - BreakpointSP exc_bkpt_sp = LanguageRuntime::CreateExceptionBreakpoint (*this, language, catch_bp, throw_bp, internal); - if (exc_bkpt_sp && additional_args) - { - Breakpoint::BreakpointPreconditionSP precondition_sp = exc_bkpt_sp->GetPrecondition(); - if (precondition_sp && additional_args) - { - if (error) - *error = precondition_sp->ConfigurePrecondition(*additional_args); - else - precondition_sp->ConfigurePrecondition(*additional_args); - } - } - return exc_bkpt_sp; -} - -BreakpointSP -Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resolver_sp, bool internal, bool request_hardware, bool resolve_indirect_symbols) -{ - BreakpointSP bp_sp; - if (filter_sp && resolver_sp) - { - bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware, resolve_indirect_symbols)); - resolver_sp->SetBreakpoint (bp_sp.get()); - AddBreakpoint (bp_sp, internal); - } - return bp_sp; -} - -void -Target::AddBreakpoint (lldb::BreakpointSP bp_sp, bool internal) -{ - if (!bp_sp) - return; - if (internal) - m_internal_breakpoint_list.Add (bp_sp, false); - else - m_breakpoint_list.Add (bp_sp, true); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - { - StreamString s; - bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); - log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, bp_sp->IsInternal() ? "yes" : "no", s.GetData()); - } - - bp_sp->ResolveBreakpoint(); - - if (!internal) - { - m_last_created_breakpoint = bp_sp; - } -} - -bool -Target::ProcessIsValid() -{ - return (m_process_sp && m_process_sp->IsAlive()); -} - -static bool -CheckIfWatchpointsExhausted(Target *target, Error &error) -{ - uint32_t num_supported_hardware_watchpoints; - Error rc = target->GetProcessSP()->GetWatchpointSupportInfo(num_supported_hardware_watchpoints); - if (num_supported_hardware_watchpoints == 0) - { - error.SetErrorStringWithFormat ("Target supports (%u) hardware watchpoint slots.\n", - num_supported_hardware_watchpoints); - return false; - } - return true; +Target::CreateExceptionBreakpoint(enum lldb::LanguageType language, + bool catch_bp, bool throw_bp, bool internal, + Args *additional_args, Error *error) { + BreakpointSP exc_bkpt_sp = LanguageRuntime::CreateExceptionBreakpoint( + *this, language, catch_bp, throw_bp, internal); + if (exc_bkpt_sp && additional_args) { + Breakpoint::BreakpointPreconditionSP precondition_sp = + exc_bkpt_sp->GetPrecondition(); + if (precondition_sp && additional_args) { + if (error) + *error = precondition_sp->ConfigurePrecondition(*additional_args); + else + precondition_sp->ConfigurePrecondition(*additional_args); + } + } + return exc_bkpt_sp; +} + +BreakpointSP Target::CreateBreakpoint(SearchFilterSP &filter_sp, + BreakpointResolverSP &resolver_sp, + bool internal, bool request_hardware, + bool resolve_indirect_symbols) { + BreakpointSP bp_sp; + if (filter_sp && resolver_sp) { + bp_sp.reset(new Breakpoint(*this, filter_sp, resolver_sp, request_hardware, + resolve_indirect_symbols)); + resolver_sp->SetBreakpoint(bp_sp.get()); + AddBreakpoint(bp_sp, internal); + } + return bp_sp; +} + +void Target::AddBreakpoint(lldb::BreakpointSP bp_sp, bool internal) { + if (!bp_sp) + return; + if (internal) + m_internal_breakpoint_list.Add(bp_sp, false); + else + m_breakpoint_list.Add(bp_sp, true); + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) { + StreamString s; + bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose); + log->Printf("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, + bp_sp->IsInternal() ? "yes" : "no", s.GetData()); + } + + bp_sp->ResolveBreakpoint(); + + if (!internal) { + m_last_created_breakpoint = bp_sp; + } +} + +bool Target::ProcessIsValid() { + return (m_process_sp && m_process_sp->IsAlive()); +} + +static bool CheckIfWatchpointsExhausted(Target *target, Error &error) { + uint32_t num_supported_hardware_watchpoints; + Error rc = target->GetProcessSP()->GetWatchpointSupportInfo( + num_supported_hardware_watchpoints); + if (num_supported_hardware_watchpoints == 0) { + error.SetErrorStringWithFormat( + "Target supports (%u) hardware watchpoint slots.\n", + num_supported_hardware_watchpoints); + return false; + } + return true; } // See also Watchpoint::SetWatchpointType(uint32_t type) and // the OptionGroupWatchpoint::WatchType enum type. -WatchpointSP -Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const CompilerType *type, uint32_t kind, Error &error) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf("Target::%s (addr = 0x%8.8" PRIx64 " size = %" PRIu64 " type = %u)\n", - __FUNCTION__, addr, (uint64_t)size, kind); - - WatchpointSP wp_sp; - if (!ProcessIsValid()) - { - error.SetErrorString("process is not alive"); - return wp_sp; - } - - if (addr == LLDB_INVALID_ADDRESS || size == 0) - { - if (size == 0) - error.SetErrorString("cannot set a watchpoint with watch_size of 0"); - else - error.SetErrorStringWithFormat("invalid watch address: %" PRIu64, addr); - return wp_sp; - } - - if (!LLDB_WATCH_TYPE_IS_VALID(kind)) - { - error.SetErrorStringWithFormat ("invalid watchpoint type: %d", kind); - } - - if (!CheckIfWatchpointsExhausted (this, error)) - return wp_sp; - - // Currently we only support one watchpoint per address, with total number - // of watchpoints limited by the hardware which the inferior is running on. - - // Grab the list mutex while doing operations. - const bool notify = false; // Don't notify about all the state changes we do on creating the watchpoint. - std::unique_lock<std::recursive_mutex> lock; - this->GetWatchpointList().GetListMutex(lock); - WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr); - if (matched_sp) - { - size_t old_size = matched_sp->GetByteSize(); - uint32_t old_type = - (matched_sp->WatchpointRead() ? LLDB_WATCH_TYPE_READ : 0) | - (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0); - // Return the existing watchpoint if both size and type match. - if (size == old_size && kind == old_type) - { - wp_sp = matched_sp; - wp_sp->SetEnabled(false, notify); - } - else - { - // Nil the matched watchpoint; we will be creating a new one. - m_process_sp->DisableWatchpoint(matched_sp.get(), notify); - m_watchpoint_list.Remove(matched_sp->GetID(), true); - } - } - - if (!wp_sp) - { - wp_sp.reset(new Watchpoint(*this, addr, size, type)); - wp_sp->SetWatchpointType(kind, notify); - m_watchpoint_list.Add (wp_sp, true); - } +WatchpointSP Target::CreateWatchpoint(lldb::addr_t addr, size_t size, + const CompilerType *type, uint32_t kind, + Error &error) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s (addr = 0x%8.8" PRIx64 " size = %" PRIu64 + " type = %u)\n", + __FUNCTION__, addr, (uint64_t)size, kind); + + WatchpointSP wp_sp; + if (!ProcessIsValid()) { + error.SetErrorString("process is not alive"); + return wp_sp; + } - error = m_process_sp->EnableWatchpoint(wp_sp.get(), notify); - if (log) - log->Printf("Target::%s (creation of watchpoint %s with id = %u)\n", - __FUNCTION__, - error.Success() ? "succeeded" : "failed", - wp_sp->GetID()); - - if (error.Fail()) - { - // Enabling the watchpoint on the device side failed. - // Remove the said watchpoint from the list maintained by the target instance. - m_watchpoint_list.Remove (wp_sp->GetID(), true); - // See if we could provide more helpful error message. - if (!OptionGroupWatchpoint::IsWatchSizeSupported(size)) - error.SetErrorStringWithFormat("watch size of %" PRIu64 " is not supported", (uint64_t)size); - - wp_sp.reset(); - } + if (addr == LLDB_INVALID_ADDRESS || size == 0) { + if (size == 0) + error.SetErrorString("cannot set a watchpoint with watch_size of 0"); else - m_last_created_watchpoint = wp_sp; + error.SetErrorStringWithFormat("invalid watch address: %" PRIu64, addr); return wp_sp; -} - -void -Target::RemoveAllBreakpoints (bool internal_also) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no"); - - m_breakpoint_list.RemoveAll (true); - if (internal_also) - m_internal_breakpoint_list.RemoveAll (false); - - m_last_created_breakpoint.reset(); -} + } -void -Target::DisableAllBreakpoints (bool internal_also) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no"); - - m_breakpoint_list.SetEnabledAll (false); - if (internal_also) - m_internal_breakpoint_list.SetEnabledAll (false); -} - -void -Target::EnableAllBreakpoints (bool internal_also) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Target::%s (internal_also = %s)\n", __FUNCTION__, internal_also ? "yes" : "no"); + if (!LLDB_WATCH_TYPE_IS_VALID(kind)) { + error.SetErrorStringWithFormat("invalid watchpoint type: %d", kind); + } - m_breakpoint_list.SetEnabledAll (true); - if (internal_also) - m_internal_breakpoint_list.SetEnabledAll (true); -} - -bool -Target::RemoveBreakpointByID (break_id_t break_id) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no"); + if (!CheckIfWatchpointsExhausted(this, error)) + return wp_sp; - if (DisableBreakpointByID (break_id)) - { - if (LLDB_BREAK_ID_IS_INTERNAL (break_id)) - m_internal_breakpoint_list.Remove(break_id, false); - else - { - if (m_last_created_breakpoint) - { - if (m_last_created_breakpoint->GetID() == break_id) - m_last_created_breakpoint.reset(); - } - m_breakpoint_list.Remove(break_id, true); - } - return true; + // Currently we only support one watchpoint per address, with total number + // of watchpoints limited by the hardware which the inferior is running on. + + // Grab the list mutex while doing operations. + const bool notify = false; // Don't notify about all the state changes we do + // on creating the watchpoint. + std::unique_lock<std::recursive_mutex> lock; + this->GetWatchpointList().GetListMutex(lock); + WatchpointSP matched_sp = m_watchpoint_list.FindByAddress(addr); + if (matched_sp) { + size_t old_size = matched_sp->GetByteSize(); + uint32_t old_type = + (matched_sp->WatchpointRead() ? LLDB_WATCH_TYPE_READ : 0) | + (matched_sp->WatchpointWrite() ? LLDB_WATCH_TYPE_WRITE : 0); + // Return the existing watchpoint if both size and type match. + if (size == old_size && kind == old_type) { + wp_sp = matched_sp; + wp_sp->SetEnabled(false, notify); + } else { + // Nil the matched watchpoint; we will be creating a new one. + m_process_sp->DisableWatchpoint(matched_sp.get(), notify); + m_watchpoint_list.Remove(matched_sp->GetID(), true); + } + } + + if (!wp_sp) { + wp_sp.reset(new Watchpoint(*this, addr, size, type)); + wp_sp->SetWatchpointType(kind, notify); + m_watchpoint_list.Add(wp_sp, true); + } + + error = m_process_sp->EnableWatchpoint(wp_sp.get(), notify); + if (log) + log->Printf("Target::%s (creation of watchpoint %s with id = %u)\n", + __FUNCTION__, error.Success() ? "succeeded" : "failed", + wp_sp->GetID()); + + if (error.Fail()) { + // Enabling the watchpoint on the device side failed. + // Remove the said watchpoint from the list maintained by the target + // instance. + m_watchpoint_list.Remove(wp_sp->GetID(), true); + // See if we could provide more helpful error message. + if (!OptionGroupWatchpoint::IsWatchSizeSupported(size)) + error.SetErrorStringWithFormat( + "watch size of %" PRIu64 " is not supported", (uint64_t)size); + + wp_sp.reset(); + } else + m_last_created_watchpoint = wp_sp; + return wp_sp; +} + +void Target::RemoveAllBreakpoints(bool internal_also) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s (internal_also = %s)\n", __FUNCTION__, + internal_also ? "yes" : "no"); + + m_breakpoint_list.RemoveAll(true); + if (internal_also) + m_internal_breakpoint_list.RemoveAll(false); + + m_last_created_breakpoint.reset(); +} + +void Target::DisableAllBreakpoints(bool internal_also) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s (internal_also = %s)\n", __FUNCTION__, + internal_also ? "yes" : "no"); + + m_breakpoint_list.SetEnabledAll(false); + if (internal_also) + m_internal_breakpoint_list.SetEnabledAll(false); +} + +void Target::EnableAllBreakpoints(bool internal_also) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s (internal_also = %s)\n", __FUNCTION__, + internal_also ? "yes" : "no"); + + m_breakpoint_list.SetEnabledAll(true); + if (internal_also) + m_internal_breakpoint_list.SetEnabledAll(true); +} + +bool Target::RemoveBreakpointByID(break_id_t break_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, + break_id, LLDB_BREAK_ID_IS_INTERNAL(break_id) ? "yes" : "no"); + + if (DisableBreakpointByID(break_id)) { + if (LLDB_BREAK_ID_IS_INTERNAL(break_id)) + m_internal_breakpoint_list.Remove(break_id, false); + else { + if (m_last_created_breakpoint) { + if (m_last_created_breakpoint->GetID() == break_id) + m_last_created_breakpoint.reset(); + } + m_breakpoint_list.Remove(break_id, true); } - return false; + return true; + } + return false; } -bool -Target::DisableBreakpointByID (break_id_t break_id) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, break_id, LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no"); +bool Target::DisableBreakpointByID(break_id_t break_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, + break_id, LLDB_BREAK_ID_IS_INTERNAL(break_id) ? "yes" : "no"); - BreakpointSP bp_sp; + BreakpointSP bp_sp; - if (LLDB_BREAK_ID_IS_INTERNAL (break_id)) - bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id); - else - bp_sp = m_breakpoint_list.FindBreakpointByID (break_id); - if (bp_sp) - { - bp_sp->SetEnabled (false); - return true; - } - return false; + if (LLDB_BREAK_ID_IS_INTERNAL(break_id)) + bp_sp = m_internal_breakpoint_list.FindBreakpointByID(break_id); + else + bp_sp = m_breakpoint_list.FindBreakpointByID(break_id); + if (bp_sp) { + bp_sp->SetEnabled(false); + return true; + } + return false; } -bool -Target::EnableBreakpointByID (break_id_t break_id) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); - if (log) - log->Printf ("Target::%s (break_id = %i, internal = %s)\n", - __FUNCTION__, - break_id, - LLDB_BREAK_ID_IS_INTERNAL (break_id) ? "yes" : "no"); +bool Target::EnableBreakpointByID(break_id_t break_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + if (log) + log->Printf("Target::%s (break_id = %i, internal = %s)\n", __FUNCTION__, + break_id, LLDB_BREAK_ID_IS_INTERNAL(break_id) ? "yes" : "no"); - BreakpointSP bp_sp; + BreakpointSP bp_sp; - if (LLDB_BREAK_ID_IS_INTERNAL (break_id)) - bp_sp = m_internal_breakpoint_list.FindBreakpointByID (break_id); - else - bp_sp = m_breakpoint_list.FindBreakpointByID (break_id); + if (LLDB_BREAK_ID_IS_INTERNAL(break_id)) + bp_sp = m_internal_breakpoint_list.FindBreakpointByID(break_id); + else + bp_sp = m_breakpoint_list.FindBreakpointByID(break_id); - if (bp_sp) - { - bp_sp->SetEnabled (true); - return true; - } - return false; + if (bp_sp) { + bp_sp->SetEnabled(true); + return true; + } + return false; } // The flag 'end_to_end', default to true, signifies that the operation is @@ -924,3404 +799,3162 @@ Target::EnableBreakpointByID (break_id_t break_id) // Assumption: Caller holds the list mutex lock for m_watchpoint_list for end // to end operations. -bool -Target::RemoveAllWatchpoints (bool end_to_end) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s\n", __FUNCTION__); +bool Target::RemoveAllWatchpoints(bool end_to_end) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s\n", __FUNCTION__); - if (!end_to_end) { - m_watchpoint_list.RemoveAll(true); - return true; - } + if (!end_to_end) { + m_watchpoint_list.RemoveAll(true); + return true; + } - // Otherwise, it's an end to end operation. + // Otherwise, it's an end to end operation. - if (!ProcessIsValid()) - return false; + if (!ProcessIsValid()) + return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) - { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); - if (!wp_sp) - return false; + size_t num_watchpoints = m_watchpoint_list.GetSize(); + for (size_t i = 0; i < num_watchpoints; ++i) { + WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + if (!wp_sp) + return false; - Error rc = m_process_sp->DisableWatchpoint(wp_sp.get()); - if (rc.Fail()) - return false; - } - m_watchpoint_list.RemoveAll (true); - m_last_created_watchpoint.reset(); - return true; // Success! + Error rc = m_process_sp->DisableWatchpoint(wp_sp.get()); + if (rc.Fail()) + return false; + } + m_watchpoint_list.RemoveAll(true); + m_last_created_watchpoint.reset(); + return true; // Success! } // Assumption: Caller holds the list mutex lock for m_watchpoint_list for end to // end operations. -bool -Target::DisableAllWatchpoints (bool end_to_end) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s\n", __FUNCTION__); +bool Target::DisableAllWatchpoints(bool end_to_end) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s\n", __FUNCTION__); - if (!end_to_end) { - m_watchpoint_list.SetEnabledAll(false); - return true; - } + if (!end_to_end) { + m_watchpoint_list.SetEnabledAll(false); + return true; + } - // Otherwise, it's an end to end operation. + // Otherwise, it's an end to end operation. - if (!ProcessIsValid()) - return false; + if (!ProcessIsValid()) + return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) - { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); - if (!wp_sp) - return false; + size_t num_watchpoints = m_watchpoint_list.GetSize(); + for (size_t i = 0; i < num_watchpoints; ++i) { + WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + if (!wp_sp) + return false; - Error rc = m_process_sp->DisableWatchpoint(wp_sp.get()); - if (rc.Fail()) - return false; - } - return true; // Success! + Error rc = m_process_sp->DisableWatchpoint(wp_sp.get()); + if (rc.Fail()) + return false; + } + return true; // Success! } // Assumption: Caller holds the list mutex lock for m_watchpoint_list for end to // end operations. -bool -Target::EnableAllWatchpoints (bool end_to_end) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s\n", __FUNCTION__); +bool Target::EnableAllWatchpoints(bool end_to_end) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s\n", __FUNCTION__); - if (!end_to_end) { - m_watchpoint_list.SetEnabledAll(true); - return true; - } + if (!end_to_end) { + m_watchpoint_list.SetEnabledAll(true); + return true; + } - // Otherwise, it's an end to end operation. + // Otherwise, it's an end to end operation. - if (!ProcessIsValid()) - return false; + if (!ProcessIsValid()) + return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) - { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); - if (!wp_sp) - return false; + size_t num_watchpoints = m_watchpoint_list.GetSize(); + for (size_t i = 0; i < num_watchpoints; ++i) { + WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + if (!wp_sp) + return false; - Error rc = m_process_sp->EnableWatchpoint(wp_sp.get()); - if (rc.Fail()) - return false; - } - return true; // Success! + Error rc = m_process_sp->EnableWatchpoint(wp_sp.get()); + if (rc.Fail()) + return false; + } + return true; // Success! } // Assumption: Caller holds the list mutex lock for m_watchpoint_list. -bool -Target::ClearAllWatchpointHitCounts () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s\n", __FUNCTION__); +bool Target::ClearAllWatchpointHitCounts() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s\n", __FUNCTION__); - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) - { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); - if (!wp_sp) - return false; + size_t num_watchpoints = m_watchpoint_list.GetSize(); + for (size_t i = 0; i < num_watchpoints; ++i) { + WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + if (!wp_sp) + return false; - wp_sp->ResetHitCount(); - } - return true; // Success! + wp_sp->ResetHitCount(); + } + return true; // Success! } // Assumption: Caller holds the list mutex lock for m_watchpoint_list. -bool -Target::ClearAllWatchpointHistoricValues () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s\n", __FUNCTION__); - - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) - { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); - if (!wp_sp) - return false; - - wp_sp->ResetHistoricValues(); - } - return true; // Success! +bool Target::ClearAllWatchpointHistoricValues() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s\n", __FUNCTION__); + + size_t num_watchpoints = m_watchpoint_list.GetSize(); + for (size_t i = 0; i < num_watchpoints; ++i) { + WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + if (!wp_sp) + return false; + + wp_sp->ResetHistoricValues(); + } + return true; // Success! } // Assumption: Caller holds the list mutex lock for m_watchpoint_list // during these operations. -bool -Target::IgnoreAllWatchpoints (uint32_t ignore_count) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s\n", __FUNCTION__); +bool Target::IgnoreAllWatchpoints(uint32_t ignore_count) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s\n", __FUNCTION__); - if (!ProcessIsValid()) - return false; + if (!ProcessIsValid()) + return false; - size_t num_watchpoints = m_watchpoint_list.GetSize(); - for (size_t i = 0; i < num_watchpoints; ++i) - { - WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); - if (!wp_sp) - return false; + size_t num_watchpoints = m_watchpoint_list.GetSize(); + for (size_t i = 0; i < num_watchpoints; ++i) { + WatchpointSP wp_sp = m_watchpoint_list.GetByIndex(i); + if (!wp_sp) + return false; - wp_sp->SetIgnoreCount(ignore_count); - } - return true; // Success! + wp_sp->SetIgnoreCount(ignore_count); + } + return true; // Success! } // Assumption: Caller holds the list mutex lock for m_watchpoint_list. -bool -Target::DisableWatchpointByID (lldb::watch_id_t watch_id) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - - if (!ProcessIsValid()) - return false; +bool Target::DisableWatchpointByID(lldb::watch_id_t watch_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - WatchpointSP wp_sp = m_watchpoint_list.FindByID (watch_id); - if (wp_sp) - { - Error rc = m_process_sp->DisableWatchpoint(wp_sp.get()); - if (rc.Success()) - return true; - - // Else, fallthrough. - } + if (!ProcessIsValid()) return false; -} -// Assumption: Caller holds the list mutex lock for m_watchpoint_list. -bool -Target::EnableWatchpointByID (lldb::watch_id_t watch_id) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - - if (!ProcessIsValid()) - return false; + WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id); + if (wp_sp) { + Error rc = m_process_sp->DisableWatchpoint(wp_sp.get()); + if (rc.Success()) + return true; - WatchpointSP wp_sp = m_watchpoint_list.FindByID (watch_id); - if (wp_sp) - { - Error rc = m_process_sp->EnableWatchpoint(wp_sp.get()); - if (rc.Success()) - return true; - - // Else, fallthrough. - } - return false; -} - -// Assumption: Caller holds the list mutex lock for m_watchpoint_list. -bool -Target::RemoveWatchpointByID (lldb::watch_id_t watch_id) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - - WatchpointSP watch_to_remove_sp = m_watchpoint_list.FindByID(watch_id); - if (watch_to_remove_sp == m_last_created_watchpoint) - m_last_created_watchpoint.reset(); - - if (DisableWatchpointByID (watch_id)) - { - m_watchpoint_list.Remove(watch_id, true); - return true; - } - return false; + // Else, fallthrough. + } + return false; } // Assumption: Caller holds the list mutex lock for m_watchpoint_list. -bool -Target::IgnoreWatchpointByID (lldb::watch_id_t watch_id, uint32_t ignore_count) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS)); - if (log) - log->Printf ("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - - if (!ProcessIsValid()) - return false; +bool Target::EnableWatchpointByID(lldb::watch_id_t watch_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - WatchpointSP wp_sp = m_watchpoint_list.FindByID (watch_id); - if (wp_sp) - { - wp_sp->SetIgnoreCount(ignore_count); - return true; - } + if (!ProcessIsValid()) return false; -} -ModuleSP -Target::GetExecutableModule () -{ - // search for the first executable in the module list - for (size_t i = 0; i < m_images.GetSize(); ++i) - { - ModuleSP module_sp = m_images.GetModuleAtIndex (i); - lldb_private::ObjectFile * obj = module_sp->GetObjectFile(); - if (obj == nullptr) - continue; - if (obj->GetType() == ObjectFile::Type::eTypeExecutable) - return module_sp; - } - // as fall back return the first module loaded - return m_images.GetModuleAtIndex (0); -} + WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id); + if (wp_sp) { + Error rc = m_process_sp->EnableWatchpoint(wp_sp.get()); + if (rc.Success()) + return true; -Module* -Target::GetExecutableModulePointer () -{ - return GetExecutableModule().get(); + // Else, fallthrough. + } + return false; } -static void -LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target) -{ - Error error; - StreamString feedback_stream; - if (module_sp && !module_sp->LoadScriptingResourceInTarget(target, error, &feedback_stream)) - { - if (error.AsCString()) - target->GetDebugger().GetErrorFile()->Printf("unable to load scripting data for module %s - error reported was %s\n", - module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(), - error.AsCString()); - } - if (feedback_stream.GetSize()) - target->GetDebugger().GetErrorFile()->Printf("%s\n", - feedback_stream.GetData()); -} - -void -Target::ClearModules(bool delete_locations) -{ - ModulesDidUnload (m_images, delete_locations); - m_section_load_history.Clear(); - m_images.Clear(); - m_scratch_type_system_map.Clear(); - m_ast_importer_sp.reset(); -} - -void -Target::DidExec () -{ - // When a process exec's we need to know about it so we can do some cleanup. - m_breakpoint_list.RemoveInvalidLocations(m_arch); - m_internal_breakpoint_list.RemoveInvalidLocations(m_arch); -} +// Assumption: Caller holds the list mutex lock for m_watchpoint_list. +bool Target::RemoveWatchpointByID(lldb::watch_id_t watch_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); -void -Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET)); - ClearModules(false); - - if (executable_sp) - { - Timer scoped_timer (LLVM_PRETTY_FUNCTION, - "Target::SetExecutableModule (executable = '%s')", - executable_sp->GetFileSpec().GetPath().c_str()); - - m_images.Append(executable_sp); // The first image is our executable file - - // If we haven't set an architecture yet, reset our architecture based on what we found in the executable module. - if (!m_arch.IsValid()) - { - m_arch = executable_sp->GetArchitecture(); - if (log) - log->Printf ("Target::SetExecutableModule setting architecture to %s (%s) based on executable file", m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str()); - } + WatchpointSP watch_to_remove_sp = m_watchpoint_list.FindByID(watch_id); + if (watch_to_remove_sp == m_last_created_watchpoint) + m_last_created_watchpoint.reset(); - FileSpecList dependent_files; - ObjectFile *executable_objfile = executable_sp->GetObjectFile(); - - if (executable_objfile && get_dependent_files) - { - executable_objfile->GetDependentModules(dependent_files); - for (uint32_t i=0; i<dependent_files.GetSize(); i++) - { - FileSpec dependent_file_spec (dependent_files.GetFileSpecPointerAtIndex(i)); - FileSpec platform_dependent_file_spec; - if (m_platform_sp) - m_platform_sp->GetFileWithUUID(dependent_file_spec, nullptr, platform_dependent_file_spec); - else - platform_dependent_file_spec = dependent_file_spec; - - ModuleSpec module_spec (platform_dependent_file_spec, m_arch); - ModuleSP image_module_sp(GetSharedModule (module_spec)); - if (image_module_sp) - { - ObjectFile *objfile = image_module_sp->GetObjectFile(); - if (objfile) - objfile->GetDependentModules(dependent_files); - } - } - } - } + if (DisableWatchpointByID(watch_id)) { + m_watchpoint_list.Remove(watch_id, true); + return true; + } + return false; } -bool -Target::SetArchitecture (const ArchSpec &arch_spec) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET)); - bool missing_local_arch = !m_arch.IsValid(); - bool replace_local_arch = true; - bool compatible_local_arch = false; - ArchSpec other(arch_spec); - - if (!missing_local_arch) - { - if (m_arch.IsCompatibleMatch(arch_spec)) - { - other.MergeFrom(m_arch); - - if (m_arch.IsCompatibleMatch(other)) - { - compatible_local_arch = true; - bool arch_changed, vendor_changed, os_changed, os_ver_changed, env_changed; - - m_arch.PiecewiseTripleCompare(other, - arch_changed, - vendor_changed, - os_changed, - os_ver_changed, - env_changed); - - if (!arch_changed && !vendor_changed && !os_changed && !env_changed) - replace_local_arch = false; - } - } - } +// Assumption: Caller holds the list mutex lock for m_watchpoint_list. +bool Target::IgnoreWatchpointByID(lldb::watch_id_t watch_id, + uint32_t ignore_count) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS)); + if (log) + log->Printf("Target::%s (watch_id = %i)\n", __FUNCTION__, watch_id); - if (compatible_local_arch || missing_local_arch) - { - // If we haven't got a valid arch spec, or the architectures are compatible - // update the architecture, unless the one we already have is more specified - if (replace_local_arch) - m_arch = other; - if (log) - log->Printf ("Target::SetArchitecture set architecture to %s (%s)", m_arch.GetArchitectureName(), m_arch.GetTriple().getTriple().c_str()); - return true; - } - - // If we have an executable file, try to reset the executable to the desired architecture - if (log) - log->Printf ("Target::SetArchitecture changing architecture to %s (%s)", arch_spec.GetArchitectureName(), arch_spec.GetTriple().getTriple().c_str()); - m_arch = other; - ModuleSP executable_sp = GetExecutableModule (); - - ClearModules(true); - // Need to do something about unsetting breakpoints. - - if (executable_sp) - { - if (log) - log->Printf("Target::SetArchitecture Trying to select executable file architecture %s (%s)", arch_spec.GetArchitectureName(), arch_spec.GetTriple().getTriple().c_str()); - ModuleSpec module_spec (executable_sp->GetFileSpec(), other); - Error error = ModuleList::GetSharedModule(module_spec, - executable_sp, - &GetExecutableSearchPaths(), - nullptr, - nullptr); - - if (!error.Fail() && executable_sp) - { - SetExecutableModule (executable_sp, true); - return true; - } - } + if (!ProcessIsValid()) return false; -} -bool -Target::MergeArchitecture (const ArchSpec &arch_spec) -{ - if (arch_spec.IsValid()) - { - if (m_arch.IsCompatibleMatch(arch_spec)) - { - // The current target arch is compatible with "arch_spec", see if we - // can improve our current architecture using bits from "arch_spec" - - // Merge bits from arch_spec into "merged_arch" and set our architecture - ArchSpec merged_arch (m_arch); - merged_arch.MergeFrom (arch_spec); - return SetArchitecture(merged_arch); - } + WatchpointSP wp_sp = m_watchpoint_list.FindByID(watch_id); + if (wp_sp) { + wp_sp->SetIgnoreCount(ignore_count); + return true; + } + return false; +} + +ModuleSP Target::GetExecutableModule() { + // search for the first executable in the module list + for (size_t i = 0; i < m_images.GetSize(); ++i) { + ModuleSP module_sp = m_images.GetModuleAtIndex(i); + lldb_private::ObjectFile *obj = module_sp->GetObjectFile(); + if (obj == nullptr) + continue; + if (obj->GetType() == ObjectFile::Type::eTypeExecutable) + return module_sp; + } + // as fall back return the first module loaded + return m_images.GetModuleAtIndex(0); +} + +Module *Target::GetExecutableModulePointer() { + return GetExecutableModule().get(); +} + +static void LoadScriptingResourceForModule(const ModuleSP &module_sp, + Target *target) { + Error error; + StreamString feedback_stream; + if (module_sp && + !module_sp->LoadScriptingResourceInTarget(target, error, + &feedback_stream)) { + if (error.AsCString()) + target->GetDebugger().GetErrorFile()->Printf( + "unable to load scripting data for module %s - error reported was " + "%s\n", + module_sp->GetFileSpec().GetFileNameStrippingExtension().GetCString(), + error.AsCString()); + } + if (feedback_stream.GetSize()) + target->GetDebugger().GetErrorFile()->Printf("%s\n", + feedback_stream.GetData()); +} + +void Target::ClearModules(bool delete_locations) { + ModulesDidUnload(m_images, delete_locations); + m_section_load_history.Clear(); + m_images.Clear(); + m_scratch_type_system_map.Clear(); + m_ast_importer_sp.reset(); +} + +void Target::DidExec() { + // When a process exec's we need to know about it so we can do some cleanup. + m_breakpoint_list.RemoveInvalidLocations(m_arch); + m_internal_breakpoint_list.RemoveInvalidLocations(m_arch); +} + +void Target::SetExecutableModule(ModuleSP &executable_sp, + bool get_dependent_files) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); + ClearModules(false); + + if (executable_sp) { + Timer scoped_timer(LLVM_PRETTY_FUNCTION, + "Target::SetExecutableModule (executable = '%s')", + executable_sp->GetFileSpec().GetPath().c_str()); + + m_images.Append(executable_sp); // The first image is our executable file + + // If we haven't set an architecture yet, reset our architecture based on + // what we found in the executable module. + if (!m_arch.IsValid()) { + m_arch = executable_sp->GetArchitecture(); + if (log) + log->Printf("Target::SetExecutableModule setting architecture to %s " + "(%s) based on executable file", + m_arch.GetArchitectureName(), + m_arch.GetTriple().getTriple().c_str()); + } + + FileSpecList dependent_files; + ObjectFile *executable_objfile = executable_sp->GetObjectFile(); + + if (executable_objfile && get_dependent_files) { + executable_objfile->GetDependentModules(dependent_files); + for (uint32_t i = 0; i < dependent_files.GetSize(); i++) { + FileSpec dependent_file_spec( + dependent_files.GetFileSpecPointerAtIndex(i)); + FileSpec platform_dependent_file_spec; + if (m_platform_sp) + m_platform_sp->GetFileWithUUID(dependent_file_spec, nullptr, + platform_dependent_file_spec); else - { - // The new architecture is different, we just need to replace it - return SetArchitecture(arch_spec); + platform_dependent_file_spec = dependent_file_spec; + + ModuleSpec module_spec(platform_dependent_file_spec, m_arch); + ModuleSP image_module_sp(GetSharedModule(module_spec)); + if (image_module_sp) { + ObjectFile *objfile = image_module_sp->GetObjectFile(); + if (objfile) + objfile->GetDependentModules(dependent_files); } + } } - return false; + } } -void -Target::WillClearList (const ModuleList& module_list) -{ -} +bool Target::SetArchitecture(const ArchSpec &arch_spec) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); + bool missing_local_arch = !m_arch.IsValid(); + bool replace_local_arch = true; + bool compatible_local_arch = false; + ArchSpec other(arch_spec); -void -Target::ModuleAdded (const ModuleList& module_list, const ModuleSP &module_sp) -{ - // A module is being added to this target for the first time - if (m_valid) - { - ModuleList my_module_list; - my_module_list.Append(module_sp); - LoadScriptingResourceForModule(module_sp, this); - ModulesDidLoad (my_module_list); - } -} + if (!missing_local_arch) { + if (m_arch.IsCompatibleMatch(arch_spec)) { + other.MergeFrom(m_arch); -void -Target::ModuleRemoved (const ModuleList& module_list, const ModuleSP &module_sp) -{ - // A module is being removed from this target. - if (m_valid) - { - ModuleList my_module_list; - my_module_list.Append(module_sp); - ModulesDidUnload (my_module_list, false); - } -} + if (m_arch.IsCompatibleMatch(other)) { + compatible_local_arch = true; + bool arch_changed, vendor_changed, os_changed, os_ver_changed, + env_changed; -void -Target::ModuleUpdated (const ModuleList& module_list, const ModuleSP &old_module_sp, const ModuleSP &new_module_sp) -{ - // A module is replacing an already added module - if (m_valid) - { - m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp); - m_internal_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp); - } -} + m_arch.PiecewiseTripleCompare(other, arch_changed, vendor_changed, + os_changed, os_ver_changed, env_changed); -void -Target::ModulesDidLoad (ModuleList &module_list) -{ - if (m_valid && module_list.GetSize()) - { - m_breakpoint_list.UpdateBreakpoints (module_list, true, false); - m_internal_breakpoint_list.UpdateBreakpoints (module_list, true, false); - if (m_process_sp) - { - m_process_sp->ModulesDidLoad (module_list); - } - BroadcastEvent (eBroadcastBitModulesLoaded, new TargetEventData (this->shared_from_this(), module_list)); + if (!arch_changed && !vendor_changed && !os_changed && !env_changed) + replace_local_arch = false; + } } -} + } -void -Target::SymbolsDidLoad (ModuleList &module_list) -{ - if (m_valid && module_list.GetSize()) - { - if (m_process_sp) - { - LanguageRuntime* runtime = m_process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); - if (runtime) - { - ObjCLanguageRuntime *objc_runtime = (ObjCLanguageRuntime*)runtime; - objc_runtime->SymbolsDidLoad(module_list); - } - } - - m_breakpoint_list.UpdateBreakpoints (module_list, true, false); - m_internal_breakpoint_list.UpdateBreakpoints (module_list, true, false); - BroadcastEvent (eBroadcastBitSymbolsLoaded, new TargetEventData (this->shared_from_this(), module_list)); - } -} - -void -Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations) -{ - if (m_valid && module_list.GetSize()) - { - UnloadModuleSections (module_list); - m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations); - m_internal_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations); - BroadcastEvent (eBroadcastBitModulesUnloaded, new TargetEventData (this->shared_from_this(), module_list)); - } -} - -bool -Target::ModuleIsExcludedForUnconstrainedSearches (const FileSpec &module_file_spec) -{ - if (GetBreakpointsConsultPlatformAvoidList()) - { - ModuleList matchingModules; - ModuleSpec module_spec (module_file_spec); - size_t num_modules = GetImages().FindModules(module_spec, matchingModules); - - // If there is more than one module for this file spec, only return true if ALL the modules are on the - // black list. - if (num_modules > 0) - { - for (size_t i = 0; i < num_modules; i++) - { - if (!ModuleIsExcludedForUnconstrainedSearches (matchingModules.GetModuleAtIndex(i))) - return false; - } - return true; - } - } - return false; -} - -bool -Target::ModuleIsExcludedForUnconstrainedSearches (const lldb::ModuleSP &module_sp) -{ - if (GetBreakpointsConsultPlatformAvoidList()) - { - if (m_platform_sp) - return m_platform_sp->ModuleIsExcludedForUnconstrainedSearches (*this, module_sp); - } - return false; -} - -size_t -Target::ReadMemoryFromFileCache (const Address& addr, void *dst, size_t dst_len, Error &error) -{ - SectionSP section_sp (addr.GetSection()); - if (section_sp) - { - // If the contents of this section are encrypted, the on-disk file is unusable. Read only from live memory. - if (section_sp->IsEncrypted()) - { - error.SetErrorString("section is encrypted"); - return 0; - } - ModuleSP module_sp (section_sp->GetModule()); - if (module_sp) - { - ObjectFile *objfile = section_sp->GetModule()->GetObjectFile(); - if (objfile) - { - size_t bytes_read = objfile->ReadSectionData (section_sp.get(), - addr.GetOffset(), - dst, - dst_len); - if (bytes_read > 0) - return bytes_read; - else - error.SetErrorStringWithFormat("error reading data from section %s", section_sp->GetName().GetCString()); - } - else - error.SetErrorString("address isn't from a object file"); - } - else - error.SetErrorString("address isn't in a module"); - } - else - error.SetErrorString("address doesn't contain a section that points to a section in a object file"); + if (compatible_local_arch || missing_local_arch) { + // If we haven't got a valid arch spec, or the architectures are compatible + // update the architecture, unless the one we already have is more specified + if (replace_local_arch) + m_arch = other; + if (log) + log->Printf("Target::SetArchitecture set architecture to %s (%s)", + m_arch.GetArchitectureName(), + m_arch.GetTriple().getTriple().c_str()); + return true; + } - return 0; -} + // If we have an executable file, try to reset the executable to the desired + // architecture + if (log) + log->Printf("Target::SetArchitecture changing architecture to %s (%s)", + arch_spec.GetArchitectureName(), + arch_spec.GetTriple().getTriple().c_str()); + m_arch = other; + ModuleSP executable_sp = GetExecutableModule(); -size_t -Target::ReadMemory (const Address& addr, - bool prefer_file_cache, - void *dst, - size_t dst_len, - Error &error, - lldb::addr_t *load_addr_ptr) -{ - error.Clear(); - - // if we end up reading this from process memory, we will fill this - // with the actual load address - if (load_addr_ptr) - *load_addr_ptr = LLDB_INVALID_ADDRESS; - - size_t bytes_read = 0; - - addr_t load_addr = LLDB_INVALID_ADDRESS; - addr_t file_addr = LLDB_INVALID_ADDRESS; - Address resolved_addr; - if (!addr.IsSectionOffset()) - { - SectionLoadList §ion_load_list = GetSectionLoadList(); - if (section_load_list.IsEmpty()) - { - // No sections are loaded, so we must assume we are not running - // yet and anything we are given is a file address. - file_addr = addr.GetOffset(); // "addr" doesn't have a section, so its offset is the file address - m_images.ResolveFileAddress (file_addr, resolved_addr); - } - else - { - // We have at least one section loaded. This can be because - // we have manually loaded some sections with "target modules load ..." - // or because we have have a live process that has sections loaded - // through the dynamic loader - load_addr = addr.GetOffset(); // "addr" doesn't have a section, so its offset is the load address - section_load_list.ResolveLoadAddress (load_addr, resolved_addr); - } - } - if (!resolved_addr.IsValid()) - resolved_addr = addr; + ClearModules(true); + // Need to do something about unsetting breakpoints. - if (prefer_file_cache) - { - bytes_read = ReadMemoryFromFileCache (resolved_addr, dst, dst_len, error); + if (executable_sp) { + if (log) + log->Printf("Target::SetArchitecture Trying to select executable file " + "architecture %s (%s)", + arch_spec.GetArchitectureName(), + arch_spec.GetTriple().getTriple().c_str()); + ModuleSpec module_spec(executable_sp->GetFileSpec(), other); + Error error = ModuleList::GetSharedModule(module_spec, executable_sp, + &GetExecutableSearchPaths(), + nullptr, nullptr); + + if (!error.Fail() && executable_sp) { + SetExecutableModule(executable_sp, true); + return true; + } + } + return false; +} + +bool Target::MergeArchitecture(const ArchSpec &arch_spec) { + if (arch_spec.IsValid()) { + if (m_arch.IsCompatibleMatch(arch_spec)) { + // The current target arch is compatible with "arch_spec", see if we + // can improve our current architecture using bits from "arch_spec" + + // Merge bits from arch_spec into "merged_arch" and set our architecture + ArchSpec merged_arch(m_arch); + merged_arch.MergeFrom(arch_spec); + return SetArchitecture(merged_arch); + } else { + // The new architecture is different, we just need to replace it + return SetArchitecture(arch_spec); + } + } + return false; +} + +void Target::WillClearList(const ModuleList &module_list) {} + +void Target::ModuleAdded(const ModuleList &module_list, + const ModuleSP &module_sp) { + // A module is being added to this target for the first time + if (m_valid) { + ModuleList my_module_list; + my_module_list.Append(module_sp); + LoadScriptingResourceForModule(module_sp, this); + ModulesDidLoad(my_module_list); + } +} + +void Target::ModuleRemoved(const ModuleList &module_list, + const ModuleSP &module_sp) { + // A module is being removed from this target. + if (m_valid) { + ModuleList my_module_list; + my_module_list.Append(module_sp); + ModulesDidUnload(my_module_list, false); + } +} + +void Target::ModuleUpdated(const ModuleList &module_list, + const ModuleSP &old_module_sp, + const ModuleSP &new_module_sp) { + // A module is replacing an already added module + if (m_valid) { + m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, + new_module_sp); + m_internal_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced( + old_module_sp, new_module_sp); + } +} + +void Target::ModulesDidLoad(ModuleList &module_list) { + if (m_valid && module_list.GetSize()) { + m_breakpoint_list.UpdateBreakpoints(module_list, true, false); + m_internal_breakpoint_list.UpdateBreakpoints(module_list, true, false); + if (m_process_sp) { + m_process_sp->ModulesDidLoad(module_list); + } + BroadcastEvent(eBroadcastBitModulesLoaded, + new TargetEventData(this->shared_from_this(), module_list)); + } +} + +void Target::SymbolsDidLoad(ModuleList &module_list) { + if (m_valid && module_list.GetSize()) { + if (m_process_sp) { + LanguageRuntime *runtime = + m_process_sp->GetLanguageRuntime(lldb::eLanguageTypeObjC); + if (runtime) { + ObjCLanguageRuntime *objc_runtime = (ObjCLanguageRuntime *)runtime; + objc_runtime->SymbolsDidLoad(module_list); + } + } + + m_breakpoint_list.UpdateBreakpoints(module_list, true, false); + m_internal_breakpoint_list.UpdateBreakpoints(module_list, true, false); + BroadcastEvent(eBroadcastBitSymbolsLoaded, + new TargetEventData(this->shared_from_this(), module_list)); + } +} + +void Target::ModulesDidUnload(ModuleList &module_list, bool delete_locations) { + if (m_valid && module_list.GetSize()) { + UnloadModuleSections(module_list); + m_breakpoint_list.UpdateBreakpoints(module_list, false, delete_locations); + m_internal_breakpoint_list.UpdateBreakpoints(module_list, false, + delete_locations); + BroadcastEvent(eBroadcastBitModulesUnloaded, + new TargetEventData(this->shared_from_this(), module_list)); + } +} + +bool Target::ModuleIsExcludedForUnconstrainedSearches( + const FileSpec &module_file_spec) { + if (GetBreakpointsConsultPlatformAvoidList()) { + ModuleList matchingModules; + ModuleSpec module_spec(module_file_spec); + size_t num_modules = GetImages().FindModules(module_spec, matchingModules); + + // If there is more than one module for this file spec, only return true if + // ALL the modules are on the + // black list. + if (num_modules > 0) { + for (size_t i = 0; i < num_modules; i++) { + if (!ModuleIsExcludedForUnconstrainedSearches( + matchingModules.GetModuleAtIndex(i))) + return false; + } + return true; + } + } + return false; +} + +bool Target::ModuleIsExcludedForUnconstrainedSearches( + const lldb::ModuleSP &module_sp) { + if (GetBreakpointsConsultPlatformAvoidList()) { + if (m_platform_sp) + return m_platform_sp->ModuleIsExcludedForUnconstrainedSearches(*this, + module_sp); + } + return false; +} + +size_t Target::ReadMemoryFromFileCache(const Address &addr, void *dst, + size_t dst_len, Error &error) { + SectionSP section_sp(addr.GetSection()); + if (section_sp) { + // If the contents of this section are encrypted, the on-disk file is + // unusable. Read only from live memory. + if (section_sp->IsEncrypted()) { + error.SetErrorString("section is encrypted"); + return 0; + } + ModuleSP module_sp(section_sp->GetModule()); + if (module_sp) { + ObjectFile *objfile = section_sp->GetModule()->GetObjectFile(); + if (objfile) { + size_t bytes_read = objfile->ReadSectionData( + section_sp.get(), addr.GetOffset(), dst, dst_len); if (bytes_read > 0) - return bytes_read; - } - - if (ProcessIsValid()) - { - if (load_addr == LLDB_INVALID_ADDRESS) - load_addr = resolved_addr.GetLoadAddress (this); - - if (load_addr == LLDB_INVALID_ADDRESS) - { - ModuleSP addr_module_sp (resolved_addr.GetModule()); - if (addr_module_sp && addr_module_sp->GetFileSpec()) - error.SetErrorStringWithFormat("%s[0x%" PRIx64 "] can't be resolved, %s in not currently loaded", - addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"), - resolved_addr.GetFileAddress(), - addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknonw>")); - else - error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved", resolved_addr.GetFileAddress()); - } + return bytes_read; else - { - bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error); - if (bytes_read != dst_len) - { - if (error.Success()) - { - if (bytes_read == 0) - error.SetErrorStringWithFormat("read memory from 0x%" PRIx64 " failed", load_addr); - else - error.SetErrorStringWithFormat("only %" PRIu64 " of %" PRIu64 " bytes were read from memory at 0x%" PRIx64, (uint64_t)bytes_read, (uint64_t)dst_len, load_addr); - } - } - if (bytes_read) - { - if (load_addr_ptr) - *load_addr_ptr = load_addr; - return bytes_read; - } - // If the address is not section offset we have an address that - // doesn't resolve to any address in any currently loaded shared - // libraries and we failed to read memory so there isn't anything - // more we can do. If it is section offset, we might be able to - // read cached memory from the object file. - if (!resolved_addr.IsSectionOffset()) - return 0; + error.SetErrorStringWithFormat("error reading data from section %s", + section_sp->GetName().GetCString()); + } else + error.SetErrorString("address isn't from a object file"); + } else + error.SetErrorString("address isn't in a module"); + } else + error.SetErrorString("address doesn't contain a section that points to a " + "section in a object file"); + + return 0; +} + +size_t Target::ReadMemory(const Address &addr, bool prefer_file_cache, + void *dst, size_t dst_len, Error &error, + lldb::addr_t *load_addr_ptr) { + error.Clear(); + + // if we end up reading this from process memory, we will fill this + // with the actual load address + if (load_addr_ptr) + *load_addr_ptr = LLDB_INVALID_ADDRESS; + + size_t bytes_read = 0; + + addr_t load_addr = LLDB_INVALID_ADDRESS; + addr_t file_addr = LLDB_INVALID_ADDRESS; + Address resolved_addr; + if (!addr.IsSectionOffset()) { + SectionLoadList §ion_load_list = GetSectionLoadList(); + if (section_load_list.IsEmpty()) { + // No sections are loaded, so we must assume we are not running + // yet and anything we are given is a file address. + file_addr = addr.GetOffset(); // "addr" doesn't have a section, so its + // offset is the file address + m_images.ResolveFileAddress(file_addr, resolved_addr); + } else { + // We have at least one section loaded. This can be because + // we have manually loaded some sections with "target modules load ..." + // or because we have have a live process that has sections loaded + // through the dynamic loader + load_addr = addr.GetOffset(); // "addr" doesn't have a section, so its + // offset is the load address + section_load_list.ResolveLoadAddress(load_addr, resolved_addr); + } + } + if (!resolved_addr.IsValid()) + resolved_addr = addr; + + if (prefer_file_cache) { + bytes_read = ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); + if (bytes_read > 0) + return bytes_read; + } + + if (ProcessIsValid()) { + if (load_addr == LLDB_INVALID_ADDRESS) + load_addr = resolved_addr.GetLoadAddress(this); + + if (load_addr == LLDB_INVALID_ADDRESS) { + ModuleSP addr_module_sp(resolved_addr.GetModule()); + if (addr_module_sp && addr_module_sp->GetFileSpec()) + error.SetErrorStringWithFormat( + "%s[0x%" PRIx64 "] can't be resolved, %s in not currently loaded", + addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"), + resolved_addr.GetFileAddress(), + addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknonw>")); + else + error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved", + resolved_addr.GetFileAddress()); + } else { + bytes_read = m_process_sp->ReadMemory(load_addr, dst, dst_len, error); + if (bytes_read != dst_len) { + if (error.Success()) { + if (bytes_read == 0) + error.SetErrorStringWithFormat( + "read memory from 0x%" PRIx64 " failed", load_addr); + else + error.SetErrorStringWithFormat( + "only %" PRIu64 " of %" PRIu64 + " bytes were read from memory at 0x%" PRIx64, + (uint64_t)bytes_read, (uint64_t)dst_len, load_addr); } - } - - if (!prefer_file_cache && resolved_addr.IsSectionOffset()) - { - // If we didn't already try and read from the object file cache, then - // try it after failing to read from the process. - return ReadMemoryFromFileCache (resolved_addr, dst, dst_len, error); - } - return 0; -} - -size_t -Target::ReadCStringFromMemory (const Address& addr, std::string &out_str, Error &error) -{ - char buf[256]; - out_str.clear(); + } + if (bytes_read) { + if (load_addr_ptr) + *load_addr_ptr = load_addr; + return bytes_read; + } + // If the address is not section offset we have an address that + // doesn't resolve to any address in any currently loaded shared + // libraries and we failed to read memory so there isn't anything + // more we can do. If it is section offset, we might be able to + // read cached memory from the object file. + if (!resolved_addr.IsSectionOffset()) + return 0; + } + } + + if (!prefer_file_cache && resolved_addr.IsSectionOffset()) { + // If we didn't already try and read from the object file cache, then + // try it after failing to read from the process. + return ReadMemoryFromFileCache(resolved_addr, dst, dst_len, error); + } + return 0; +} + +size_t Target::ReadCStringFromMemory(const Address &addr, std::string &out_str, + Error &error) { + char buf[256]; + out_str.clear(); + addr_t curr_addr = addr.GetLoadAddress(this); + Address address(addr); + while (1) { + size_t length = ReadCStringFromMemory(address, buf, sizeof(buf), error); + if (length == 0) + break; + out_str.append(buf, length); + // If we got "length - 1" bytes, we didn't get the whole C string, we + // need to read some more characters + if (length == sizeof(buf) - 1) + curr_addr += length; + else + break; + address = Address(curr_addr); + } + return out_str.size(); +} + +size_t Target::ReadCStringFromMemory(const Address &addr, char *dst, + size_t dst_max_len, Error &result_error) { + size_t total_cstr_len = 0; + if (dst && dst_max_len) { + result_error.Clear(); + // NULL out everything just to be safe + memset(dst, 0, dst_max_len); + Error error; addr_t curr_addr = addr.GetLoadAddress(this); Address address(addr); - while (1) - { - size_t length = ReadCStringFromMemory (address, buf, sizeof(buf), error); - if (length == 0) - break; - out_str.append(buf, length); - // If we got "length - 1" bytes, we didn't get the whole C string, we - // need to read some more characters - if (length == sizeof(buf) - 1) - curr_addr += length; - else - break; - address = Address(curr_addr); - } - return out_str.size(); -} -size_t -Target::ReadCStringFromMemory (const Address& addr, char *dst, size_t dst_max_len, Error &result_error) -{ - size_t total_cstr_len = 0; - if (dst && dst_max_len) - { - result_error.Clear(); - // NULL out everything just to be safe - memset (dst, 0, dst_max_len); - Error error; - addr_t curr_addr = addr.GetLoadAddress(this); - Address address(addr); - - // We could call m_process_sp->GetMemoryCacheLineSize() but I don't - // think this really needs to be tied to the memory cache subsystem's - // cache line size, so leave this as a fixed constant. - const size_t cache_line_size = 512; - - size_t bytes_left = dst_max_len - 1; - char *curr_dst = dst; - - while (bytes_left > 0) - { - addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size); - addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left); - size_t bytes_read = ReadMemory (address, false, curr_dst, bytes_to_read, error); - - if (bytes_read == 0) - { - result_error = error; - dst[total_cstr_len] = '\0'; - break; - } - const size_t len = strlen(curr_dst); - - total_cstr_len += len; - - if (len < bytes_to_read) - break; - - curr_dst += bytes_read; - curr_addr += bytes_read; - bytes_left -= bytes_read; - address = Address(curr_addr); - } - } - else - { - if (dst == nullptr) - result_error.SetErrorString("invalid arguments"); - else - result_error.Clear(); - } - return total_cstr_len; -} + // We could call m_process_sp->GetMemoryCacheLineSize() but I don't + // think this really needs to be tied to the memory cache subsystem's + // cache line size, so leave this as a fixed constant. + const size_t cache_line_size = 512; + + size_t bytes_left = dst_max_len - 1; + char *curr_dst = dst; + + while (bytes_left > 0) { + addr_t cache_line_bytes_left = + cache_line_size - (curr_addr % cache_line_size); + addr_t bytes_to_read = + std::min<addr_t>(bytes_left, cache_line_bytes_left); + size_t bytes_read = + ReadMemory(address, false, curr_dst, bytes_to_read, error); + + if (bytes_read == 0) { + result_error = error; + dst[total_cstr_len] = '\0'; + break; + } + const size_t len = strlen(curr_dst); -size_t -Target::ReadScalarIntegerFromMemory (const Address& addr, - bool prefer_file_cache, - uint32_t byte_size, - bool is_signed, - Scalar &scalar, - Error &error) -{ - uint64_t uval; - - if (byte_size <= sizeof(uval)) - { - size_t bytes_read = ReadMemory (addr, prefer_file_cache, &uval, byte_size, error); - if (bytes_read == byte_size) - { - DataExtractor data (&uval, sizeof(uval), m_arch.GetByteOrder(), m_arch.GetAddressByteSize()); - lldb::offset_t offset = 0; - if (byte_size <= 4) - scalar = data.GetMaxU32 (&offset, byte_size); - else - scalar = data.GetMaxU64 (&offset, byte_size); - - if (is_signed) - scalar.SignExtend(byte_size * 8); - return bytes_read; - } + total_cstr_len += len; + + if (len < bytes_to_read) + break; + + curr_dst += bytes_read; + curr_addr += bytes_read; + bytes_left -= bytes_read; + address = Address(curr_addr); } + } else { + if (dst == nullptr) + result_error.SetErrorString("invalid arguments"); else - { - error.SetErrorStringWithFormat ("byte size of %u is too large for integer scalar type", byte_size); - } - return 0; -} - -uint64_t -Target::ReadUnsignedIntegerFromMemory (const Address& addr, - bool prefer_file_cache, - size_t integer_byte_size, - uint64_t fail_value, - Error &error) -{ - Scalar scalar; - if (ReadScalarIntegerFromMemory (addr, - prefer_file_cache, - integer_byte_size, - false, - scalar, - error)) - return scalar.ULongLong(fail_value); - return fail_value; -} - -bool -Target::ReadPointerFromMemory (const Address& addr, - bool prefer_file_cache, - Error &error, - Address &pointer_addr) -{ - Scalar scalar; - if (ReadScalarIntegerFromMemory (addr, - prefer_file_cache, - m_arch.GetAddressByteSize(), - false, - scalar, - error)) - { - addr_t pointer_vm_addr = scalar.ULongLong(LLDB_INVALID_ADDRESS); - if (pointer_vm_addr != LLDB_INVALID_ADDRESS) - { - SectionLoadList §ion_load_list = GetSectionLoadList(); - if (section_load_list.IsEmpty()) - { - // No sections are loaded, so we must assume we are not running - // yet and anything we are given is a file address. - m_images.ResolveFileAddress (pointer_vm_addr, pointer_addr); - } - else - { - // We have at least one section loaded. This can be because - // we have manually loaded some sections with "target modules load ..." - // or because we have have a live process that has sections loaded - // through the dynamic loader - section_load_list.ResolveLoadAddress (pointer_vm_addr, pointer_addr); + result_error.Clear(); + } + return total_cstr_len; +} + +size_t Target::ReadScalarIntegerFromMemory(const Address &addr, + bool prefer_file_cache, + uint32_t byte_size, bool is_signed, + Scalar &scalar, Error &error) { + uint64_t uval; + + if (byte_size <= sizeof(uval)) { + size_t bytes_read = + ReadMemory(addr, prefer_file_cache, &uval, byte_size, error); + if (bytes_read == byte_size) { + DataExtractor data(&uval, sizeof(uval), m_arch.GetByteOrder(), + m_arch.GetAddressByteSize()); + lldb::offset_t offset = 0; + if (byte_size <= 4) + scalar = data.GetMaxU32(&offset, byte_size); + else + scalar = data.GetMaxU64(&offset, byte_size); + + if (is_signed) + scalar.SignExtend(byte_size * 8); + return bytes_read; + } + } else { + error.SetErrorStringWithFormat( + "byte size of %u is too large for integer scalar type", byte_size); + } + return 0; +} + +uint64_t Target::ReadUnsignedIntegerFromMemory(const Address &addr, + bool prefer_file_cache, + size_t integer_byte_size, + uint64_t fail_value, + Error &error) { + Scalar scalar; + if (ReadScalarIntegerFromMemory(addr, prefer_file_cache, integer_byte_size, + false, scalar, error)) + return scalar.ULongLong(fail_value); + return fail_value; +} + +bool Target::ReadPointerFromMemory(const Address &addr, bool prefer_file_cache, + Error &error, Address &pointer_addr) { + Scalar scalar; + if (ReadScalarIntegerFromMemory(addr, prefer_file_cache, + m_arch.GetAddressByteSize(), false, scalar, + error)) { + addr_t pointer_vm_addr = scalar.ULongLong(LLDB_INVALID_ADDRESS); + if (pointer_vm_addr != LLDB_INVALID_ADDRESS) { + SectionLoadList §ion_load_list = GetSectionLoadList(); + if (section_load_list.IsEmpty()) { + // No sections are loaded, so we must assume we are not running + // yet and anything we are given is a file address. + m_images.ResolveFileAddress(pointer_vm_addr, pointer_addr); + } else { + // We have at least one section loaded. This can be because + // we have manually loaded some sections with "target modules load ..." + // or because we have have a live process that has sections loaded + // through the dynamic loader + section_load_list.ResolveLoadAddress(pointer_vm_addr, pointer_addr); + } + // We weren't able to resolve the pointer value, so just return + // an address with no section + if (!pointer_addr.IsValid()) + pointer_addr.SetOffset(pointer_vm_addr); + return true; + } + } + return false; +} + +ModuleSP Target::GetSharedModule(const ModuleSpec &module_spec, + Error *error_ptr) { + ModuleSP module_sp; + + Error error; + + // First see if we already have this module in our module list. If we do, + // then we're done, we don't need + // to consult the shared modules list. But only do this if we are passed a + // UUID. + + if (module_spec.GetUUID().IsValid()) + module_sp = m_images.FindFirstModule(module_spec); + + if (!module_sp) { + ModuleSP old_module_sp; // This will get filled in if we have a new version + // of the library + bool did_create_module = false; + + // If there are image search path entries, try to use them first to acquire + // a suitable image. + if (m_image_search_paths.GetSize()) { + ModuleSpec transformed_spec(module_spec); + if (m_image_search_paths.RemapPath( + module_spec.GetFileSpec().GetDirectory(), + transformed_spec.GetFileSpec().GetDirectory())) { + transformed_spec.GetFileSpec().GetFilename() = + module_spec.GetFileSpec().GetFilename(); + error = ModuleList::GetSharedModule(transformed_spec, module_sp, + &GetExecutableSearchPaths(), + &old_module_sp, &did_create_module); + } + } + + if (!module_sp) { + // If we have a UUID, we can check our global shared module list in case + // we already have it. If we don't have a valid UUID, then we can't since + // the path in "module_spec" will be a platform path, and we will need to + // let the platform find that file. For example, we could be asking for + // "/usr/lib/dyld" and if we do not have a UUID, we don't want to pick + // the local copy of "/usr/lib/dyld" since our platform could be a remote + // platform that has its own "/usr/lib/dyld" in an SDK or in a local file + // cache. + if (module_spec.GetUUID().IsValid()) { + // We have a UUID, it is OK to check the global module list... + error = ModuleList::GetSharedModule(module_spec, module_sp, + &GetExecutableSearchPaths(), + &old_module_sp, &did_create_module); + } + + if (!module_sp) { + // The platform is responsible for finding and caching an appropriate + // module in the shared module cache. + if (m_platform_sp) { + error = m_platform_sp->GetSharedModule( + module_spec, m_process_sp.get(), module_sp, + &GetExecutableSearchPaths(), &old_module_sp, &did_create_module); + } else { + error.SetErrorString("no platform is currently set"); + } + } + } + + // We found a module that wasn't in our target list. Let's make sure that + // there wasn't an equivalent + // module in the list already, and if there was, let's remove it. + if (module_sp) { + ObjectFile *objfile = module_sp->GetObjectFile(); + if (objfile) { + switch (objfile->GetType()) { + case ObjectFile::eTypeCoreFile: /// A core file that has a checkpoint of + /// a program's execution state + case ObjectFile::eTypeExecutable: /// A normal executable + case ObjectFile::eTypeDynamicLinker: /// The platform's dynamic linker + /// executable + case ObjectFile::eTypeObjectFile: /// An intermediate object file + case ObjectFile::eTypeSharedLibrary: /// A shared library that can be + /// used during execution + break; + case ObjectFile::eTypeDebugInfo: /// An object file that contains only + /// debug information + if (error_ptr) + error_ptr->SetErrorString("debug info files aren't valid target " + "modules, please specify an executable"); + return ModuleSP(); + case ObjectFile::eTypeStubLibrary: /// A library that can be linked + /// against but not used for + /// execution + if (error_ptr) + error_ptr->SetErrorString("stub libraries aren't valid target " + "modules, please specify an executable"); + return ModuleSP(); + default: + if (error_ptr) + error_ptr->SetErrorString( + "unsupported file type, please specify an executable"); + return ModuleSP(); + } + // GetSharedModule is not guaranteed to find the old shared module, for + // instance + // in the common case where you pass in the UUID, it is only going to + // find the one + // module matching the UUID. In fact, it has no good way to know what + // the "old module" + // relevant to this target is, since there might be many copies of a + // module with this file spec + // in various running debug sessions, but only one of them will belong + // to this target. + // So let's remove the UUID from the module list, and look in the + // target's module list. + // Only do this if there is SOMETHING else in the module spec... + if (!old_module_sp) { + if (module_spec.GetUUID().IsValid() && + !module_spec.GetFileSpec().GetFilename().IsEmpty() && + !module_spec.GetFileSpec().GetDirectory().IsEmpty()) { + ModuleSpec module_spec_copy(module_spec.GetFileSpec()); + module_spec_copy.GetUUID().Clear(); + + ModuleList found_modules; + size_t num_found = + m_images.FindModules(module_spec_copy, found_modules); + if (num_found == 1) { + old_module_sp = found_modules.GetModuleAtIndex(0); } - // We weren't able to resolve the pointer value, so just return - // an address with no section - if (!pointer_addr.IsValid()) - pointer_addr.SetOffset (pointer_vm_addr); - return true; - + } } + + if (old_module_sp && + m_images.GetIndexForModule(old_module_sp.get()) != + LLDB_INVALID_INDEX32) { + m_images.ReplaceModule(old_module_sp, module_sp); + Module *old_module_ptr = old_module_sp.get(); + old_module_sp.reset(); + ModuleList::RemoveSharedModuleIfOrphaned(old_module_ptr); + } else + m_images.Append(module_sp); + } else + module_sp.reset(); } - return false; + } + if (error_ptr) + *error_ptr = error; + return module_sp; } -ModuleSP -Target::GetSharedModule (const ModuleSpec &module_spec, Error *error_ptr) -{ - ModuleSP module_sp; +TargetSP Target::CalculateTarget() { return shared_from_this(); } - Error error; +ProcessSP Target::CalculateProcess() { return m_process_sp; } - // First see if we already have this module in our module list. If we do, then we're done, we don't need - // to consult the shared modules list. But only do this if we are passed a UUID. - - if (module_spec.GetUUID().IsValid()) - module_sp = m_images.FindFirstModule(module_spec); - - if (!module_sp) - { - ModuleSP old_module_sp; // This will get filled in if we have a new version of the library - bool did_create_module = false; - - // If there are image search path entries, try to use them first to acquire a suitable image. - if (m_image_search_paths.GetSize()) - { - ModuleSpec transformed_spec (module_spec); - if (m_image_search_paths.RemapPath (module_spec.GetFileSpec().GetDirectory(), transformed_spec.GetFileSpec().GetDirectory())) - { - transformed_spec.GetFileSpec().GetFilename() = module_spec.GetFileSpec().GetFilename(); - error = ModuleList::GetSharedModule (transformed_spec, - module_sp, - &GetExecutableSearchPaths(), - &old_module_sp, - &did_create_module); - } - } - - if (!module_sp) - { - // If we have a UUID, we can check our global shared module list in case - // we already have it. If we don't have a valid UUID, then we can't since - // the path in "module_spec" will be a platform path, and we will need to - // let the platform find that file. For example, we could be asking for - // "/usr/lib/dyld" and if we do not have a UUID, we don't want to pick - // the local copy of "/usr/lib/dyld" since our platform could be a remote - // platform that has its own "/usr/lib/dyld" in an SDK or in a local file - // cache. - if (module_spec.GetUUID().IsValid()) - { - // We have a UUID, it is OK to check the global module list... - error = ModuleList::GetSharedModule (module_spec, - module_sp, - &GetExecutableSearchPaths(), - &old_module_sp, - &did_create_module); - } +ThreadSP Target::CalculateThread() { return ThreadSP(); } - if (!module_sp) - { - // The platform is responsible for finding and caching an appropriate - // module in the shared module cache. - if (m_platform_sp) - { - error = m_platform_sp->GetSharedModule (module_spec, - m_process_sp.get(), - module_sp, - &GetExecutableSearchPaths(), - &old_module_sp, - &did_create_module); - } - else - { - error.SetErrorString("no platform is currently set"); - } - } - } +StackFrameSP Target::CalculateStackFrame() { return StackFrameSP(); } - // We found a module that wasn't in our target list. Let's make sure that there wasn't an equivalent - // module in the list already, and if there was, let's remove it. - if (module_sp) - { - ObjectFile *objfile = module_sp->GetObjectFile(); - if (objfile) - { - switch (objfile->GetType()) - { - case ObjectFile::eTypeCoreFile: /// A core file that has a checkpoint of a program's execution state - case ObjectFile::eTypeExecutable: /// A normal executable - case ObjectFile::eTypeDynamicLinker: /// The platform's dynamic linker executable - case ObjectFile::eTypeObjectFile: /// An intermediate object file - case ObjectFile::eTypeSharedLibrary: /// A shared library that can be used during execution - break; - case ObjectFile::eTypeDebugInfo: /// An object file that contains only debug information - if (error_ptr) - error_ptr->SetErrorString("debug info files aren't valid target modules, please specify an executable"); - return ModuleSP(); - case ObjectFile::eTypeStubLibrary: /// A library that can be linked against but not used for execution - if (error_ptr) - error_ptr->SetErrorString("stub libraries aren't valid target modules, please specify an executable"); - return ModuleSP(); - default: - if (error_ptr) - error_ptr->SetErrorString("unsupported file type, please specify an executable"); - return ModuleSP(); - } - // GetSharedModule is not guaranteed to find the old shared module, for instance - // in the common case where you pass in the UUID, it is only going to find the one - // module matching the UUID. In fact, it has no good way to know what the "old module" - // relevant to this target is, since there might be many copies of a module with this file spec - // in various running debug sessions, but only one of them will belong to this target. - // So let's remove the UUID from the module list, and look in the target's module list. - // Only do this if there is SOMETHING else in the module spec... - if (!old_module_sp) - { - if (module_spec.GetUUID().IsValid() && !module_spec.GetFileSpec().GetFilename().IsEmpty() && !module_spec.GetFileSpec().GetDirectory().IsEmpty()) - { - ModuleSpec module_spec_copy(module_spec.GetFileSpec()); - module_spec_copy.GetUUID().Clear(); - - ModuleList found_modules; - size_t num_found = m_images.FindModules (module_spec_copy, found_modules); - if (num_found == 1) - { - old_module_sp = found_modules.GetModuleAtIndex(0); - } - } - } - - if (old_module_sp && m_images.GetIndexForModule (old_module_sp.get()) != LLDB_INVALID_INDEX32) - { - m_images.ReplaceModule(old_module_sp, module_sp); - Module *old_module_ptr = old_module_sp.get(); - old_module_sp.reset(); - ModuleList::RemoveSharedModuleIfOrphaned (old_module_ptr); - } - else - m_images.Append(module_sp); - } - else - module_sp.reset(); - } - } - if (error_ptr) - *error_ptr = error; - return module_sp; +void Target::CalculateExecutionContext(ExecutionContext &exe_ctx) { + exe_ctx.Clear(); + exe_ctx.SetTargetPtr(this); } -TargetSP -Target::CalculateTarget () -{ - return shared_from_this(); +PathMappingList &Target::GetImageSearchPathList() { + return m_image_search_paths; } -ProcessSP -Target::CalculateProcess () -{ - return m_process_sp; +void Target::ImageSearchPathsChanged(const PathMappingList &path_list, + void *baton) { + Target *target = (Target *)baton; + ModuleSP exe_module_sp(target->GetExecutableModule()); + if (exe_module_sp) + target->SetExecutableModule(exe_module_sp, true); } -ThreadSP -Target::CalculateThread () -{ - return ThreadSP(); -} +TypeSystem *Target::GetScratchTypeSystemForLanguage(Error *error, + lldb::LanguageType language, + bool create_on_demand) { + if (!m_valid) + return nullptr; -StackFrameSP -Target::CalculateStackFrame () -{ - return StackFrameSP(); -} + if (error) { + error->Clear(); + } -void -Target::CalculateExecutionContext (ExecutionContext &exe_ctx) -{ - exe_ctx.Clear(); - exe_ctx.SetTargetPtr(this); -} - -PathMappingList & -Target::GetImageSearchPathList () -{ - return m_image_search_paths; -} + if (language == eLanguageTypeMipsAssembler // GNU AS and LLVM use it for all + // assembly code + || language == eLanguageTypeUnknown) { + std::set<lldb::LanguageType> languages_for_types; + std::set<lldb::LanguageType> languages_for_expressions; -void -Target::ImageSearchPathsChanged(const PathMappingList &path_list, - void *baton) -{ - Target *target = (Target *)baton; - ModuleSP exe_module_sp (target->GetExecutableModule()); - if (exe_module_sp) - target->SetExecutableModule (exe_module_sp, true); -} + Language::GetLanguagesSupportingTypeSystems(languages_for_types, + languages_for_expressions); -TypeSystem * -Target::GetScratchTypeSystemForLanguage (Error *error, lldb::LanguageType language, bool create_on_demand) -{ - if (!m_valid) + if (languages_for_expressions.count(eLanguageTypeC)) { + language = eLanguageTypeC; // LLDB's default. Override by setting the + // target language. + } else { + if (languages_for_expressions.empty()) { return nullptr; - - if (error) - { - error->Clear(); - } - - if (language == eLanguageTypeMipsAssembler // GNU AS and LLVM use it for all assembly code - || language == eLanguageTypeUnknown) - { - std::set<lldb::LanguageType> languages_for_types; - std::set<lldb::LanguageType> languages_for_expressions; - - Language::GetLanguagesSupportingTypeSystems(languages_for_types, languages_for_expressions); - - if (languages_for_expressions.count(eLanguageTypeC)) - { - language = eLanguageTypeC; // LLDB's default. Override by setting the target language. - } - else - { - if (languages_for_expressions.empty()) - { - return nullptr; - } - else - { - language = *languages_for_expressions.begin(); - } - } + } else { + language = *languages_for_expressions.begin(); + } } + } - return m_scratch_type_system_map.GetTypeSystemForLanguage(language, this, create_on_demand); + return m_scratch_type_system_map.GetTypeSystemForLanguage(language, this, + create_on_demand); } PersistentExpressionState * -Target::GetPersistentExpressionStateForLanguage (lldb::LanguageType language) -{ - TypeSystem *type_system = GetScratchTypeSystemForLanguage(nullptr, language, true); - - if (type_system) - { - return type_system->GetPersistentExpressionState(); - } - else - { - return nullptr; - } +Target::GetPersistentExpressionStateForLanguage(lldb::LanguageType language) { + TypeSystem *type_system = + GetScratchTypeSystemForLanguage(nullptr, language, true); + + if (type_system) { + return type_system->GetPersistentExpressionState(); + } else { + return nullptr; + } } -UserExpression * -Target::GetUserExpressionForLanguage(const char *expr, - const char *expr_prefix, - lldb::LanguageType language, - Expression::ResultType desired_type, - const EvaluateExpressionOptions &options, - Error &error) -{ - Error type_system_error; - - TypeSystem *type_system = GetScratchTypeSystemForLanguage (&type_system_error, language); - UserExpression *user_expr = nullptr; - - if (!type_system) - { - error.SetErrorStringWithFormat("Could not find type system for language %s: %s", Language::GetNameForLanguageType(language), type_system_error.AsCString()); - return nullptr; - } - - user_expr = type_system->GetUserExpression(expr, expr_prefix, language, desired_type, options); - if (!user_expr) - error.SetErrorStringWithFormat("Could not create an expression for language %s", Language::GetNameForLanguageType(language)); - - return user_expr; -} - -FunctionCaller * -Target::GetFunctionCallerForLanguage (lldb::LanguageType language, - const CompilerType &return_type, - const Address& function_address, - const ValueList &arg_value_list, - const char *name, - Error &error) -{ - Error type_system_error; - TypeSystem *type_system = GetScratchTypeSystemForLanguage (&type_system_error, language); - FunctionCaller *persistent_fn = nullptr; - - if (!type_system) - { - error.SetErrorStringWithFormat("Could not find type system for language %s: %s", Language::GetNameForLanguageType(language), type_system_error.AsCString()); - return persistent_fn; - } - - persistent_fn = type_system->GetFunctionCaller (return_type, function_address, arg_value_list, name); - if (!persistent_fn) - error.SetErrorStringWithFormat("Could not create an expression for language %s", Language::GetNameForLanguageType(language)); - +UserExpression *Target::GetUserExpressionForLanguage( + const char *expr, const char *expr_prefix, lldb::LanguageType language, + Expression::ResultType desired_type, + const EvaluateExpressionOptions &options, Error &error) { + Error type_system_error; + + TypeSystem *type_system = + GetScratchTypeSystemForLanguage(&type_system_error, language); + UserExpression *user_expr = nullptr; + + if (!type_system) { + error.SetErrorStringWithFormat( + "Could not find type system for language %s: %s", + Language::GetNameForLanguageType(language), + type_system_error.AsCString()); + return nullptr; + } + + user_expr = type_system->GetUserExpression(expr, expr_prefix, language, + desired_type, options); + if (!user_expr) + error.SetErrorStringWithFormat( + "Could not create an expression for language %s", + Language::GetNameForLanguageType(language)); + + return user_expr; +} + +FunctionCaller *Target::GetFunctionCallerForLanguage( + lldb::LanguageType language, const CompilerType &return_type, + const Address &function_address, const ValueList &arg_value_list, + const char *name, Error &error) { + Error type_system_error; + TypeSystem *type_system = + GetScratchTypeSystemForLanguage(&type_system_error, language); + FunctionCaller *persistent_fn = nullptr; + + if (!type_system) { + error.SetErrorStringWithFormat( + "Could not find type system for language %s: %s", + Language::GetNameForLanguageType(language), + type_system_error.AsCString()); return persistent_fn; + } + + persistent_fn = type_system->GetFunctionCaller(return_type, function_address, + arg_value_list, name); + if (!persistent_fn) + error.SetErrorStringWithFormat( + "Could not create an expression for language %s", + Language::GetNameForLanguageType(language)); + + return persistent_fn; } UtilityFunction * -Target::GetUtilityFunctionForLanguage (const char *text, - lldb::LanguageType language, - const char *name, - Error &error) -{ - Error type_system_error; - TypeSystem *type_system = GetScratchTypeSystemForLanguage (&type_system_error, language); - UtilityFunction *utility_fn = nullptr; - - if (!type_system) - { - error.SetErrorStringWithFormat("Could not find type system for language %s: %s", Language::GetNameForLanguageType(language), type_system_error.AsCString()); - return utility_fn; - } - - utility_fn = type_system->GetUtilityFunction (text, name); - if (!utility_fn) - error.SetErrorStringWithFormat("Could not create an expression for language %s", Language::GetNameForLanguageType(language)); - +Target::GetUtilityFunctionForLanguage(const char *text, + lldb::LanguageType language, + const char *name, Error &error) { + Error type_system_error; + TypeSystem *type_system = + GetScratchTypeSystemForLanguage(&type_system_error, language); + UtilityFunction *utility_fn = nullptr; + + if (!type_system) { + error.SetErrorStringWithFormat( + "Could not find type system for language %s: %s", + Language::GetNameForLanguageType(language), + type_system_error.AsCString()); return utility_fn; + } + + utility_fn = type_system->GetUtilityFunction(text, name); + if (!utility_fn) + error.SetErrorStringWithFormat( + "Could not create an expression for language %s", + Language::GetNameForLanguageType(language)); + + return utility_fn; } -ClangASTContext * -Target::GetScratchClangASTContext(bool create_on_demand) -{ - if (m_valid) - { - if (TypeSystem* type_system = GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC, create_on_demand)) - return llvm::dyn_cast<ClangASTContext>(type_system); - } - return nullptr; +ClangASTContext *Target::GetScratchClangASTContext(bool create_on_demand) { + if (m_valid) { + if (TypeSystem *type_system = GetScratchTypeSystemForLanguage( + nullptr, eLanguageTypeC, create_on_demand)) + return llvm::dyn_cast<ClangASTContext>(type_system); + } + return nullptr; } -ClangASTImporterSP -Target::GetClangASTImporter() -{ - if (m_valid) - { - if (!m_ast_importer_sp) - { - m_ast_importer_sp.reset(new ClangASTImporter()); - } - return m_ast_importer_sp; +ClangASTImporterSP Target::GetClangASTImporter() { + if (m_valid) { + if (!m_ast_importer_sp) { + m_ast_importer_sp.reset(new ClangASTImporter()); } - return ClangASTImporterSP(); + return m_ast_importer_sp; + } + return ClangASTImporterSP(); } -void -Target::SettingsInitialize () -{ - Process::SettingsInitialize (); -} +void Target::SettingsInitialize() { Process::SettingsInitialize(); } -void -Target::SettingsTerminate () -{ - Process::SettingsTerminate (); -} +void Target::SettingsTerminate() { Process::SettingsTerminate(); } -FileSpecList -Target::GetDefaultExecutableSearchPaths () -{ - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetExecutableSearchPaths(); - return FileSpecList(); +FileSpecList Target::GetDefaultExecutableSearchPaths() { + TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); + if (properties_sp) + return properties_sp->GetExecutableSearchPaths(); + return FileSpecList(); } -FileSpecList -Target::GetDefaultDebugFileSearchPaths () -{ - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetDebugFileSearchPaths(); - return FileSpecList(); +FileSpecList Target::GetDefaultDebugFileSearchPaths() { + TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); + if (properties_sp) + return properties_sp->GetDebugFileSearchPaths(); + return FileSpecList(); } -FileSpecList -Target::GetDefaultClangModuleSearchPaths () -{ - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetClangModuleSearchPaths(); - return FileSpecList(); +FileSpecList Target::GetDefaultClangModuleSearchPaths() { + TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); + if (properties_sp) + return properties_sp->GetClangModuleSearchPaths(); + return FileSpecList(); } -ArchSpec -Target::GetDefaultArchitecture () -{ - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - return properties_sp->GetDefaultArchitecture(); - return ArchSpec(); +ArchSpec Target::GetDefaultArchitecture() { + TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); + if (properties_sp) + return properties_sp->GetDefaultArchitecture(); + return ArchSpec(); } -void -Target::SetDefaultArchitecture (const ArchSpec &arch) -{ - TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); - if (properties_sp) - { - LogIfAnyCategoriesSet(LIBLLDB_LOG_TARGET, "Target::SetDefaultArchitecture setting target's default architecture to %s (%s)", arch.GetArchitectureName(), arch.GetTriple().getTriple().c_str()); - return properties_sp->SetDefaultArchitecture(arch); - } +void Target::SetDefaultArchitecture(const ArchSpec &arch) { + TargetPropertiesSP properties_sp(Target::GetGlobalProperties()); + if (properties_sp) { + LogIfAnyCategoriesSet( + LIBLLDB_LOG_TARGET, "Target::SetDefaultArchitecture setting target's " + "default architecture to %s (%s)", + arch.GetArchitectureName(), arch.GetTriple().getTriple().c_str()); + return properties_sp->SetDefaultArchitecture(arch); + } } -Target * -Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const SymbolContext *sc_ptr) -{ - // The target can either exist in the "process" of ExecutionContext, or in - // the "target_sp" member of SymbolContext. This accessor helper function - // will get the target from one of these locations. - - Target *target = nullptr; - if (sc_ptr != nullptr) - target = sc_ptr->target_sp.get(); - if (target == nullptr && exe_ctx_ptr) - target = exe_ctx_ptr->GetTargetPtr(); - return target; -} - -ExpressionResults -Target::EvaluateExpression(const char *expr_cstr, - ExecutionContextScope *exe_scope, - lldb::ValueObjectSP &result_valobj_sp, - const EvaluateExpressionOptions& options, - std::string *fixed_expression) -{ - result_valobj_sp.reset(); - - ExpressionResults execution_results = eExpressionSetupError; +Target *Target::GetTargetFromContexts(const ExecutionContext *exe_ctx_ptr, + const SymbolContext *sc_ptr) { + // The target can either exist in the "process" of ExecutionContext, or in + // the "target_sp" member of SymbolContext. This accessor helper function + // will get the target from one of these locations. - if (expr_cstr == nullptr || expr_cstr[0] == '\0') - return execution_results; + Target *target = nullptr; + if (sc_ptr != nullptr) + target = sc_ptr->target_sp.get(); + if (target == nullptr && exe_ctx_ptr) + target = exe_ctx_ptr->GetTargetPtr(); + return target; +} - // We shouldn't run stop hooks in expressions. - // Be sure to reset this if you return anywhere within this function. - bool old_suppress_value = m_suppress_stop_hooks; - m_suppress_stop_hooks = true; +ExpressionResults Target::EvaluateExpression( + const char *expr_cstr, ExecutionContextScope *exe_scope, + lldb::ValueObjectSP &result_valobj_sp, + const EvaluateExpressionOptions &options, std::string *fixed_expression) { + result_valobj_sp.reset(); - ExecutionContext exe_ctx; - - if (exe_scope) - { - exe_scope->CalculateExecutionContext(exe_ctx); - } - else if (m_process_sp) - { - m_process_sp->CalculateExecutionContext(exe_ctx); - } - else - { - CalculateExecutionContext(exe_ctx); - } - - // Make sure we aren't just trying to see the value of a persistent - // variable (something like "$0") - lldb::ExpressionVariableSP persistent_var_sp; - // Only check for persistent variables the expression starts with a '$' - if (expr_cstr[0] == '$') - persistent_var_sp = GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC)->GetPersistentExpressionState()->GetVariable (expr_cstr); - - if (persistent_var_sp) - { - result_valobj_sp = persistent_var_sp->GetValueObject (); - execution_results = eExpressionCompleted; - } - else - { - const char *prefix = GetExpressionPrefixContentsAsCString(); - Error error; - execution_results = UserExpression::Evaluate (exe_ctx, - options, - expr_cstr, - prefix, - result_valobj_sp, - error, - 0, // Line Number - fixed_expression); - } - - m_suppress_stop_hooks = old_suppress_value; - + ExpressionResults execution_results = eExpressionSetupError; + + if (expr_cstr == nullptr || expr_cstr[0] == '\0') return execution_results; + + // We shouldn't run stop hooks in expressions. + // Be sure to reset this if you return anywhere within this function. + bool old_suppress_value = m_suppress_stop_hooks; + m_suppress_stop_hooks = true; + + ExecutionContext exe_ctx; + + if (exe_scope) { + exe_scope->CalculateExecutionContext(exe_ctx); + } else if (m_process_sp) { + m_process_sp->CalculateExecutionContext(exe_ctx); + } else { + CalculateExecutionContext(exe_ctx); + } + + // Make sure we aren't just trying to see the value of a persistent + // variable (something like "$0") + lldb::ExpressionVariableSP persistent_var_sp; + // Only check for persistent variables the expression starts with a '$' + if (expr_cstr[0] == '$') + persistent_var_sp = GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC) + ->GetPersistentExpressionState() + ->GetVariable(expr_cstr); + + if (persistent_var_sp) { + result_valobj_sp = persistent_var_sp->GetValueObject(); + execution_results = eExpressionCompleted; + } else { + const char *prefix = GetExpressionPrefixContentsAsCString(); + Error error; + execution_results = UserExpression::Evaluate( + exe_ctx, options, expr_cstr, prefix, result_valobj_sp, error, + 0, // Line Number + fixed_expression); + } + + m_suppress_stop_hooks = old_suppress_value; + + return execution_results; } lldb::ExpressionVariableSP -Target::GetPersistentVariable(const ConstString &name) -{ - lldb::ExpressionVariableSP variable_sp; - m_scratch_type_system_map.ForEach([this, name, &variable_sp](TypeSystem *type_system) -> bool - { - if (PersistentExpressionState *persistent_state = type_system->GetPersistentExpressionState()) - { - variable_sp = persistent_state->GetVariable(name); - - if (variable_sp) - return false; // Stop iterating the ForEach +Target::GetPersistentVariable(const ConstString &name) { + lldb::ExpressionVariableSP variable_sp; + m_scratch_type_system_map.ForEach( + [this, name, &variable_sp](TypeSystem *type_system) -> bool { + if (PersistentExpressionState *persistent_state = + type_system->GetPersistentExpressionState()) { + variable_sp = persistent_state->GetVariable(name); + + if (variable_sp) + return false; // Stop iterating the ForEach } - return true; // Keep iterating the ForEach - }); - return variable_sp; + return true; // Keep iterating the ForEach + }); + return variable_sp; } -lldb::addr_t -Target::GetPersistentSymbol(const ConstString &name) -{ - lldb::addr_t address = LLDB_INVALID_ADDRESS; - - m_scratch_type_system_map.ForEach([this, name, &address](TypeSystem *type_system) -> bool - { - if (PersistentExpressionState *persistent_state = type_system->GetPersistentExpressionState()) - { - address = persistent_state->LookupSymbol(name); - if (address != LLDB_INVALID_ADDRESS) - return false; // Stop iterating the ForEach - } - return true; // Keep iterating the ForEach - }); - return address; -} +lldb::addr_t Target::GetPersistentSymbol(const ConstString &name) { + lldb::addr_t address = LLDB_INVALID_ADDRESS; -lldb::addr_t -Target::GetCallableLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const -{ - addr_t code_addr = load_addr; - switch (m_arch.GetMachine()) - { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - switch (addr_class) - { - case eAddressClassData: - case eAddressClassDebug: - return LLDB_INVALID_ADDRESS; - - case eAddressClassUnknown: - case eAddressClassInvalid: - case eAddressClassCode: - case eAddressClassCodeAlternateISA: - case eAddressClassRuntime: - if ((code_addr & 2ull) || (addr_class == eAddressClassCodeAlternateISA)) - code_addr |= 1ull; - break; + m_scratch_type_system_map.ForEach( + [this, name, &address](TypeSystem *type_system) -> bool { + if (PersistentExpressionState *persistent_state = + type_system->GetPersistentExpressionState()) { + address = persistent_state->LookupSymbol(name); + if (address != LLDB_INVALID_ADDRESS) + return false; // Stop iterating the ForEach } - break; - - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) - { - case eAddressClassData: - case eAddressClassDebug: - return LLDB_INVALID_ADDRESS; - - case eAddressClassUnknown: - case eAddressClassInvalid: - case eAddressClassCode: - case eAddressClassCodeAlternateISA: - case eAddressClassRuntime: - // Check if bit zero it no set? - if ((code_addr & 1ull) == 0) - { - // Bit zero isn't set, check if the address is a multiple of 2? - if (code_addr & 2ull) - { - // The address is a multiple of 2 so it must be thumb, set bit zero - code_addr |= 1ull; - } - else if (addr_class == eAddressClassCodeAlternateISA) - { - // We checked the address and the address claims to be the alternate ISA - // which means thumb, so set bit zero. - code_addr |= 1ull; - } - } - break; + return true; // Keep iterating the ForEach + }); + return address; +} + +lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const { + addr_t code_addr = load_addr; + switch (m_arch.GetMachine()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + switch (addr_class) { + case eAddressClassData: + case eAddressClassDebug: + return LLDB_INVALID_ADDRESS; + + case eAddressClassUnknown: + case eAddressClassInvalid: + case eAddressClassCode: + case eAddressClassCodeAlternateISA: + case eAddressClassRuntime: + if ((code_addr & 2ull) || (addr_class == eAddressClassCodeAlternateISA)) + code_addr |= 1ull; + break; + } + break; + + case llvm::Triple::arm: + case llvm::Triple::thumb: + switch (addr_class) { + case eAddressClassData: + case eAddressClassDebug: + return LLDB_INVALID_ADDRESS; + + case eAddressClassUnknown: + case eAddressClassInvalid: + case eAddressClassCode: + case eAddressClassCodeAlternateISA: + case eAddressClassRuntime: + // Check if bit zero it no set? + if ((code_addr & 1ull) == 0) { + // Bit zero isn't set, check if the address is a multiple of 2? + if (code_addr & 2ull) { + // The address is a multiple of 2 so it must be thumb, set bit zero + code_addr |= 1ull; + } else if (addr_class == eAddressClassCodeAlternateISA) { + // We checked the address and the address claims to be the alternate + // ISA + // which means thumb, so set bit zero. + code_addr |= 1ull; } - break; - - default: - break; - } - return code_addr; -} + } + break; + } + break; + + default: + break; + } + return code_addr; +} + +lldb::addr_t Target::GetOpcodeLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const { + addr_t opcode_addr = load_addr; + switch (m_arch.GetMachine()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::arm: + case llvm::Triple::thumb: + switch (addr_class) { + case eAddressClassData: + case eAddressClassDebug: + return LLDB_INVALID_ADDRESS; + + case eAddressClassInvalid: + case eAddressClassUnknown: + case eAddressClassCode: + case eAddressClassCodeAlternateISA: + case eAddressClassRuntime: + opcode_addr &= ~(1ull); + break; + } + break; + + default: + break; + } + return opcode_addr; +} + +lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { + addr_t breakable_addr = addr; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + switch (m_arch.GetMachine()) { + default: + break; + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: { + addr_t function_start = 0; + addr_t current_offset = 0; + uint32_t loop_count = 0; + Address resolved_addr; + uint32_t arch_flags = m_arch.GetFlags(); + bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; + bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; + SectionLoadList §ion_load_list = GetSectionLoadList(); + + if (section_load_list.IsEmpty()) + // No sections are loaded, so we must assume we are not running yet + // and need to operate only on file address. + m_images.ResolveFileAddress(addr, resolved_addr); + else + section_load_list.ResolveLoadAddress(addr, resolved_addr); + + // Get the function boundaries to make sure we don't scan back before the + // beginning of the current function. + ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); + if (temp_addr_module_sp) { + SymbolContext sc; + uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, + resolve_scope, sc); + Address sym_addr; + if (sc.function) + sym_addr = sc.function->GetAddressRange().GetBaseAddress(); + else if (sc.symbol) + sym_addr = sc.symbol->GetAddress(); + + function_start = sym_addr.GetLoadAddress(this); + if (function_start == LLDB_INVALID_ADDRESS) + function_start = sym_addr.GetFileAddress(); + + if (function_start) + current_offset = addr - function_start; + } + + // If breakpoint address is start of function then we dont have to do + // anything. + if (current_offset == 0) + return breakable_addr; + else + loop_count = current_offset / 2; -lldb::addr_t -Target::GetOpcodeLoadAddress (lldb::addr_t load_addr, AddressClass addr_class) const -{ - addr_t opcode_addr = load_addr; - switch (m_arch.GetMachine()) - { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) - { - case eAddressClassData: - case eAddressClassDebug: - return LLDB_INVALID_ADDRESS; - - case eAddressClassInvalid: - case eAddressClassUnknown: - case eAddressClassCode: - case eAddressClassCodeAlternateISA: - case eAddressClassRuntime: - opcode_addr &= ~(1ull); - break; - } - break; - - default: - break; + if (loop_count > 3) { + // Scan previous 6 bytes + if (IsMips16 | IsMicromips) + loop_count = 3; + // For mips-only, instructions are always 4 bytes, so scan previous 4 + // bytes only. + else + loop_count = 2; } - return opcode_addr; -} -lldb::addr_t -Target::GetBreakableLoadAddress (lldb::addr_t addr) -{ - addr_t breakable_addr = addr; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS)); + // Create Disassembler Instance + lldb::DisassemblerSP disasm_sp( + Disassembler::FindPlugin(m_arch, nullptr, nullptr)); - switch (m_arch.GetMachine()) - { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - { - addr_t function_start = 0; - addr_t current_offset = 0; - uint32_t loop_count = 0; - Address resolved_addr; - uint32_t arch_flags = m_arch.GetFlags (); - bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; - bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; - SectionLoadList §ion_load_list = GetSectionLoadList(); - - if (section_load_list.IsEmpty()) - // No sections are loaded, so we must assume we are not running yet - // and need to operate only on file address. - m_images.ResolveFileAddress (addr, resolved_addr); - else - section_load_list.ResolveLoadAddress(addr, resolved_addr); - - // Get the function boundaries to make sure we don't scan back before the beginning of the current function. - ModuleSP temp_addr_module_sp (resolved_addr.GetModule()); - if (temp_addr_module_sp) - { - SymbolContext sc; - uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; - temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, resolve_scope, sc); - Address sym_addr; - if (sc.function) - sym_addr = sc.function->GetAddressRange().GetBaseAddress(); - else if (sc.symbol) - sym_addr = sc.symbol->GetAddress(); - - function_start = sym_addr.GetLoadAddress(this); - if (function_start == LLDB_INVALID_ADDRESS) - function_start = sym_addr.GetFileAddress(); - - if (function_start) - current_offset = addr - function_start; + ExecutionContext exe_ctx; + CalculateExecutionContext(exe_ctx); + InstructionList instruction_list; + InstructionSP prev_insn; + bool prefer_file_cache = true; // Read from file + uint32_t inst_to_choose = 0; + + for (uint32_t i = 1; i <= loop_count; i++) { + // Adjust the address to read from. + resolved_addr.Slide(-2); + AddressRange range(resolved_addr, i * 2); + uint32_t insn_size = 0; + + disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); + + uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); + if (num_insns) { + prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); + insn_size = prev_insn->GetOpcode().GetByteSize(); + if (i == 1 && insn_size == 2) { + // This looks like a valid 2-byte instruction (but it could be a part + // of upper 4 byte instruction). + instruction_list.Append(prev_insn); + inst_to_choose = 1; + } else if (i == 2) { + // Here we may get one 4-byte instruction or two 2-byte instructions. + if (num_insns == 2) { + // Looks like there are two 2-byte instructions above our breakpoint + // target address. + // Now the upper 2-byte instruction is either a valid 2-byte + // instruction or could be a part of it's upper 4-byte instruction. + // In both cases we don't care because in this case lower 2-byte + // instruction is definitely a valid instruction + // and whatever i=1 iteration has found out is true. + inst_to_choose = 1; + break; + } else if (insn_size == 4) { + // This instruction claims its a valid 4-byte instruction. But it + // could be a part of it's upper 4-byte instruction. + // Lets try scanning upper 2 bytes to verify this. + instruction_list.Append(prev_insn); + inst_to_choose = 2; + } + } else if (i == 3) { + if (insn_size == 4) + // FIXME: We reached here that means instruction at [target - 4] has + // already claimed to be a 4-byte instruction, + // and now instruction at [target - 6] is also claiming that it's a + // 4-byte instruction. This can not be true. + // In this case we can not decide the valid previous instruction so + // we let lldb set the breakpoint at the address given by user. + inst_to_choose = 0; + else + // This is straight-forward + inst_to_choose = 2; + break; } - - // If breakpoint address is start of function then we dont have to do anything. - if (current_offset == 0) - return breakable_addr; - else - loop_count = current_offset / 2; - - if (loop_count > 3) - { - // Scan previous 6 bytes - if (IsMips16 | IsMicromips) - loop_count = 3; - // For mips-only, instructions are always 4 bytes, so scan previous 4 bytes only. - else - loop_count = 2; + } else { + // Decode failed, bytes do not form a valid instruction. So whatever + // previous iteration has found out is true. + if (i > 1) { + inst_to_choose = i - 1; + break; } + } + } - // Create Disassembler Instance - lldb::DisassemblerSP disasm_sp(Disassembler::FindPlugin(m_arch, nullptr, nullptr)); - - ExecutionContext exe_ctx; - CalculateExecutionContext(exe_ctx); - InstructionList instruction_list; - InstructionSP prev_insn; - bool prefer_file_cache = true; // Read from file - uint32_t inst_to_choose = 0; - - for (uint32_t i = 1; i <= loop_count; i++) - { - // Adjust the address to read from. - resolved_addr.Slide (-2); - AddressRange range(resolved_addr, i*2); - uint32_t insn_size = 0; - - disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); - - uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); - if (num_insns) - { - prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); - insn_size = prev_insn->GetOpcode().GetByteSize(); - if (i == 1 && insn_size == 2) - { - // This looks like a valid 2-byte instruction (but it could be a part of upper 4 byte instruction). - instruction_list.Append(prev_insn); - inst_to_choose = 1; - } - else if (i == 2) - { - // Here we may get one 4-byte instruction or two 2-byte instructions. - if (num_insns == 2) - { - // Looks like there are two 2-byte instructions above our breakpoint target address. - // Now the upper 2-byte instruction is either a valid 2-byte instruction or could be a part of it's upper 4-byte instruction. - // In both cases we don't care because in this case lower 2-byte instruction is definitely a valid instruction - // and whatever i=1 iteration has found out is true. - inst_to_choose = 1; - break; - } - else if (insn_size == 4) - { - // This instruction claims its a valid 4-byte instruction. But it could be a part of it's upper 4-byte instruction. - // Lets try scanning upper 2 bytes to verify this. - instruction_list.Append(prev_insn); - inst_to_choose = 2; - } - } - else if (i == 3) - { - if (insn_size == 4) - // FIXME: We reached here that means instruction at [target - 4] has already claimed to be a 4-byte instruction, - // and now instruction at [target - 6] is also claiming that it's a 4-byte instruction. This can not be true. - // In this case we can not decide the valid previous instruction so we let lldb set the breakpoint at the address given by user. - inst_to_choose = 0; - else - // This is straight-forward - inst_to_choose = 2; - break; - } - } - else - { - // Decode failed, bytes do not form a valid instruction. So whatever previous iteration has found out is true. - if (i > 1) - { - inst_to_choose = i - 1; - break; - } - } - } + // Check if we are able to find any valid instruction. + if (inst_to_choose) { + if (inst_to_choose > instruction_list.GetSize()) + inst_to_choose--; + prev_insn = instruction_list.GetInstructionAtIndex(inst_to_choose - 1); - // Check if we are able to find any valid instruction. - if (inst_to_choose) - { - if (inst_to_choose > instruction_list.GetSize()) - inst_to_choose--; - prev_insn = instruction_list.GetInstructionAtIndex(inst_to_choose - 1); - - if (prev_insn->HasDelaySlot()) - { - uint32_t shift_size = prev_insn->GetOpcode().GetByteSize(); - // Adjust the breakable address - breakable_addr = addr - shift_size; - if (log) - log->Printf ("Target::%s Breakpoint at 0x%8.8" PRIx64 " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", __FUNCTION__, addr, breakable_addr); - } - } - break; - } + if (prev_insn->HasDelaySlot()) { + uint32_t shift_size = prev_insn->GetOpcode().GetByteSize(); + // Adjust the breakable address + breakable_addr = addr - shift_size; + if (log) + log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64 + " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", + __FUNCTION__, addr, breakable_addr); + } } - return breakable_addr; + break; + } + } + return breakable_addr; } -SourceManager & -Target::GetSourceManager () -{ - if (!m_source_manager_ap) - m_source_manager_ap.reset (new SourceManager(shared_from_this())); - return *m_source_manager_ap; +SourceManager &Target::GetSourceManager() { + if (!m_source_manager_ap) + m_source_manager_ap.reset(new SourceManager(shared_from_this())); + return *m_source_manager_ap; } -ClangModulesDeclVendor * -Target::GetClangModulesDeclVendor () -{ - static std::mutex s_clang_modules_decl_vendor_mutex; // If this is contended we can make it per-target +ClangModulesDeclVendor *Target::GetClangModulesDeclVendor() { + static std::mutex s_clang_modules_decl_vendor_mutex; // If this is contended + // we can make it + // per-target - { - std::lock_guard<std::mutex> guard(s_clang_modules_decl_vendor_mutex); + { + std::lock_guard<std::mutex> guard(s_clang_modules_decl_vendor_mutex); - if (!m_clang_modules_decl_vendor_ap) - { - m_clang_modules_decl_vendor_ap.reset(ClangModulesDeclVendor::Create(*this)); - } + if (!m_clang_modules_decl_vendor_ap) { + m_clang_modules_decl_vendor_ap.reset( + ClangModulesDeclVendor::Create(*this)); } - - return m_clang_modules_decl_vendor_ap.get(); -} + } -Target::StopHookSP -Target::CreateStopHook () -{ - lldb::user_id_t new_uid = ++m_stop_hook_next_id; - Target::StopHookSP stop_hook_sp (new StopHook(shared_from_this(), new_uid)); - m_stop_hooks[new_uid] = stop_hook_sp; - return stop_hook_sp; + return m_clang_modules_decl_vendor_ap.get(); } -bool -Target::RemoveStopHookByID (lldb::user_id_t user_id) -{ - size_t num_removed = m_stop_hooks.erase(user_id); - return (num_removed != 0); +Target::StopHookSP Target::CreateStopHook() { + lldb::user_id_t new_uid = ++m_stop_hook_next_id; + Target::StopHookSP stop_hook_sp(new StopHook(shared_from_this(), new_uid)); + m_stop_hooks[new_uid] = stop_hook_sp; + return stop_hook_sp; } -void -Target::RemoveAllStopHooks () -{ - m_stop_hooks.clear(); +bool Target::RemoveStopHookByID(lldb::user_id_t user_id) { + size_t num_removed = m_stop_hooks.erase(user_id); + return (num_removed != 0); } -Target::StopHookSP -Target::GetStopHookByID (lldb::user_id_t user_id) -{ - StopHookSP found_hook; - - StopHookCollection::iterator specified_hook_iter; - specified_hook_iter = m_stop_hooks.find (user_id); - if (specified_hook_iter != m_stop_hooks.end()) - found_hook = (*specified_hook_iter).second; - return found_hook; -} +void Target::RemoveAllStopHooks() { m_stop_hooks.clear(); } -bool -Target::SetStopHookActiveStateByID (lldb::user_id_t user_id, bool active_state) -{ - StopHookCollection::iterator specified_hook_iter; - specified_hook_iter = m_stop_hooks.find (user_id); - if (specified_hook_iter == m_stop_hooks.end()) - return false; - - (*specified_hook_iter).second->SetIsActive (active_state); - return true; -} +Target::StopHookSP Target::GetStopHookByID(lldb::user_id_t user_id) { + StopHookSP found_hook; -void -Target::SetAllStopHooksActiveState (bool active_state) -{ - StopHookCollection::iterator pos, end = m_stop_hooks.end(); - for (pos = m_stop_hooks.begin(); pos != end; pos++) - { - (*pos).second->SetIsActive (active_state); - } + StopHookCollection::iterator specified_hook_iter; + specified_hook_iter = m_stop_hooks.find(user_id); + if (specified_hook_iter != m_stop_hooks.end()) + found_hook = (*specified_hook_iter).second; + return found_hook; } -void -Target::RunStopHooks () -{ - if (m_suppress_stop_hooks) - return; - - if (!m_process_sp) - return; - - // <rdar://problem/12027563> make sure we check that we are not stopped because of us running a user expression - // since in that case we do not want to run the stop-hooks - if (m_process_sp->GetModIDRef().IsLastResumeForUserExpression()) - return; - - if (m_stop_hooks.empty()) - return; - - StopHookCollection::iterator pos, end = m_stop_hooks.end(); - - // If there aren't any active stop hooks, don't bother either: - bool any_active_hooks = false; - for (pos = m_stop_hooks.begin(); pos != end; pos++) - { - if ((*pos).second->IsActive()) - { - any_active_hooks = true; - break; - } - } - if (!any_active_hooks) - return; - - CommandReturnObject result; - - std::vector<ExecutionContext> exc_ctx_with_reasons; - std::vector<SymbolContext> sym_ctx_with_reasons; - - ThreadList &cur_threadlist = m_process_sp->GetThreadList(); - size_t num_threads = cur_threadlist.GetSize(); - for (size_t i = 0; i < num_threads; i++) - { - lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex (i); - if (cur_thread_sp->ThreadStoppedForAReason()) - { - lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0); - exc_ctx_with_reasons.push_back(ExecutionContext(m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get())); - sym_ctx_with_reasons.push_back(cur_frame_sp->GetSymbolContext(eSymbolContextEverything)); +bool Target::SetStopHookActiveStateByID(lldb::user_id_t user_id, + bool active_state) { + StopHookCollection::iterator specified_hook_iter; + specified_hook_iter = m_stop_hooks.find(user_id); + if (specified_hook_iter == m_stop_hooks.end()) + return false; + + (*specified_hook_iter).second->SetIsActive(active_state); + return true; +} + +void Target::SetAllStopHooksActiveState(bool active_state) { + StopHookCollection::iterator pos, end = m_stop_hooks.end(); + for (pos = m_stop_hooks.begin(); pos != end; pos++) { + (*pos).second->SetIsActive(active_state); + } +} + +void Target::RunStopHooks() { + if (m_suppress_stop_hooks) + return; + + if (!m_process_sp) + return; + + // <rdar://problem/12027563> make sure we check that we are not stopped + // because of us running a user expression + // since in that case we do not want to run the stop-hooks + if (m_process_sp->GetModIDRef().IsLastResumeForUserExpression()) + return; + + if (m_stop_hooks.empty()) + return; + + StopHookCollection::iterator pos, end = m_stop_hooks.end(); + + // If there aren't any active stop hooks, don't bother either: + bool any_active_hooks = false; + for (pos = m_stop_hooks.begin(); pos != end; pos++) { + if ((*pos).second->IsActive()) { + any_active_hooks = true; + break; + } + } + if (!any_active_hooks) + return; + + CommandReturnObject result; + + std::vector<ExecutionContext> exc_ctx_with_reasons; + std::vector<SymbolContext> sym_ctx_with_reasons; + + ThreadList &cur_threadlist = m_process_sp->GetThreadList(); + size_t num_threads = cur_threadlist.GetSize(); + for (size_t i = 0; i < num_threads; i++) { + lldb::ThreadSP cur_thread_sp = cur_threadlist.GetThreadAtIndex(i); + if (cur_thread_sp->ThreadStoppedForAReason()) { + lldb::StackFrameSP cur_frame_sp = cur_thread_sp->GetStackFrameAtIndex(0); + exc_ctx_with_reasons.push_back(ExecutionContext( + m_process_sp.get(), cur_thread_sp.get(), cur_frame_sp.get())); + sym_ctx_with_reasons.push_back( + cur_frame_sp->GetSymbolContext(eSymbolContextEverything)); + } + } + + // If no threads stopped for a reason, don't run the stop-hooks. + size_t num_exe_ctx = exc_ctx_with_reasons.size(); + if (num_exe_ctx == 0) + return; + + result.SetImmediateOutputStream(m_debugger.GetAsyncOutputStream()); + result.SetImmediateErrorStream(m_debugger.GetAsyncErrorStream()); + + bool keep_going = true; + bool hooks_ran = false; + bool print_hook_header = (m_stop_hooks.size() != 1); + bool print_thread_header = (num_exe_ctx != 1); + + for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++) { + // result.Clear(); + StopHookSP cur_hook_sp = (*pos).second; + if (!cur_hook_sp->IsActive()) + continue; + + bool any_thread_matched = false; + for (size_t i = 0; keep_going && i < num_exe_ctx; i++) { + if ((cur_hook_sp->GetSpecifier() == nullptr || + cur_hook_sp->GetSpecifier()->SymbolContextMatches( + sym_ctx_with_reasons[i])) && + (cur_hook_sp->GetThreadSpecifier() == nullptr || + cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests( + exc_ctx_with_reasons[i].GetThreadRef()))) { + if (!hooks_ran) { + hooks_ran = true; } - } - - // If no threads stopped for a reason, don't run the stop-hooks. - size_t num_exe_ctx = exc_ctx_with_reasons.size(); - if (num_exe_ctx == 0) - return; - - result.SetImmediateOutputStream (m_debugger.GetAsyncOutputStream()); - result.SetImmediateErrorStream (m_debugger.GetAsyncErrorStream()); - - bool keep_going = true; - bool hooks_ran = false; - bool print_hook_header = (m_stop_hooks.size() != 1); - bool print_thread_header = (num_exe_ctx != 1); - - for (pos = m_stop_hooks.begin(); keep_going && pos != end; pos++) - { - // result.Clear(); - StopHookSP cur_hook_sp = (*pos).second; - if (!cur_hook_sp->IsActive()) - continue; - - bool any_thread_matched = false; - for (size_t i = 0; keep_going && i < num_exe_ctx; i++) - { - if ((cur_hook_sp->GetSpecifier() == nullptr - || cur_hook_sp->GetSpecifier()->SymbolContextMatches(sym_ctx_with_reasons[i])) - && (cur_hook_sp->GetThreadSpecifier() == nullptr - || cur_hook_sp->GetThreadSpecifier()->ThreadPassesBasicTests(exc_ctx_with_reasons[i].GetThreadRef()))) - { - if (!hooks_ran) - { - hooks_ran = true; - } - if (print_hook_header && !any_thread_matched) - { - const char *cmd = (cur_hook_sp->GetCommands().GetSize() == 1 ? - cur_hook_sp->GetCommands().GetStringAtIndex(0) : - nullptr); - if (cmd) - result.AppendMessageWithFormat("\n- Hook %" PRIu64 " (%s)\n", cur_hook_sp->GetID(), cmd); - else - result.AppendMessageWithFormat("\n- Hook %" PRIu64 "\n", cur_hook_sp->GetID()); - any_thread_matched = true; - } - - if (print_thread_header) - result.AppendMessageWithFormat("-- Thread %d\n", exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID()); - - CommandInterpreterRunOptions options; - options.SetStopOnContinue (true); - options.SetStopOnError (true); - options.SetEchoCommands (false); - options.SetPrintResults (true); - options.SetAddToHistory (false); - - GetDebugger().GetCommandInterpreter().HandleCommands (cur_hook_sp->GetCommands(), - &exc_ctx_with_reasons[i], - options, - result); - - // If the command started the target going again, we should bag out of - // running the stop hooks. - if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult) || - (result.GetStatus() == eReturnStatusSuccessContinuingResult)) - { - result.AppendMessageWithFormat ("Aborting stop hooks, hook %" PRIu64 " set the program running.", cur_hook_sp->GetID()); - keep_going = false; - } - } + if (print_hook_header && !any_thread_matched) { + const char *cmd = + (cur_hook_sp->GetCommands().GetSize() == 1 + ? cur_hook_sp->GetCommands().GetStringAtIndex(0) + : nullptr); + if (cmd) + result.AppendMessageWithFormat("\n- Hook %" PRIu64 " (%s)\n", + cur_hook_sp->GetID(), cmd); + else + result.AppendMessageWithFormat("\n- Hook %" PRIu64 "\n", + cur_hook_sp->GetID()); + any_thread_matched = true; } - } - - result.GetImmediateOutputStream()->Flush(); - result.GetImmediateErrorStream()->Flush(); -} -const TargetPropertiesSP & -Target::GetGlobalProperties() -{ - // NOTE: intentional leak so we don't crash if global destructor chain gets - // called as other threads still use the result of this function - static TargetPropertiesSP *g_settings_sp_ptr = nullptr; - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_settings_sp_ptr = new TargetPropertiesSP(new TargetProperties(nullptr)); - }); - return *g_settings_sp_ptr; -} - -Error -Target::Install (ProcessLaunchInfo *launch_info) -{ - Error error; - PlatformSP platform_sp (GetPlatform()); - if (platform_sp) - { - if (platform_sp->IsRemote()) - { - if (platform_sp->IsConnected()) - { - // Install all files that have an install path, and always install the - // main executable when connected to a remote platform - const ModuleList& modules = GetImages(); - const size_t num_images = modules.GetSize(); - for (size_t idx = 0; idx < num_images; ++idx) + if (print_thread_header) + result.AppendMessageWithFormat( + "-- Thread %d\n", + exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID()); + + CommandInterpreterRunOptions options; + options.SetStopOnContinue(true); + options.SetStopOnError(true); + options.SetEchoCommands(false); + options.SetPrintResults(true); + options.SetAddToHistory(false); + + GetDebugger().GetCommandInterpreter().HandleCommands( + cur_hook_sp->GetCommands(), &exc_ctx_with_reasons[i], options, + result); + + // If the command started the target going again, we should bag out of + // running the stop hooks. + if ((result.GetStatus() == eReturnStatusSuccessContinuingNoResult) || + (result.GetStatus() == eReturnStatusSuccessContinuingResult)) { + result.AppendMessageWithFormat("Aborting stop hooks, hook %" PRIu64 + " set the program running.", + cur_hook_sp->GetID()); + keep_going = false; + } + } + } + } + + result.GetImmediateOutputStream()->Flush(); + result.GetImmediateErrorStream()->Flush(); +} + +const TargetPropertiesSP &Target::GetGlobalProperties() { + // NOTE: intentional leak so we don't crash if global destructor chain gets + // called as other threads still use the result of this function + static TargetPropertiesSP *g_settings_sp_ptr = nullptr; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_settings_sp_ptr = new TargetPropertiesSP(new TargetProperties(nullptr)); + }); + return *g_settings_sp_ptr; +} + +Error Target::Install(ProcessLaunchInfo *launch_info) { + Error error; + PlatformSP platform_sp(GetPlatform()); + if (platform_sp) { + if (platform_sp->IsRemote()) { + if (platform_sp->IsConnected()) { + // Install all files that have an install path, and always install the + // main executable when connected to a remote platform + const ModuleList &modules = GetImages(); + const size_t num_images = modules.GetSize(); + for (size_t idx = 0; idx < num_images; ++idx) { + ModuleSP module_sp(modules.GetModuleAtIndex(idx)); + if (module_sp) { + const bool is_main_executable = module_sp == GetExecutableModule(); + FileSpec local_file(module_sp->GetFileSpec()); + if (local_file) { + FileSpec remote_file(module_sp->GetRemoteInstallFileSpec()); + if (!remote_file) { + if (is_main_executable) // TODO: add setting for always + // installing main executable??? { - ModuleSP module_sp(modules.GetModuleAtIndex(idx)); - if (module_sp) - { - const bool is_main_executable = module_sp == GetExecutableModule(); - FileSpec local_file (module_sp->GetFileSpec()); - if (local_file) - { - FileSpec remote_file (module_sp->GetRemoteInstallFileSpec()); - if (!remote_file) - { - if (is_main_executable) // TODO: add setting for always installing main executable??? - { - // Always install the main executable - remote_file = platform_sp->GetRemoteWorkingDirectory(); - remote_file.AppendPathComponent(module_sp->GetFileSpec().GetFilename().GetCString()); - } - } - if (remote_file) - { - error = platform_sp->Install(local_file, remote_file); - if (error.Success()) - { - module_sp->SetPlatformFileSpec(remote_file); - if (is_main_executable) - { - platform_sp->SetFilePermissions(remote_file, 0700); - if (launch_info) - launch_info->SetExecutableFile(remote_file, false); - } - } - else - break; - } - } - } + // Always install the main executable + remote_file = platform_sp->GetRemoteWorkingDirectory(); + remote_file.AppendPathComponent( + module_sp->GetFileSpec().GetFilename().GetCString()); } + } + if (remote_file) { + error = platform_sp->Install(local_file, remote_file); + if (error.Success()) { + module_sp->SetPlatformFileSpec(remote_file); + if (is_main_executable) { + platform_sp->SetFilePermissions(remote_file, 0700); + if (launch_info) + launch_info->SetExecutableFile(remote_file, false); + } + } else + break; + } } + } } + } } - return error; -} - -bool -Target::ResolveLoadAddress (addr_t load_addr, Address &so_addr, uint32_t stop_id) -{ - return m_section_load_history.ResolveLoadAddress(stop_id, load_addr, so_addr); -} - -bool -Target::ResolveFileAddress (lldb::addr_t file_addr, Address &resolved_addr) -{ - return m_images.ResolveFileAddress(file_addr, resolved_addr); -} - -bool -Target::SetSectionLoadAddress (const SectionSP §ion_sp, addr_t new_section_load_addr, bool warn_multiple) -{ - const addr_t old_section_load_addr = m_section_load_history.GetSectionLoadAddress (SectionLoadHistory::eStopIDNow, section_sp); - if (old_section_load_addr != new_section_load_addr) - { - uint32_t stop_id = 0; - ProcessSP process_sp(GetProcessSP()); - if (process_sp) - stop_id = process_sp->GetStopID(); - else - stop_id = m_section_load_history.GetLastStopID(); - if (m_section_load_history.SetSectionLoadAddress (stop_id, section_sp, new_section_load_addr, warn_multiple)) - return true; // Return true if the section load address was changed... - } - return false; // Return false to indicate nothing changed + } + return error; } -size_t -Target::UnloadModuleSections (const ModuleList &module_list) -{ - size_t section_unload_count = 0; - size_t num_modules = module_list.GetSize(); - for (size_t i=0; i<num_modules; ++i) - { - section_unload_count += UnloadModuleSections (module_list.GetModuleAtIndex(i)); - } - return section_unload_count; +bool Target::ResolveLoadAddress(addr_t load_addr, Address &so_addr, + uint32_t stop_id) { + return m_section_load_history.ResolveLoadAddress(stop_id, load_addr, so_addr); } -size_t -Target::UnloadModuleSections (const lldb::ModuleSP &module_sp) -{ - uint32_t stop_id = 0; - ProcessSP process_sp(GetProcessSP()); - if (process_sp) - stop_id = process_sp->GetStopID(); - else - stop_id = m_section_load_history.GetLastStopID(); - SectionList *sections = module_sp->GetSectionList(); - size_t section_unload_count = 0; - if (sections) - { - const uint32_t num_sections = sections->GetNumSections(0); - for (uint32_t i = 0; i < num_sections; ++i) - { - section_unload_count += m_section_load_history.SetSectionUnloaded(stop_id, sections->GetSectionAtIndex(i)); - } - } - return section_unload_count; +bool Target::ResolveFileAddress(lldb::addr_t file_addr, + Address &resolved_addr) { + return m_images.ResolveFileAddress(file_addr, resolved_addr); } -bool -Target::SetSectionUnloaded (const lldb::SectionSP §ion_sp) -{ +bool Target::SetSectionLoadAddress(const SectionSP §ion_sp, + addr_t new_section_load_addr, + bool warn_multiple) { + const addr_t old_section_load_addr = + m_section_load_history.GetSectionLoadAddress( + SectionLoadHistory::eStopIDNow, section_sp); + if (old_section_load_addr != new_section_load_addr) { uint32_t stop_id = 0; ProcessSP process_sp(GetProcessSP()); if (process_sp) - stop_id = process_sp->GetStopID(); + stop_id = process_sp->GetStopID(); else - stop_id = m_section_load_history.GetLastStopID(); - return m_section_load_history.SetSectionUnloaded (stop_id, section_sp); -} - -bool -Target::SetSectionUnloaded (const lldb::SectionSP §ion_sp, addr_t load_addr) -{ - uint32_t stop_id = 0; + stop_id = m_section_load_history.GetLastStopID(); + if (m_section_load_history.SetSectionLoadAddress( + stop_id, section_sp, new_section_load_addr, warn_multiple)) + return true; // Return true if the section load address was changed... + } + return false; // Return false to indicate nothing changed +} + +size_t Target::UnloadModuleSections(const ModuleList &module_list) { + size_t section_unload_count = 0; + size_t num_modules = module_list.GetSize(); + for (size_t i = 0; i < num_modules; ++i) { + section_unload_count += + UnloadModuleSections(module_list.GetModuleAtIndex(i)); + } + return section_unload_count; +} + +size_t Target::UnloadModuleSections(const lldb::ModuleSP &module_sp) { + uint32_t stop_id = 0; + ProcessSP process_sp(GetProcessSP()); + if (process_sp) + stop_id = process_sp->GetStopID(); + else + stop_id = m_section_load_history.GetLastStopID(); + SectionList *sections = module_sp->GetSectionList(); + size_t section_unload_count = 0; + if (sections) { + const uint32_t num_sections = sections->GetNumSections(0); + for (uint32_t i = 0; i < num_sections; ++i) { + section_unload_count += m_section_load_history.SetSectionUnloaded( + stop_id, sections->GetSectionAtIndex(i)); + } + } + return section_unload_count; +} + +bool Target::SetSectionUnloaded(const lldb::SectionSP §ion_sp) { + uint32_t stop_id = 0; + ProcessSP process_sp(GetProcessSP()); + if (process_sp) + stop_id = process_sp->GetStopID(); + else + stop_id = m_section_load_history.GetLastStopID(); + return m_section_load_history.SetSectionUnloaded(stop_id, section_sp); +} + +bool Target::SetSectionUnloaded(const lldb::SectionSP §ion_sp, + addr_t load_addr) { + uint32_t stop_id = 0; + ProcessSP process_sp(GetProcessSP()); + if (process_sp) + stop_id = process_sp->GetStopID(); + else + stop_id = m_section_load_history.GetLastStopID(); + return m_section_load_history.SetSectionUnloaded(stop_id, section_sp, + load_addr); +} + +void Target::ClearAllLoadedSections() { m_section_load_history.Clear(); } + +Error Target::Launch(ProcessLaunchInfo &launch_info, Stream *stream) { + Error error; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_TARGET)); + + if (log) + log->Printf("Target::%s() called for %s", __FUNCTION__, + launch_info.GetExecutableFile().GetPath().c_str()); + + StateType state = eStateInvalid; + + // Scope to temporarily get the process state in case someone has manually + // remotely connected already to a process and we can skip the platform + // launching. + { ProcessSP process_sp(GetProcessSP()); - if (process_sp) - stop_id = process_sp->GetStopID(); - else - stop_id = m_section_load_history.GetLastStopID(); - return m_section_load_history.SetSectionUnloaded (stop_id, section_sp, load_addr); -} - -void -Target::ClearAllLoadedSections () -{ - m_section_load_history.Clear(); -} - -Error -Target::Launch (ProcessLaunchInfo &launch_info, Stream *stream) -{ - Error error; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET)); + if (process_sp) { + state = process_sp->GetState(); + if (log) + log->Printf( + "Target::%s the process exists, and its current state is %s", + __FUNCTION__, StateAsCString(state)); + } else { + if (log) + log->Printf("Target::%s the process instance doesn't currently exist.", + __FUNCTION__); + } + } + + launch_info.GetFlags().Set(eLaunchFlagDebug); + + // Get the value of synchronous execution here. If you wait till after you + // have started to + // run, then you could have hit a breakpoint, whose command might switch the + // value, and + // then you'll pick up that incorrect value. + Debugger &debugger = GetDebugger(); + const bool synchronous_execution = + debugger.GetCommandInterpreter().GetSynchronous(); + + PlatformSP platform_sp(GetPlatform()); + + // Finalize the file actions, and if none were given, default to opening + // up a pseudo terminal + const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false; + if (log) + log->Printf("Target::%s have platform=%s, platform_sp->IsHost()=%s, " + "default_to_use_pty=%s", + __FUNCTION__, platform_sp ? "true" : "false", + platform_sp ? (platform_sp->IsHost() ? "true" : "false") + : "n/a", + default_to_use_pty ? "true" : "false"); + + launch_info.FinalizeFileActions(this, default_to_use_pty); + + if (state == eStateConnected) { + if (launch_info.GetFlags().Test(eLaunchFlagLaunchInTTY)) { + error.SetErrorString( + "can't launch in tty when launching through a remote connection"); + return error; + } + } + + if (!launch_info.GetArchitecture().IsValid()) + launch_info.GetArchitecture() = GetArchitecture(); + + // If we're not already connected to the process, and if we have a platform + // that can launch a process for debugging, go ahead and do that here. + if (state != eStateConnected && platform_sp && + platform_sp->CanDebugProcess()) { if (log) - log->Printf ("Target::%s() called for %s", __FUNCTION__, launch_info.GetExecutableFile().GetPath().c_str ()); - - StateType state = eStateInvalid; - - // Scope to temporarily get the process state in case someone has manually - // remotely connected already to a process and we can skip the platform - // launching. - { - ProcessSP process_sp (GetProcessSP()); - - if (process_sp) - { - state = process_sp->GetState(); - if (log) - log->Printf ("Target::%s the process exists, and its current state is %s", __FUNCTION__, StateAsCString (state)); - } - else - { - if (log) - log->Printf ("Target::%s the process instance doesn't currently exist.", __FUNCTION__); - } - } + log->Printf("Target::%s asking the platform to debug the process", + __FUNCTION__); - launch_info.GetFlags().Set (eLaunchFlagDebug); - - // Get the value of synchronous execution here. If you wait till after you have started to - // run, then you could have hit a breakpoint, whose command might switch the value, and - // then you'll pick up that incorrect value. - Debugger &debugger = GetDebugger(); - const bool synchronous_execution = debugger.GetCommandInterpreter().GetSynchronous (); - - PlatformSP platform_sp (GetPlatform()); - - // Finalize the file actions, and if none were given, default to opening - // up a pseudo terminal - const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false; + // Get a weak pointer to the previous process if we have one + ProcessWP process_wp; + if (m_process_sp) + process_wp = m_process_sp; + m_process_sp = + GetPlatform()->DebugProcess(launch_info, debugger, this, error); + + // Cleanup the old process since someone might still have a strong + // reference to this process and we would like to allow it to cleanup + // as much as it can without the object being destroyed. We try to + // lock the shared pointer and if that works, then someone else still + // has a strong reference to the process. + + ProcessSP old_process_sp(process_wp.lock()); + if (old_process_sp) + old_process_sp->Finalize(); + } else { if (log) - log->Printf ("Target::%s have platform=%s, platform_sp->IsHost()=%s, default_to_use_pty=%s", - __FUNCTION__, - platform_sp ? "true" : "false", - platform_sp ? (platform_sp->IsHost () ? "true" : "false") : "n/a", - default_to_use_pty ? "true" : "false"); - - launch_info.FinalizeFileActions (this, default_to_use_pty); - - if (state == eStateConnected) - { - if (launch_info.GetFlags().Test (eLaunchFlagLaunchInTTY)) - { - error.SetErrorString("can't launch in tty when launching through a remote connection"); - return error; - } - } - - if (!launch_info.GetArchitecture().IsValid()) - launch_info.GetArchitecture() = GetArchitecture(); + log->Printf("Target::%s the platform doesn't know how to debug a " + "process, getting a process plugin to do this for us.", + __FUNCTION__); - // If we're not already connected to the process, and if we have a platform that can launch a process for debugging, go ahead and do that here. - if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ()) - { - if (log) - log->Printf ("Target::%s asking the platform to debug the process", __FUNCTION__); - - // Get a weak pointer to the previous process if we have one - ProcessWP process_wp; - if (m_process_sp) - process_wp = m_process_sp; - m_process_sp = GetPlatform()->DebugProcess (launch_info, - debugger, - this, - error); - - // Cleanup the old process since someone might still have a strong - // reference to this process and we would like to allow it to cleanup - // as much as it can without the object being destroyed. We try to - // lock the shared pointer and if that works, then someone else still - // has a strong reference to the process. - - ProcessSP old_process_sp(process_wp.lock()); - if (old_process_sp) - old_process_sp->Finalize(); + if (state == eStateConnected) { + assert(m_process_sp); + } else { + // Use a Process plugin to construct the process. + const char *plugin_name = launch_info.GetProcessPluginName(); + CreateProcess(launch_info.GetListenerForProcess(debugger), plugin_name, + nullptr); } - else - { - if (log) - log->Printf ("Target::%s the platform doesn't know how to debug a process, getting a process plugin to do this for us.", __FUNCTION__); - - if (state == eStateConnected) - { - assert(m_process_sp); - } - else - { - // Use a Process plugin to construct the process. - const char *plugin_name = launch_info.GetProcessPluginName(); - CreateProcess(launch_info.GetListenerForProcess(debugger), plugin_name, nullptr); - } - // Since we didn't have a platform launch the process, launch it here. - if (m_process_sp) - error = m_process_sp->Launch (launch_info); - } - - if (!m_process_sp) - { - if (error.Success()) - error.SetErrorString("failed to launch or debug process"); - return error; - } + // Since we didn't have a platform launch the process, launch it here. + if (m_process_sp) + error = m_process_sp->Launch(launch_info); + } + if (!m_process_sp) { if (error.Success()) - { - if (synchronous_execution || !launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - { - ListenerSP hijack_listener_sp (launch_info.GetHijackListener()); - if (!hijack_listener_sp) - { - hijack_listener_sp = Listener::MakeListener("lldb.Target.Launch.hijack"); - launch_info.SetHijackListener(hijack_listener_sp); - m_process_sp->HijackProcessEvents(hijack_listener_sp); - } - - StateType state = m_process_sp->WaitForProcessToStop(std::chrono::microseconds(0), nullptr, false, - hijack_listener_sp, nullptr); - - if (state == eStateStopped) - { - if (!launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) - { - if (synchronous_execution) - { - error = m_process_sp->PrivateResume(); - if (error.Success()) - { - state = m_process_sp->WaitForProcessToStop(std::chrono::microseconds(0), nullptr, true, - hijack_listener_sp, stream); - const bool must_be_alive = false; // eStateExited is ok, so this must be false - if (!StateIsStoppedState(state, must_be_alive)) - { - error.SetErrorStringWithFormat("process isn't stopped: %s", StateAsCString(state)); - } - } - } - else - { - m_process_sp->RestoreProcessEvents(); - error = m_process_sp->PrivateResume(); - } - if (!error.Success()) - { - Error error2; - error2.SetErrorStringWithFormat("process resume at entry point failed: %s", error.AsCString()); - error = error2; - } - } - } - else if (state == eStateExited) - { - bool with_shell = !!launch_info.GetShell(); - const int exit_status = m_process_sp->GetExitStatus(); - const char *exit_desc = m_process_sp->GetExitDescription(); -#define LAUNCH_SHELL_MESSAGE "\n'r' and 'run' are aliases that default to launching through a shell.\nTry launching without going through a shell by using 'process launch'." - if (exit_desc && exit_desc[0]) - { - if (with_shell) - error.SetErrorStringWithFormat ("process exited with status %i (%s)" LAUNCH_SHELL_MESSAGE, exit_status, exit_desc); - else - error.SetErrorStringWithFormat ("process exited with status %i (%s)", exit_status, exit_desc); - } - else - { - if (with_shell) - error.SetErrorStringWithFormat ("process exited with status %i" LAUNCH_SHELL_MESSAGE, exit_status); - else - error.SetErrorStringWithFormat ("process exited with status %i", exit_status); - } - } - else - { - error.SetErrorStringWithFormat ("initial process state wasn't stopped: %s", StateAsCString(state)); - } - } - m_process_sp->RestoreProcessEvents (); - } - else - { - Error error2; - error2.SetErrorStringWithFormat ("process launch failed: %s", error.AsCString()); - error = error2; - } + error.SetErrorString("failed to launch or debug process"); return error; -} - -Error -Target::Attach (ProcessAttachInfo &attach_info, Stream *stream) -{ - auto state = eStateInvalid; - auto process_sp = GetProcessSP (); - if (process_sp) - { - state = process_sp->GetState (); - if (process_sp->IsAlive () && state != eStateConnected) - { - if (state == eStateAttaching) - return Error ("process attach is in progress"); - return Error ("a process is already being debugged"); - } - } - - const ModuleSP old_exec_module_sp = GetExecutableModule (); - - // If no process info was specified, then use the target executable - // name as the process to attach to by default - if (!attach_info.ProcessInfoSpecified ()) - { - if (old_exec_module_sp) - attach_info.GetExecutableFile ().GetFilename () = old_exec_module_sp->GetPlatformFileSpec ().GetFilename (); - - if (!attach_info.ProcessInfoSpecified ()) - { - return Error ("no process specified, create a target with a file, or specify the --pid or --name"); - } - } - - const auto platform_sp = GetDebugger ().GetPlatformList ().GetSelectedPlatform (); - ListenerSP hijack_listener_sp; - const bool async = attach_info.GetAsync(); - if (!async) - { - hijack_listener_sp = Listener::MakeListener("lldb.Target.Attach.attach.hijack"); - attach_info.SetHijackListener (hijack_listener_sp); - } - - Error error; - if (state != eStateConnected && platform_sp != nullptr && platform_sp->CanDebugProcess ()) - { - SetPlatform (platform_sp); - process_sp = platform_sp->Attach (attach_info, GetDebugger (), this, error); - } - else - { - if (state != eStateConnected) - { - const char *plugin_name = attach_info.GetProcessPluginName (); - process_sp = CreateProcess (attach_info.GetListenerForProcess (GetDebugger ()), plugin_name, nullptr); - if (process_sp == nullptr) - { - error.SetErrorStringWithFormat ("failed to create process using plugin %s", (plugin_name) ? plugin_name : "null"); - return error; + } + + if (error.Success()) { + if (synchronous_execution || + !launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) { + ListenerSP hijack_listener_sp(launch_info.GetHijackListener()); + if (!hijack_listener_sp) { + hijack_listener_sp = + Listener::MakeListener("lldb.Target.Launch.hijack"); + launch_info.SetHijackListener(hijack_listener_sp); + m_process_sp->HijackProcessEvents(hijack_listener_sp); + } + + StateType state = m_process_sp->WaitForProcessToStop( + std::chrono::microseconds(0), nullptr, false, hijack_listener_sp, + nullptr); + + if (state == eStateStopped) { + if (!launch_info.GetFlags().Test(eLaunchFlagStopAtEntry)) { + if (synchronous_execution) { + error = m_process_sp->PrivateResume(); + if (error.Success()) { + state = m_process_sp->WaitForProcessToStop( + std::chrono::microseconds(0), nullptr, true, + hijack_listener_sp, stream); + const bool must_be_alive = + false; // eStateExited is ok, so this must be false + if (!StateIsStoppedState(state, must_be_alive)) { + error.SetErrorStringWithFormat("process isn't stopped: %s", + StateAsCString(state)); + } } + } else { + m_process_sp->RestoreProcessEvents(); + error = m_process_sp->PrivateResume(); + } + if (!error.Success()) { + Error error2; + error2.SetErrorStringWithFormat( + "process resume at entry point failed: %s", error.AsCString()); + error = error2; + } } - if (hijack_listener_sp) - process_sp->HijackProcessEvents (hijack_listener_sp); - error = process_sp->Attach (attach_info); - } - - if (error.Success () && process_sp) - { - if (async) - { - process_sp->RestoreProcessEvents (); + } else if (state == eStateExited) { + bool with_shell = !!launch_info.GetShell(); + const int exit_status = m_process_sp->GetExitStatus(); + const char *exit_desc = m_process_sp->GetExitDescription(); +#define LAUNCH_SHELL_MESSAGE \ + "\n'r' and 'run' are aliases that default to launching through a " \ + "shell.\nTry launching without going through a shell by using 'process " \ + "launch'." + if (exit_desc && exit_desc[0]) { + if (with_shell) + error.SetErrorStringWithFormat( + "process exited with status %i (%s)" LAUNCH_SHELL_MESSAGE, + exit_status, exit_desc); + else + error.SetErrorStringWithFormat("process exited with status %i (%s)", + exit_status, exit_desc); + } else { + if (with_shell) + error.SetErrorStringWithFormat( + "process exited with status %i" LAUNCH_SHELL_MESSAGE, + exit_status); + else + error.SetErrorStringWithFormat("process exited with status %i", + exit_status); } + } else { + error.SetErrorStringWithFormat( + "initial process state wasn't stopped: %s", StateAsCString(state)); + } + } + m_process_sp->RestoreProcessEvents(); + } else { + Error error2; + error2.SetErrorStringWithFormat("process launch failed: %s", + error.AsCString()); + error = error2; + } + return error; +} + +Error Target::Attach(ProcessAttachInfo &attach_info, Stream *stream) { + auto state = eStateInvalid; + auto process_sp = GetProcessSP(); + if (process_sp) { + state = process_sp->GetState(); + if (process_sp->IsAlive() && state != eStateConnected) { + if (state == eStateAttaching) + return Error("process attach is in progress"); + return Error("a process is already being debugged"); + } + } + + const ModuleSP old_exec_module_sp = GetExecutableModule(); + + // If no process info was specified, then use the target executable + // name as the process to attach to by default + if (!attach_info.ProcessInfoSpecified()) { + if (old_exec_module_sp) + attach_info.GetExecutableFile().GetFilename() = + old_exec_module_sp->GetPlatformFileSpec().GetFilename(); + + if (!attach_info.ProcessInfoSpecified()) { + return Error("no process specified, create a target with a file, or " + "specify the --pid or --name"); + } + } + + const auto platform_sp = + GetDebugger().GetPlatformList().GetSelectedPlatform(); + ListenerSP hijack_listener_sp; + const bool async = attach_info.GetAsync(); + if (!async) { + hijack_listener_sp = + Listener::MakeListener("lldb.Target.Attach.attach.hijack"); + attach_info.SetHijackListener(hijack_listener_sp); + } + + Error error; + if (state != eStateConnected && platform_sp != nullptr && + platform_sp->CanDebugProcess()) { + SetPlatform(platform_sp); + process_sp = platform_sp->Attach(attach_info, GetDebugger(), this, error); + } else { + if (state != eStateConnected) { + const char *plugin_name = attach_info.GetProcessPluginName(); + process_sp = + CreateProcess(attach_info.GetListenerForProcess(GetDebugger()), + plugin_name, nullptr); + if (process_sp == nullptr) { + error.SetErrorStringWithFormat( + "failed to create process using plugin %s", + (plugin_name) ? plugin_name : "null"); + return error; + } + } + if (hijack_listener_sp) + process_sp->HijackProcessEvents(hijack_listener_sp); + error = process_sp->Attach(attach_info); + } + + if (error.Success() && process_sp) { + if (async) { + process_sp->RestoreProcessEvents(); + } else { + state = process_sp->WaitForProcessToStop( + std::chrono::microseconds(0), nullptr, false, + attach_info.GetHijackListener(), stream); + process_sp->RestoreProcessEvents(); + + if (state != eStateStopped) { + const char *exit_desc = process_sp->GetExitDescription(); + if (exit_desc) + error.SetErrorStringWithFormat("%s", exit_desc); else - { - state = process_sp->WaitForProcessToStop(std::chrono::microseconds(0), nullptr, false, - attach_info.GetHijackListener(), stream); - process_sp->RestoreProcessEvents (); - - if (state != eStateStopped) - { - const char *exit_desc = process_sp->GetExitDescription (); - if (exit_desc) - error.SetErrorStringWithFormat ("%s", exit_desc); - else - error.SetErrorString ("process did not stop (no such process or permission problem?)"); - process_sp->Destroy (false); - } - } + error.SetErrorString( + "process did not stop (no such process or permission problem?)"); + process_sp->Destroy(false); + } } - return error; + } + return error; } //-------------------------------------------------------------- // Target::StopHook //-------------------------------------------------------------- -Target::StopHook::StopHook (lldb::TargetSP target_sp, lldb::user_id_t uid) : - UserID (uid), - m_target_sp (target_sp), - m_commands (), - m_specifier_sp (), - m_thread_spec_ap(), - m_active (true) -{ -} +Target::StopHook::StopHook(lldb::TargetSP target_sp, lldb::user_id_t uid) + : UserID(uid), m_target_sp(target_sp), m_commands(), m_specifier_sp(), + m_thread_spec_ap(), m_active(true) {} -Target::StopHook::StopHook (const StopHook &rhs) : - UserID (rhs.GetID()), - m_target_sp (rhs.m_target_sp), - m_commands (rhs.m_commands), - m_specifier_sp (rhs.m_specifier_sp), - m_thread_spec_ap (), - m_active (rhs.m_active) -{ - if (rhs.m_thread_spec_ap) - m_thread_spec_ap.reset (new ThreadSpec(*rhs.m_thread_spec_ap.get())); +Target::StopHook::StopHook(const StopHook &rhs) + : UserID(rhs.GetID()), m_target_sp(rhs.m_target_sp), + m_commands(rhs.m_commands), m_specifier_sp(rhs.m_specifier_sp), + m_thread_spec_ap(), m_active(rhs.m_active) { + if (rhs.m_thread_spec_ap) + m_thread_spec_ap.reset(new ThreadSpec(*rhs.m_thread_spec_ap.get())); } - + Target::StopHook::~StopHook() = default; -void -Target::StopHook::SetSpecifier(SymbolContextSpecifier *specifier) -{ - m_specifier_sp.reset(specifier); +void Target::StopHook::SetSpecifier(SymbolContextSpecifier *specifier) { + m_specifier_sp.reset(specifier); } -void -Target::StopHook::SetThreadSpecifier (ThreadSpec *specifier) -{ - m_thread_spec_ap.reset (specifier); +void Target::StopHook::SetThreadSpecifier(ThreadSpec *specifier) { + m_thread_spec_ap.reset(specifier); } -void -Target::StopHook::GetDescription (Stream *s, lldb::DescriptionLevel level) const -{ - int indent_level = s->GetIndentLevel(); +void Target::StopHook::GetDescription(Stream *s, + lldb::DescriptionLevel level) const { + int indent_level = s->GetIndentLevel(); - s->SetIndentLevel(indent_level + 2); + s->SetIndentLevel(indent_level + 2); - s->Printf ("Hook: %" PRIu64 "\n", GetID()); - if (m_active) - s->Indent ("State: enabled\n"); - else - s->Indent ("State: disabled\n"); - - if (m_specifier_sp) - { - s->Indent(); - s->PutCString ("Specifier:\n"); - s->SetIndentLevel (indent_level + 4); - m_specifier_sp->GetDescription (s, level); - s->SetIndentLevel (indent_level + 2); - } + s->Printf("Hook: %" PRIu64 "\n", GetID()); + if (m_active) + s->Indent("State: enabled\n"); + else + s->Indent("State: disabled\n"); - if (m_thread_spec_ap) - { - StreamString tmp; - s->Indent("Thread:\n"); - m_thread_spec_ap->GetDescription (&tmp, level); - s->SetIndentLevel (indent_level + 4); - s->Indent (tmp.GetData()); - s->PutCString ("\n"); - s->SetIndentLevel (indent_level + 2); - } + if (m_specifier_sp) { + s->Indent(); + s->PutCString("Specifier:\n"); + s->SetIndentLevel(indent_level + 4); + m_specifier_sp->GetDescription(s, level); + s->SetIndentLevel(indent_level + 2); + } + + if (m_thread_spec_ap) { + StreamString tmp; + s->Indent("Thread:\n"); + m_thread_spec_ap->GetDescription(&tmp, level); + s->SetIndentLevel(indent_level + 4); + s->Indent(tmp.GetData()); + s->PutCString("\n"); + s->SetIndentLevel(indent_level + 2); + } - s->Indent ("Commands: \n"); - s->SetIndentLevel (indent_level + 4); - uint32_t num_commands = m_commands.GetSize(); - for (uint32_t i = 0; i < num_commands; i++) - { - s->Indent(m_commands.GetStringAtIndex(i)); - s->PutCString ("\n"); - } - s->SetIndentLevel (indent_level); + s->Indent("Commands: \n"); + s->SetIndentLevel(indent_level + 4); + uint32_t num_commands = m_commands.GetSize(); + for (uint32_t i = 0; i < num_commands; i++) { + s->Indent(m_commands.GetStringAtIndex(i)); + s->PutCString("\n"); + } + s->SetIndentLevel(indent_level); } //-------------------------------------------------------------- // class TargetProperties //-------------------------------------------------------------- -OptionEnumValueElement -lldb_private::g_dynamic_value_types[] = -{ - { eNoDynamicValues, "no-dynamic-values", "Don't calculate the dynamic type of values"}, - { eDynamicCanRunTarget, "run-target", "Calculate the dynamic type of values even if you have to run the target."}, - { eDynamicDontRunTarget, "no-run-target", "Calculate the dynamic type of values, but don't run the target."}, - { 0, nullptr, nullptr } -}; - -static OptionEnumValueElement -g_inline_breakpoint_enums[] = -{ - { eInlineBreakpointsNever, "never", "Never look for inline breakpoint locations (fastest). This setting should only be used if you know that no inlining occurs in your programs."}, - { eInlineBreakpointsHeaders, "headers", "Only check for inline breakpoint locations when setting breakpoints in header files, but not when setting breakpoint in implementation source files (default)."}, - { eInlineBreakpointsAlways, "always", "Always look for inline breakpoint locations when setting file and line breakpoints (slower but most accurate)."}, - { 0, nullptr, nullptr } -}; - -typedef enum x86DisassemblyFlavor -{ - eX86DisFlavorDefault, - eX86DisFlavorIntel, - eX86DisFlavorATT +OptionEnumValueElement lldb_private::g_dynamic_value_types[] = { + {eNoDynamicValues, "no-dynamic-values", + "Don't calculate the dynamic type of values"}, + {eDynamicCanRunTarget, "run-target", "Calculate the dynamic type of values " + "even if you have to run the target."}, + {eDynamicDontRunTarget, "no-run-target", + "Calculate the dynamic type of values, but don't run the target."}, + {0, nullptr, nullptr}}; + +static OptionEnumValueElement g_inline_breakpoint_enums[] = { + {eInlineBreakpointsNever, "never", "Never look for inline breakpoint " + "locations (fastest). This setting " + "should only be used if you know that " + "no inlining occurs in your programs."}, + {eInlineBreakpointsHeaders, "headers", + "Only check for inline breakpoint locations when setting breakpoints in " + "header files, but not when setting breakpoint in implementation source " + "files (default)."}, + {eInlineBreakpointsAlways, "always", + "Always look for inline breakpoint locations when setting file and line " + "breakpoints (slower but most accurate)."}, + {0, nullptr, nullptr}}; + +typedef enum x86DisassemblyFlavor { + eX86DisFlavorDefault, + eX86DisFlavorIntel, + eX86DisFlavorATT } x86DisassemblyFlavor; -static OptionEnumValueElement -g_x86_dis_flavor_value_types[] = -{ - { eX86DisFlavorDefault, "default", "Disassembler default (currently att)."}, - { eX86DisFlavorIntel, "intel", "Intel disassembler flavor."}, - { eX86DisFlavorATT, "att", "AT&T disassembler flavor."}, - { 0, nullptr, nullptr } -}; - -static OptionEnumValueElement -g_hex_immediate_style_values[] = -{ - { Disassembler::eHexStyleC, "c", "C-style (0xffff)."}, - { Disassembler::eHexStyleAsm, "asm", "Asm-style (0ffffh)."}, - { 0, nullptr, nullptr } -}; - -static OptionEnumValueElement -g_load_script_from_sym_file_values[] = -{ - { eLoadScriptFromSymFileTrue, "true", "Load debug scripts inside symbol files"}, - { eLoadScriptFromSymFileFalse, "false", "Do not load debug scripts inside symbol files."}, - { eLoadScriptFromSymFileWarn, "warn", "Warn about debug scripts inside symbol files but do not load them."}, - { 0, nullptr, nullptr } -}; - -static OptionEnumValueElement -g_load_current_working_dir_lldbinit_values[] = -{ - { eLoadCWDlldbinitTrue, "true", "Load .lldbinit files from current directory"}, - { eLoadCWDlldbinitFalse, "false", "Do not load .lldbinit files from current directory"}, - { eLoadCWDlldbinitWarn, "warn", "Warn about loading .lldbinit files from current directory"}, - { 0, nullptr, nullptr } -}; - -static OptionEnumValueElement -g_memory_module_load_level_values[] = -{ - { eMemoryModuleLoadLevelMinimal, "minimal" , "Load minimal information when loading modules from memory. Currently this setting loads sections only."}, - { eMemoryModuleLoadLevelPartial, "partial" , "Load partial information when loading modules from memory. Currently this setting loads sections and function bounds."}, - { eMemoryModuleLoadLevelComplete, "complete", "Load complete information when loading modules from memory. Currently this setting loads sections and all symbols."}, - { 0, nullptr, nullptr } -}; - -static PropertyDefinition -g_properties[] = -{ - { "default-arch" , OptionValue::eTypeArch , true , 0 , nullptr, nullptr, "Default architecture to choose, when there's a choice." }, - { "move-to-nearest-code" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Move breakpoints to nearest code." }, - { "language" , OptionValue::eTypeLanguage , false, eLanguageTypeUnknown , nullptr, nullptr, "The language to use when interpreting expressions entered in commands." }, - { "expr-prefix" , OptionValue::eTypeFileSpec , false, 0 , nullptr, nullptr, "Path to a file containing expressions to be prepended to all expressions." }, - { "prefer-dynamic-value" , OptionValue::eTypeEnum , false, eDynamicDontRunTarget , nullptr, g_dynamic_value_types, "Should printed values be shown as their dynamic value." }, - { "enable-synthetic-value" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Should synthetic values be used by default whenever available." }, - { "skip-prologue" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Skip function prologues when setting breakpoints by name." }, - { "source-map" , OptionValue::eTypePathMap , false, 0 , nullptr, nullptr, "Source path remappings are used to track the change of location between a source file when built, and " - "where it exists on the current system. It consists of an array of duples, the first element of each duple is " - "some part (starting at the root) of the path to the file when it was built, " - "and the second is where the remainder of the original build hierarchy is rooted on the local system. " - "Each element of the array is checked in order and the first one that results in a match wins." }, - { "exec-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , nullptr, nullptr, "Executable search paths to use when locating executable files whose paths don't match the local file system." }, - { "debug-file-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , nullptr, nullptr, "List of directories to be searched when locating debug symbol files." }, - { "clang-module-search-paths" , OptionValue::eTypeFileSpecList, false, 0 , nullptr, nullptr, "List of directories to be searched when locating modules for Clang." }, - { "auto-import-clang-modules" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Automatically load Clang modules referred to by the program." }, - { "auto-apply-fixits" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Automatically apply fix-it hints to expressions." }, - { "notify-about-fixits" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Print the fixed expression text." }, - { "max-children-count" , OptionValue::eTypeSInt64 , false, 256 , nullptr, nullptr, "Maximum number of children to expand in any level of depth." }, - { "max-string-summary-length" , OptionValue::eTypeSInt64 , false, 1024 , nullptr, nullptr, "Maximum number of characters to show when using %s in summary strings." }, - { "max-memory-read-size" , OptionValue::eTypeSInt64 , false, 1024 , nullptr, nullptr, "Maximum number of bytes that 'memory read' will fetch before --force must be specified." }, - { "breakpoints-use-platform-avoid-list", OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Consult the platform module avoid list when setting non-module specific breakpoints." }, - { "arg0" , OptionValue::eTypeString , false, 0 , nullptr, nullptr, "The first argument passed to the program in the argument array which can be different from the executable itself." }, - { "run-args" , OptionValue::eTypeArgs , false, 0 , nullptr, nullptr, "A list containing all the arguments to be passed to the executable when it is run. Note that this does NOT include the argv[0] which is in target.arg0." }, - { "env-vars" , OptionValue::eTypeDictionary, false, OptionValue::eTypeString , nullptr, nullptr, "A list of all the environment variables to be passed to the executable's environment, and their values." }, - { "inherit-env" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Inherit the environment from the process that is running LLDB." }, - { "input-path" , OptionValue::eTypeFileSpec , false, 0 , nullptr, nullptr, "The file/path to be used by the executable program for reading its standard input." }, - { "output-path" , OptionValue::eTypeFileSpec , false, 0 , nullptr, nullptr, "The file/path to be used by the executable program for writing its standard output." }, - { "error-path" , OptionValue::eTypeFileSpec , false, 0 , nullptr, nullptr, "The file/path to be used by the executable program for writing its standard error." }, - { "detach-on-error" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "debugserver will detach (rather than killing) a process if it loses connection with lldb." }, - { "disable-aslr" , OptionValue::eTypeBoolean , false, true , nullptr, nullptr, "Disable Address Space Layout Randomization (ASLR)" }, - { "disable-stdio" , OptionValue::eTypeBoolean , false, false , nullptr, nullptr, "Disable stdin/stdout for process (e.g. for a GUI application)" }, - { "inline-breakpoint-strategy" , OptionValue::eTypeEnum , false, eInlineBreakpointsAlways , nullptr, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. " - "Breakpoint locations can end up being inlined by the compiler, so that a compile unit 'a.c' might contain an inlined function from another source file. " - "Usually this is limited to breakpoint locations from inlined functions from header or other include files, or more accurately non-implementation source files. " - "Sometimes code might #include implementation files and cause inlined breakpoint locations in inlined implementation files. " - "Always checking for inlined breakpoint locations can be expensive (memory and time), so if you have a project with many headers " - "and find that setting breakpoints is slow, then you can change this setting to headers. " - "This setting allows you to control exactly which strategy is used when setting " - "file and line breakpoints." }, - // FIXME: This is the wrong way to do per-architecture settings, but we don't have a general per architecture settings system in place yet. - { "x86-disassembly-flavor" , OptionValue::eTypeEnum , false, eX86DisFlavorDefault, nullptr, g_x86_dis_flavor_value_types, "The default disassembly flavor to use for x86 or x86-64 targets." }, - { "use-hex-immediates" , OptionValue::eTypeBoolean , false, true, nullptr, nullptr, "Show immediates in disassembly as hexadecimal." }, - { "hex-immediate-style" , OptionValue::eTypeEnum , false, Disassembler::eHexStyleC, nullptr, g_hex_immediate_style_values, "Which style to use for printing hexadecimal disassembly values." }, - { "use-fast-stepping" , OptionValue::eTypeBoolean , false, true, nullptr, nullptr, "Use a fast stepping algorithm based on running from branch to branch rather than instruction single-stepping." }, - { "load-script-from-symbol-file" , OptionValue::eTypeEnum , false, eLoadScriptFromSymFileWarn, nullptr, g_load_script_from_sym_file_values, "Allow LLDB to load scripting resources embedded in symbol files when available." }, - { "load-cwd-lldbinit" , OptionValue::eTypeEnum , false, eLoadCWDlldbinitWarn, nullptr, g_load_current_working_dir_lldbinit_values, "Allow LLDB to .lldbinit files from the current directory automatically." }, - { "memory-module-load-level" , OptionValue::eTypeEnum , false, eMemoryModuleLoadLevelComplete, nullptr, g_memory_module_load_level_values, - "Loading modules from memory can be slow as reading the symbol tables and other data can take a long time depending on your connection to the debug target. " - "This setting helps users control how much information gets loaded when loading modules from memory." - "'complete' is the default value for this setting which will load all sections and symbols by reading them from memory (slowest, most accurate). " - "'partial' will load sections and attempt to find function bounds without downloading the symbol table (faster, still accurate, missing symbol names). " - "'minimal' is the fastest setting and will load section data with no symbols, but should rarely be used as stack frames in these memory regions will be inaccurate and not provide any context (fastest). " }, - { "display-expression-in-crashlogs" , OptionValue::eTypeBoolean , false, false, nullptr, nullptr, "Expressions that crash will show up in crash logs if the host system supports executable specific crash log strings and this setting is set to true." }, - { "trap-handler-names" , OptionValue::eTypeArray , true, OptionValue::eTypeString, nullptr, nullptr, "A list of trap handler function names, e.g. a common Unix user process one is _sigtramp." }, - { "display-runtime-support-values" , OptionValue::eTypeBoolean , false, false, nullptr, nullptr, "If true, LLDB will show variables that are meant to support the operation of a language's runtime support." }, - { "non-stop-mode" , OptionValue::eTypeBoolean , false, 0, nullptr, nullptr, "Disable lock-step debugging, instead control threads independently." }, - { nullptr , OptionValue::eTypeInvalid , false, 0 , nullptr, nullptr, nullptr } -}; - -enum -{ - ePropertyDefaultArch, - ePropertyMoveToNearestCode, - ePropertyLanguage, - ePropertyExprPrefix, - ePropertyPreferDynamic, - ePropertyEnableSynthetic, - ePropertySkipPrologue, - ePropertySourceMap, - ePropertyExecutableSearchPaths, - ePropertyDebugFileSearchPaths, - ePropertyClangModuleSearchPaths, - ePropertyAutoImportClangModules, - ePropertyAutoApplyFixIts, - ePropertyNotifyAboutFixIts, - ePropertyMaxChildrenCount, - ePropertyMaxSummaryLength, - ePropertyMaxMemReadSize, - ePropertyBreakpointUseAvoidList, - ePropertyArg0, - ePropertyRunArgs, - ePropertyEnvVars, - ePropertyInheritEnv, - ePropertyInputPath, - ePropertyOutputPath, - ePropertyErrorPath, - ePropertyDetachOnError, - ePropertyDisableASLR, - ePropertyDisableSTDIO, - ePropertyInlineStrategy, - ePropertyDisassemblyFlavor, - ePropertyUseHexImmediates, - ePropertyHexImmediateStyle, - ePropertyUseFastStepping, - ePropertyLoadScriptFromSymbolFile, - ePropertyLoadCWDlldbinitFile, - ePropertyMemoryModuleLoadLevel, - ePropertyDisplayExpressionsInCrashlogs, - ePropertyTrapHandlerNames, - ePropertyDisplayRuntimeSupportValues, - ePropertyNonStopModeEnabled, - ePropertyExperimental +static OptionEnumValueElement g_x86_dis_flavor_value_types[] = { + {eX86DisFlavorDefault, "default", "Disassembler default (currently att)."}, + {eX86DisFlavorIntel, "intel", "Intel disassembler flavor."}, + {eX86DisFlavorATT, "att", "AT&T disassembler flavor."}, + {0, nullptr, nullptr}}; + +static OptionEnumValueElement g_hex_immediate_style_values[] = { + {Disassembler::eHexStyleC, "c", "C-style (0xffff)."}, + {Disassembler::eHexStyleAsm, "asm", "Asm-style (0ffffh)."}, + {0, nullptr, nullptr}}; + +static OptionEnumValueElement g_load_script_from_sym_file_values[] = { + {eLoadScriptFromSymFileTrue, "true", + "Load debug scripts inside symbol files"}, + {eLoadScriptFromSymFileFalse, "false", + "Do not load debug scripts inside symbol files."}, + {eLoadScriptFromSymFileWarn, "warn", + "Warn about debug scripts inside symbol files but do not load them."}, + {0, nullptr, nullptr}}; + +static OptionEnumValueElement g_load_current_working_dir_lldbinit_values[] = { + {eLoadCWDlldbinitTrue, "true", + "Load .lldbinit files from current directory"}, + {eLoadCWDlldbinitFalse, "false", + "Do not load .lldbinit files from current directory"}, + {eLoadCWDlldbinitWarn, "warn", + "Warn about loading .lldbinit files from current directory"}, + {0, nullptr, nullptr}}; + +static OptionEnumValueElement g_memory_module_load_level_values[] = { + {eMemoryModuleLoadLevelMinimal, "minimal", + "Load minimal information when loading modules from memory. Currently " + "this setting loads sections only."}, + {eMemoryModuleLoadLevelPartial, "partial", + "Load partial information when loading modules from memory. Currently " + "this setting loads sections and function bounds."}, + {eMemoryModuleLoadLevelComplete, "complete", + "Load complete information when loading modules from memory. Currently " + "this setting loads sections and all symbols."}, + {0, nullptr, nullptr}}; + +static PropertyDefinition g_properties[] = { + {"default-arch", OptionValue::eTypeArch, true, 0, nullptr, nullptr, + "Default architecture to choose, when there's a choice."}, + {"move-to-nearest-code", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "Move breakpoints to nearest code."}, + {"language", OptionValue::eTypeLanguage, false, eLanguageTypeUnknown, + nullptr, nullptr, + "The language to use when interpreting expressions entered in commands."}, + {"expr-prefix", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + "Path to a file containing expressions to be prepended to all " + "expressions."}, + {"prefer-dynamic-value", OptionValue::eTypeEnum, false, + eDynamicDontRunTarget, nullptr, g_dynamic_value_types, + "Should printed values be shown as their dynamic value."}, + {"enable-synthetic-value", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "Should synthetic values be used by default whenever available."}, + {"skip-prologue", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + "Skip function prologues when setting breakpoints by name."}, + {"source-map", OptionValue::eTypePathMap, false, 0, nullptr, nullptr, + "Source path remappings are used to track the change of location between " + "a source file when built, and " + "where it exists on the current system. It consists of an array of " + "duples, the first element of each duple is " + "some part (starting at the root) of the path to the file when it was " + "built, " + "and the second is where the remainder of the original build hierarchy is " + "rooted on the local system. " + "Each element of the array is checked in order and the first one that " + "results in a match wins."}, + {"exec-search-paths", OptionValue::eTypeFileSpecList, false, 0, nullptr, + nullptr, "Executable search paths to use when locating executable files " + "whose paths don't match the local file system."}, + {"debug-file-search-paths", OptionValue::eTypeFileSpecList, false, 0, + nullptr, nullptr, + "List of directories to be searched when locating debug symbol files."}, + {"clang-module-search-paths", OptionValue::eTypeFileSpecList, false, 0, + nullptr, nullptr, + "List of directories to be searched when locating modules for Clang."}, + {"auto-import-clang-modules", OptionValue::eTypeBoolean, false, true, + nullptr, nullptr, + "Automatically load Clang modules referred to by the program."}, + {"auto-apply-fixits", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "Automatically apply fix-it hints to expressions."}, + {"notify-about-fixits", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "Print the fixed expression text."}, + {"max-children-count", OptionValue::eTypeSInt64, false, 256, nullptr, + nullptr, "Maximum number of children to expand in any level of depth."}, + {"max-string-summary-length", OptionValue::eTypeSInt64, false, 1024, + nullptr, nullptr, + "Maximum number of characters to show when using %s in summary strings."}, + {"max-memory-read-size", OptionValue::eTypeSInt64, false, 1024, nullptr, + nullptr, "Maximum number of bytes that 'memory read' will fetch before " + "--force must be specified."}, + {"breakpoints-use-platform-avoid-list", OptionValue::eTypeBoolean, false, + true, nullptr, nullptr, "Consult the platform module avoid list when " + "setting non-module specific breakpoints."}, + {"arg0", OptionValue::eTypeString, false, 0, nullptr, nullptr, + "The first argument passed to the program in the argument array which can " + "be different from the executable itself."}, + {"run-args", OptionValue::eTypeArgs, false, 0, nullptr, nullptr, + "A list containing all the arguments to be passed to the executable when " + "it is run. Note that this does NOT include the argv[0] which is in " + "target.arg0."}, + {"env-vars", OptionValue::eTypeDictionary, false, OptionValue::eTypeString, + nullptr, nullptr, "A list of all the environment variables to be passed " + "to the executable's environment, and their values."}, + {"inherit-env", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + "Inherit the environment from the process that is running LLDB."}, + {"input-path", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + "The file/path to be used by the executable program for reading its " + "standard input."}, + {"output-path", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + "The file/path to be used by the executable program for writing its " + "standard output."}, + {"error-path", OptionValue::eTypeFileSpec, false, 0, nullptr, nullptr, + "The file/path to be used by the executable program for writing its " + "standard error."}, + {"detach-on-error", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "debugserver will detach (rather than killing) a process if it " + "loses connection with lldb."}, + {"disable-aslr", OptionValue::eTypeBoolean, false, true, nullptr, nullptr, + "Disable Address Space Layout Randomization (ASLR)"}, + {"disable-stdio", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, + "Disable stdin/stdout for process (e.g. for a GUI application)"}, + {"inline-breakpoint-strategy", OptionValue::eTypeEnum, false, + eInlineBreakpointsAlways, nullptr, g_inline_breakpoint_enums, + "The strategy to use when settings breakpoints by file and line. " + "Breakpoint locations can end up being inlined by the compiler, so that a " + "compile unit 'a.c' might contain an inlined function from another source " + "file. " + "Usually this is limited to breakpoint locations from inlined functions " + "from header or other include files, or more accurately " + "non-implementation source files. " + "Sometimes code might #include implementation files and cause inlined " + "breakpoint locations in inlined implementation files. " + "Always checking for inlined breakpoint locations can be expensive " + "(memory and time), so if you have a project with many headers " + "and find that setting breakpoints is slow, then you can change this " + "setting to headers. " + "This setting allows you to control exactly which strategy is used when " + "setting " + "file and line breakpoints."}, + // FIXME: This is the wrong way to do per-architecture settings, but we + // don't have a general per architecture settings system in place yet. + {"x86-disassembly-flavor", OptionValue::eTypeEnum, false, + eX86DisFlavorDefault, nullptr, g_x86_dis_flavor_value_types, + "The default disassembly flavor to use for x86 or x86-64 targets."}, + {"use-hex-immediates", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "Show immediates in disassembly as hexadecimal."}, + {"hex-immediate-style", OptionValue::eTypeEnum, false, + Disassembler::eHexStyleC, nullptr, g_hex_immediate_style_values, + "Which style to use for printing hexadecimal disassembly values."}, + {"use-fast-stepping", OptionValue::eTypeBoolean, false, true, nullptr, + nullptr, "Use a fast stepping algorithm based on running from branch to " + "branch rather than instruction single-stepping."}, + {"load-script-from-symbol-file", OptionValue::eTypeEnum, false, + eLoadScriptFromSymFileWarn, nullptr, g_load_script_from_sym_file_values, + "Allow LLDB to load scripting resources embedded in symbol files when " + "available."}, + {"load-cwd-lldbinit", OptionValue::eTypeEnum, false, eLoadCWDlldbinitWarn, + nullptr, g_load_current_working_dir_lldbinit_values, + "Allow LLDB to .lldbinit files from the current directory automatically."}, + {"memory-module-load-level", OptionValue::eTypeEnum, false, + eMemoryModuleLoadLevelComplete, nullptr, g_memory_module_load_level_values, + "Loading modules from memory can be slow as reading the symbol tables and " + "other data can take a long time depending on your connection to the " + "debug target. " + "This setting helps users control how much information gets loaded when " + "loading modules from memory." + "'complete' is the default value for this setting which will load all " + "sections and symbols by reading them from memory (slowest, most " + "accurate). " + "'partial' will load sections and attempt to find function bounds without " + "downloading the symbol table (faster, still accurate, missing symbol " + "names). " + "'minimal' is the fastest setting and will load section data with no " + "symbols, but should rarely be used as stack frames in these memory " + "regions will be inaccurate and not provide any context (fastest). "}, + {"display-expression-in-crashlogs", OptionValue::eTypeBoolean, false, false, + nullptr, nullptr, "Expressions that crash will show up in crash logs if " + "the host system supports executable specific crash log " + "strings and this setting is set to true."}, + {"trap-handler-names", OptionValue::eTypeArray, true, + OptionValue::eTypeString, nullptr, nullptr, + "A list of trap handler function names, e.g. a common Unix user process " + "one is _sigtramp."}, + {"display-runtime-support-values", OptionValue::eTypeBoolean, false, false, + nullptr, nullptr, "If true, LLDB will show variables that are meant to " + "support the operation of a language's runtime " + "support."}, + {"non-stop-mode", OptionValue::eTypeBoolean, false, 0, nullptr, nullptr, + "Disable lock-step debugging, instead control threads independently."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; + +enum { + ePropertyDefaultArch, + ePropertyMoveToNearestCode, + ePropertyLanguage, + ePropertyExprPrefix, + ePropertyPreferDynamic, + ePropertyEnableSynthetic, + ePropertySkipPrologue, + ePropertySourceMap, + ePropertyExecutableSearchPaths, + ePropertyDebugFileSearchPaths, + ePropertyClangModuleSearchPaths, + ePropertyAutoImportClangModules, + ePropertyAutoApplyFixIts, + ePropertyNotifyAboutFixIts, + ePropertyMaxChildrenCount, + ePropertyMaxSummaryLength, + ePropertyMaxMemReadSize, + ePropertyBreakpointUseAvoidList, + ePropertyArg0, + ePropertyRunArgs, + ePropertyEnvVars, + ePropertyInheritEnv, + ePropertyInputPath, + ePropertyOutputPath, + ePropertyErrorPath, + ePropertyDetachOnError, + ePropertyDisableASLR, + ePropertyDisableSTDIO, + ePropertyInlineStrategy, + ePropertyDisassemblyFlavor, + ePropertyUseHexImmediates, + ePropertyHexImmediateStyle, + ePropertyUseFastStepping, + ePropertyLoadScriptFromSymbolFile, + ePropertyLoadCWDlldbinitFile, + ePropertyMemoryModuleLoadLevel, + ePropertyDisplayExpressionsInCrashlogs, + ePropertyTrapHandlerNames, + ePropertyDisplayRuntimeSupportValues, + ePropertyNonStopModeEnabled, + ePropertyExperimental }; -class TargetOptionValueProperties : public OptionValueProperties -{ +class TargetOptionValueProperties : public OptionValueProperties { public: - TargetOptionValueProperties (const ConstString &name) : - OptionValueProperties (name), - m_target(nullptr), - m_got_host_env (false) - { - } - - // This constructor is used when creating TargetOptionValueProperties when it - // is part of a new lldb_private::Target instance. It will copy all current - // global property values as needed - TargetOptionValueProperties (Target *target, const TargetPropertiesSP &target_properties_sp) : - OptionValueProperties(*target_properties_sp->GetValueProperties()), - m_target (target), - m_got_host_env (false) - { - } + TargetOptionValueProperties(const ConstString &name) + : OptionValueProperties(name), m_target(nullptr), m_got_host_env(false) {} + + // This constructor is used when creating TargetOptionValueProperties when it + // is part of a new lldb_private::Target instance. It will copy all current + // global property values as needed + TargetOptionValueProperties(Target *target, + const TargetPropertiesSP &target_properties_sp) + : OptionValueProperties(*target_properties_sp->GetValueProperties()), + m_target(target), m_got_host_env(false) {} + + const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, + bool will_modify, + uint32_t idx) const override { + // When getting the value for a key from the target options, we will always + // try and grab the setting from the current target if there is one. Else we + // just + // use the one from this instance. + if (idx == ePropertyEnvVars) + GetHostEnvironmentIfNeeded(); + + if (exe_ctx) { + Target *target = exe_ctx->GetTargetPtr(); + if (target) { + TargetOptionValueProperties *target_properties = + static_cast<TargetOptionValueProperties *>( + target->GetValueProperties().get()); + if (this != target_properties) + return target_properties->ProtectedGetPropertyAtIndex(idx); + } + } + return ProtectedGetPropertyAtIndex(idx); + } + + lldb::TargetSP GetTargetSP() { return m_target->shared_from_this(); } - const Property * - GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override - { - // When getting the value for a key from the target options, we will always - // try and grab the setting from the current target if there is one. Else we just - // use the one from this instance. - if (idx == ePropertyEnvVars) - GetHostEnvironmentIfNeeded (); - - if (exe_ctx) - { - Target *target = exe_ctx->GetTargetPtr(); - if (target) - { - TargetOptionValueProperties *target_properties = static_cast<TargetOptionValueProperties *>(target->GetValueProperties().get()); - if (this != target_properties) - return target_properties->ProtectedGetPropertyAtIndex (idx); - } - } - return ProtectedGetPropertyAtIndex (idx); - } - - lldb::TargetSP - GetTargetSP () - { - return m_target->shared_from_this(); - } - protected: - void - GetHostEnvironmentIfNeeded () const - { - if (!m_got_host_env) - { - if (m_target) - { - m_got_host_env = true; - const uint32_t idx = ePropertyInheritEnv; - if (GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0)) - { - PlatformSP platform_sp (m_target->GetPlatform()); - if (platform_sp) - { - StringList env; - if (platform_sp->GetEnvironment(env)) - { - OptionValueDictionary *env_dict = GetPropertyAtIndexAsOptionValueDictionary(nullptr, ePropertyEnvVars); - if (env_dict) - { - const bool can_replace = false; - const size_t envc = env.GetSize(); - for (size_t idx=0; idx<envc; idx++) - { - const char *env_entry = env.GetStringAtIndex (idx); - if (env_entry) - { - const char *equal_pos = ::strchr(env_entry, '='); - ConstString key; - // It is ok to have environment variables with no values - const char *value = nullptr; - if (equal_pos) - { - key.SetCStringWithLength(env_entry, equal_pos - env_entry); - if (equal_pos[1]) - value = equal_pos + 1; - } - else - { - key.SetCString(env_entry); - } - // Don't allow existing keys to be replaced with ones we get from the platform environment - env_dict->SetValueForKey(key, OptionValueSP(new OptionValueString(value)), can_replace); - } - } - } - } + void GetHostEnvironmentIfNeeded() const { + if (!m_got_host_env) { + if (m_target) { + m_got_host_env = true; + const uint32_t idx = ePropertyInheritEnv; + if (GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0)) { + PlatformSP platform_sp(m_target->GetPlatform()); + if (platform_sp) { + StringList env; + if (platform_sp->GetEnvironment(env)) { + OptionValueDictionary *env_dict = + GetPropertyAtIndexAsOptionValueDictionary(nullptr, + ePropertyEnvVars); + if (env_dict) { + const bool can_replace = false; + const size_t envc = env.GetSize(); + for (size_t idx = 0; idx < envc; idx++) { + const char *env_entry = env.GetStringAtIndex(idx); + if (env_entry) { + const char *equal_pos = ::strchr(env_entry, '='); + ConstString key; + // It is ok to have environment variables with no values + const char *value = nullptr; + if (equal_pos) { + key.SetCStringWithLength(env_entry, + equal_pos - env_entry); + if (equal_pos[1]) + value = equal_pos + 1; + } else { + key.SetCString(env_entry); } + // Don't allow existing keys to be replaced with ones we get + // from the platform environment + env_dict->SetValueForKey( + key, OptionValueSP(new OptionValueString(value)), + can_replace); + } } + } } + } } + } } - Target *m_target; - mutable bool m_got_host_env; + } + Target *m_target; + mutable bool m_got_host_env; }; //---------------------------------------------------------------------- // TargetProperties //---------------------------------------------------------------------- -static PropertyDefinition -g_experimental_properties[] -{ -{ "inject-local-vars", OptionValue::eTypeBoolean , true, true, nullptr, nullptr, "If true, inject local variables explicitly into the expression text. " - "This will fix symbol resolution when there are name collisions between ivars and local variables. " - "But it can make expressions run much more slowly." }, -{ nullptr, OptionValue::eTypeInvalid , true, 0 , nullptr, nullptr, nullptr } -}; - -enum -{ - ePropertyInjectLocalVars = 0 -}; - -class TargetExperimentalOptionValueProperties : public OptionValueProperties -{ +static PropertyDefinition g_experimental_properties[]{ + {"inject-local-vars", OptionValue::eTypeBoolean, true, true, nullptr, + nullptr, + "If true, inject local variables explicitly into the expression text. " + "This will fix symbol resolution when there are name collisions between " + "ivars and local variables. " + "But it can make expressions run much more slowly."}, + {nullptr, OptionValue::eTypeInvalid, true, 0, nullptr, nullptr, nullptr}}; + +enum { ePropertyInjectLocalVars = 0 }; + +class TargetExperimentalOptionValueProperties : public OptionValueProperties { public: - TargetExperimentalOptionValueProperties () : - OptionValueProperties (ConstString(Properties::GetExperimentalSettingsName())) - { - } + TargetExperimentalOptionValueProperties() + : OptionValueProperties( + ConstString(Properties::GetExperimentalSettingsName())) {} }; -TargetExperimentalProperties::TargetExperimentalProperties() : - Properties(OptionValuePropertiesSP(new TargetExperimentalOptionValueProperties())) -{ - m_collection_sp->Initialize(g_experimental_properties); +TargetExperimentalProperties::TargetExperimentalProperties() + : Properties(OptionValuePropertiesSP( + new TargetExperimentalOptionValueProperties())) { + m_collection_sp->Initialize(g_experimental_properties); } //---------------------------------------------------------------------- // TargetProperties //---------------------------------------------------------------------- -TargetProperties::TargetProperties (Target *target) : - Properties (), - m_launch_info () -{ - if (target) - { - m_collection_sp.reset (new TargetOptionValueProperties(target, Target::GetGlobalProperties())); - - // Set callbacks to update launch_info whenever "settins set" updated any of these properties - m_collection_sp->SetValueChangedCallback(ePropertyArg0, TargetProperties::Arg0ValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyOutputPath, TargetProperties::OutputPathValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyErrorPath, TargetProperties::ErrorPathValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyDetachOnError, TargetProperties::DetachOnErrorValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyDisableASLR, TargetProperties::DisableASLRValueChangedCallback, this); - m_collection_sp->SetValueChangedCallback(ePropertyDisableSTDIO, TargetProperties::DisableSTDIOValueChangedCallback, this); - - m_experimental_properties_up.reset(new TargetExperimentalProperties()); - m_collection_sp->AppendProperty (ConstString(Properties::GetExperimentalSettingsName()), - ConstString("Experimental settings - setting these won't produce errors if the setting is not present."), - true, - m_experimental_properties_up->GetValueProperties()); - - // Update m_launch_info once it was created - Arg0ValueChangedCallback(this, nullptr); - RunArgsValueChangedCallback(this, nullptr); - //EnvVarsValueChangedCallback(this, nullptr); // FIXME: cause segfault in Target::GetPlatform() - InputPathValueChangedCallback(this, nullptr); - OutputPathValueChangedCallback(this, nullptr); - ErrorPathValueChangedCallback(this, nullptr); - DetachOnErrorValueChangedCallback(this, nullptr); - DisableASLRValueChangedCallback(this, nullptr); - DisableSTDIOValueChangedCallback(this, nullptr); - } - else - { - m_collection_sp.reset (new TargetOptionValueProperties(ConstString("target"))); - m_collection_sp->Initialize(g_properties); - m_experimental_properties_up.reset(new TargetExperimentalProperties()); - m_collection_sp->AppendProperty (ConstString(Properties::GetExperimentalSettingsName()), - ConstString("Experimental settings - setting these won't produce errors if the setting is not present."), - true, - m_experimental_properties_up->GetValueProperties()); - m_collection_sp->AppendProperty(ConstString("process"), - ConstString("Settings specific to processes."), - true, - Process::GetGlobalProperties()->GetValueProperties()); - } +TargetProperties::TargetProperties(Target *target) + : Properties(), m_launch_info() { + if (target) { + m_collection_sp.reset( + new TargetOptionValueProperties(target, Target::GetGlobalProperties())); + + // Set callbacks to update launch_info whenever "settins set" updated any of + // these properties + m_collection_sp->SetValueChangedCallback( + ePropertyArg0, TargetProperties::Arg0ValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyRunArgs, TargetProperties::RunArgsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyEnvVars, TargetProperties::EnvVarsValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyInputPath, TargetProperties::InputPathValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyOutputPath, TargetProperties::OutputPathValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyErrorPath, TargetProperties::ErrorPathValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyDetachOnError, + TargetProperties::DetachOnErrorValueChangedCallback, this); + m_collection_sp->SetValueChangedCallback( + ePropertyDisableASLR, TargetProperties::DisableASLRValueChangedCallback, + this); + m_collection_sp->SetValueChangedCallback( + ePropertyDisableSTDIO, + TargetProperties::DisableSTDIOValueChangedCallback, this); + + m_experimental_properties_up.reset(new TargetExperimentalProperties()); + m_collection_sp->AppendProperty( + ConstString(Properties::GetExperimentalSettingsName()), + ConstString("Experimental settings - setting these won't produce " + "errors if the setting is not present."), + true, m_experimental_properties_up->GetValueProperties()); + + // Update m_launch_info once it was created + Arg0ValueChangedCallback(this, nullptr); + RunArgsValueChangedCallback(this, nullptr); + // EnvVarsValueChangedCallback(this, nullptr); // FIXME: cause segfault in + // Target::GetPlatform() + InputPathValueChangedCallback(this, nullptr); + OutputPathValueChangedCallback(this, nullptr); + ErrorPathValueChangedCallback(this, nullptr); + DetachOnErrorValueChangedCallback(this, nullptr); + DisableASLRValueChangedCallback(this, nullptr); + DisableSTDIOValueChangedCallback(this, nullptr); + } else { + m_collection_sp.reset( + new TargetOptionValueProperties(ConstString("target"))); + m_collection_sp->Initialize(g_properties); + m_experimental_properties_up.reset(new TargetExperimentalProperties()); + m_collection_sp->AppendProperty( + ConstString(Properties::GetExperimentalSettingsName()), + ConstString("Experimental settings - setting these won't produce " + "errors if the setting is not present."), + true, m_experimental_properties_up->GetValueProperties()); + m_collection_sp->AppendProperty( + ConstString("process"), ConstString("Settings specific to processes."), + true, Process::GetGlobalProperties()->GetValueProperties()); + } } TargetProperties::~TargetProperties() = default; -bool -TargetProperties::GetInjectLocalVariables(ExecutionContext *exe_ctx) const -{ - const Property *exp_property = m_collection_sp->GetPropertyAtIndex(exe_ctx, false, ePropertyExperimental); - OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); - if (exp_values) - return exp_values->GetPropertyAtIndexAsBoolean(exe_ctx, ePropertyInjectLocalVars, true); - else - return true; -} - -void -TargetProperties::SetInjectLocalVariables(ExecutionContext *exe_ctx, bool b) -{ - const Property *exp_property = m_collection_sp->GetPropertyAtIndex(exe_ctx, true, ePropertyExperimental); - OptionValueProperties *exp_values = exp_property->GetValue()->GetAsProperties(); - if (exp_values) - exp_values->SetPropertyAtIndexAsBoolean(exe_ctx, ePropertyInjectLocalVars, true); -} - -ArchSpec -TargetProperties::GetDefaultArchitecture () const -{ - OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch(nullptr, ePropertyDefaultArch); - if (value) - return value->GetCurrentValue(); - return ArchSpec(); -} - -void -TargetProperties::SetDefaultArchitecture (const ArchSpec& arch) -{ - OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch(nullptr, ePropertyDefaultArch); - if (value) - return value->SetCurrentValue(arch, true); -} - -bool -TargetProperties::GetMoveToNearestCode() const -{ - const uint32_t idx = ePropertyMoveToNearestCode; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); -} - -lldb::DynamicValueType -TargetProperties::GetPreferDynamicValue() const -{ - const uint32_t idx = ePropertyPreferDynamic; - return (lldb::DynamicValueType)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); -} - -bool -TargetProperties::SetPreferDynamicValue (lldb::DynamicValueType d) -{ - const uint32_t idx = ePropertyPreferDynamic; - return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d); +bool TargetProperties::GetInjectLocalVariables( + ExecutionContext *exe_ctx) const { + const Property *exp_property = m_collection_sp->GetPropertyAtIndex( + exe_ctx, false, ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (exp_values) + return exp_values->GetPropertyAtIndexAsBoolean( + exe_ctx, ePropertyInjectLocalVars, true); + else + return true; } -bool -TargetProperties::GetDisableASLR () const -{ - const uint32_t idx = ePropertyDisableASLR; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +void TargetProperties::SetInjectLocalVariables(ExecutionContext *exe_ctx, + bool b) { + const Property *exp_property = + m_collection_sp->GetPropertyAtIndex(exe_ctx, true, ePropertyExperimental); + OptionValueProperties *exp_values = + exp_property->GetValue()->GetAsProperties(); + if (exp_values) + exp_values->SetPropertyAtIndexAsBoolean(exe_ctx, ePropertyInjectLocalVars, + true); } -void -TargetProperties::SetDisableASLR (bool b) -{ - const uint32_t idx = ePropertyDisableASLR; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +ArchSpec TargetProperties::GetDefaultArchitecture() const { + OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch( + nullptr, ePropertyDefaultArch); + if (value) + return value->GetCurrentValue(); + return ArchSpec(); } -bool -TargetProperties::GetDetachOnError () const -{ - const uint32_t idx = ePropertyDetachOnError; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +void TargetProperties::SetDefaultArchitecture(const ArchSpec &arch) { + OptionValueArch *value = m_collection_sp->GetPropertyAtIndexAsOptionValueArch( + nullptr, ePropertyDefaultArch); + if (value) + return value->SetCurrentValue(arch, true); } -void -TargetProperties::SetDetachOnError (bool b) -{ - const uint32_t idx = ePropertyDetachOnError; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +bool TargetProperties::GetMoveToNearestCode() const { + const uint32_t idx = ePropertyMoveToNearestCode; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -TargetProperties::GetDisableSTDIO () const -{ - const uint32_t idx = ePropertyDisableSTDIO; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +lldb::DynamicValueType TargetProperties::GetPreferDynamicValue() const { + const uint32_t idx = ePropertyPreferDynamic; + return (lldb::DynamicValueType) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -void -TargetProperties::SetDisableSTDIO (bool b) -{ - const uint32_t idx = ePropertyDisableSTDIO; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +bool TargetProperties::SetPreferDynamicValue(lldb::DynamicValueType d) { + const uint32_t idx = ePropertyPreferDynamic; + return m_collection_sp->SetPropertyAtIndexAsEnumeration(nullptr, idx, d); } -const char * -TargetProperties::GetDisassemblyFlavor () const -{ - const uint32_t idx = ePropertyDisassemblyFlavor; - const char *return_value; - - x86DisassemblyFlavor flavor_value = (x86DisassemblyFlavor) m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); - return_value = g_x86_dis_flavor_value_types[flavor_value].string_value; - return return_value; +bool TargetProperties::GetDisableASLR() const { + const uint32_t idx = ePropertyDisableASLR; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -InlineStrategy -TargetProperties::GetInlineStrategy () const -{ - const uint32_t idx = ePropertyInlineStrategy; - return (InlineStrategy)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +void TargetProperties::SetDisableASLR(bool b) { + const uint32_t idx = ePropertyDisableASLR; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -const char * -TargetProperties::GetArg0 () const -{ - const uint32_t idx = ePropertyArg0; - return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, nullptr); +bool TargetProperties::GetDetachOnError() const { + const uint32_t idx = ePropertyDetachOnError; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -TargetProperties::SetArg0 (const char *arg) -{ - const uint32_t idx = ePropertyArg0; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, arg); - m_launch_info.SetArg0(arg); +void TargetProperties::SetDetachOnError(bool b) { + const uint32_t idx = ePropertyDetachOnError; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -bool -TargetProperties::GetRunArguments (Args &args) const -{ - const uint32_t idx = ePropertyRunArgs; - return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); +bool TargetProperties::GetDisableSTDIO() const { + const uint32_t idx = ePropertyDisableSTDIO; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -TargetProperties::SetRunArguments (const Args &args) -{ - const uint32_t idx = ePropertyRunArgs; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); - m_launch_info.GetArguments() = args; +void TargetProperties::SetDisableSTDIO(bool b) { + const uint32_t idx = ePropertyDisableSTDIO; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -size_t -TargetProperties::GetEnvironmentAsArgs (Args &env) const -{ - const uint32_t idx = ePropertyEnvVars; - return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env); -} +const char *TargetProperties::GetDisassemblyFlavor() const { + const uint32_t idx = ePropertyDisassemblyFlavor; + const char *return_value; -void -TargetProperties::SetEnvironmentFromArgs (const Args &env) -{ - const uint32_t idx = ePropertyEnvVars; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, env); - m_launch_info.GetEnvironmentEntries() = env; + x86DisassemblyFlavor flavor_value = + (x86DisassemblyFlavor)m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); + return_value = g_x86_dis_flavor_value_types[flavor_value].string_value; + return return_value; } -bool -TargetProperties::GetSkipPrologue() const -{ - const uint32_t idx = ePropertySkipPrologue; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +InlineStrategy TargetProperties::GetInlineStrategy() const { + const uint32_t idx = ePropertyInlineStrategy; + return (InlineStrategy)m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -PathMappingList & -TargetProperties::GetSourcePathMap () const -{ - const uint32_t idx = ePropertySourceMap; - OptionValuePathMappings *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValuePathMappings(nullptr, false, idx); - assert(option_value); - return option_value->GetCurrentValue(); +const char *TargetProperties::GetArg0() const { + const uint32_t idx = ePropertyArg0; + return m_collection_sp->GetPropertyAtIndexAsString(nullptr, idx, nullptr); } -FileSpecList & -TargetProperties::GetExecutableSearchPaths () -{ - const uint32_t idx = ePropertyExecutableSearchPaths; - OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, false, idx); - assert(option_value); - return option_value->GetCurrentValue(); +void TargetProperties::SetArg0(const char *arg) { + const uint32_t idx = ePropertyArg0; + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, arg); + m_launch_info.SetArg0(arg); } -FileSpecList & -TargetProperties::GetDebugFileSearchPaths () -{ - const uint32_t idx = ePropertyDebugFileSearchPaths; - OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, false, idx); - assert(option_value); - return option_value->GetCurrentValue(); +bool TargetProperties::GetRunArguments(Args &args) const { + const uint32_t idx = ePropertyRunArgs; + return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); } -FileSpecList & -TargetProperties::GetClangModuleSearchPaths () -{ - const uint32_t idx = ePropertyClangModuleSearchPaths; - OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, false, idx); - assert(option_value); - return option_value->GetCurrentValue(); +void TargetProperties::SetRunArguments(const Args &args) { + const uint32_t idx = ePropertyRunArgs; + m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); + m_launch_info.GetArguments() = args; } -bool -TargetProperties::GetEnableAutoImportClangModules() const -{ - const uint32_t idx = ePropertyAutoImportClangModules; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +size_t TargetProperties::GetEnvironmentAsArgs(Args &env) const { + const uint32_t idx = ePropertyEnvVars; + return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, env); } -bool -TargetProperties::GetEnableAutoApplyFixIts() const -{ - const uint32_t idx = ePropertyAutoApplyFixIts; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +void TargetProperties::SetEnvironmentFromArgs(const Args &env) { + const uint32_t idx = ePropertyEnvVars; + m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, env); + m_launch_info.GetEnvironmentEntries() = env; } -bool -TargetProperties::GetEnableNotifyAboutFixIts() const -{ - const uint32_t idx = ePropertyNotifyAboutFixIts; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool TargetProperties::GetSkipPrologue() const { + const uint32_t idx = ePropertySkipPrologue; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -TargetProperties::GetEnableSyntheticValue () const -{ - const uint32_t idx = ePropertyEnableSynthetic; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +PathMappingList &TargetProperties::GetSourcePathMap() const { + const uint32_t idx = ePropertySourceMap; + OptionValuePathMappings *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValuePathMappings(nullptr, + false, idx); + assert(option_value); + return option_value->GetCurrentValue(); } -uint32_t -TargetProperties::GetMaximumNumberOfChildrenToDisplay() const -{ - const uint32_t idx = ePropertyMaxChildrenCount; - return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); +FileSpecList &TargetProperties::GetExecutableSearchPaths() { + const uint32_t idx = ePropertyExecutableSearchPaths; + OptionValueFileSpecList *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, + false, idx); + assert(option_value); + return option_value->GetCurrentValue(); } -uint32_t -TargetProperties::GetMaximumSizeOfStringSummary() const -{ - const uint32_t idx = ePropertyMaxSummaryLength; - return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); +FileSpecList &TargetProperties::GetDebugFileSearchPaths() { + const uint32_t idx = ePropertyDebugFileSearchPaths; + OptionValueFileSpecList *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, + false, idx); + assert(option_value); + return option_value->GetCurrentValue(); } -uint32_t -TargetProperties::GetMaximumMemReadSize () const -{ - const uint32_t idx = ePropertyMaxMemReadSize; - return m_collection_sp->GetPropertyAtIndexAsSInt64(nullptr, idx, g_properties[idx].default_uint_value); +FileSpecList &TargetProperties::GetClangModuleSearchPaths() { + const uint32_t idx = ePropertyClangModuleSearchPaths; + OptionValueFileSpecList *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, + false, idx); + assert(option_value); + return option_value->GetCurrentValue(); } -FileSpec -TargetProperties::GetStandardInputPath () const -{ - const uint32_t idx = ePropertyInputPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +bool TargetProperties::GetEnableAutoImportClangModules() const { + const uint32_t idx = ePropertyAutoImportClangModules; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -TargetProperties::SetStandardInputPath (const char *p) -{ - const uint32_t idx = ePropertyInputPath; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); +bool TargetProperties::GetEnableAutoApplyFixIts() const { + const uint32_t idx = ePropertyAutoApplyFixIts; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -FileSpec -TargetProperties::GetStandardOutputPath () const -{ - const uint32_t idx = ePropertyOutputPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +bool TargetProperties::GetEnableNotifyAboutFixIts() const { + const uint32_t idx = ePropertyNotifyAboutFixIts; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -TargetProperties::SetStandardOutputPath (const char *p) -{ - const uint32_t idx = ePropertyOutputPath; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); +bool TargetProperties::GetEnableSyntheticValue() const { + const uint32_t idx = ePropertyEnableSynthetic; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -FileSpec -TargetProperties::GetStandardErrorPath () const -{ - const uint32_t idx = ePropertyErrorPath; - return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); +uint32_t TargetProperties::GetMaximumNumberOfChildrenToDisplay() const { + const uint32_t idx = ePropertyMaxChildrenCount; + return m_collection_sp->GetPropertyAtIndexAsSInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -LanguageType -TargetProperties::GetLanguage () const -{ - OptionValueLanguage *value = m_collection_sp->GetPropertyAtIndexAsOptionValueLanguage(nullptr, ePropertyLanguage); - if (value) - return value->GetCurrentValue(); - return LanguageType(); +uint32_t TargetProperties::GetMaximumSizeOfStringSummary() const { + const uint32_t idx = ePropertyMaxSummaryLength; + return m_collection_sp->GetPropertyAtIndexAsSInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -const char * -TargetProperties::GetExpressionPrefixContentsAsCString () -{ - const uint32_t idx = ePropertyExprPrefix; - OptionValueFileSpec *file = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false, idx); - if (file) - { - const bool null_terminate = true; - DataBufferSP data_sp(file->GetFileContents(null_terminate)); - if (data_sp) - return (const char *) data_sp->GetBytes(); - } - return nullptr; +uint32_t TargetProperties::GetMaximumMemReadSize() const { + const uint32_t idx = ePropertyMaxMemReadSize; + return m_collection_sp->GetPropertyAtIndexAsSInt64( + nullptr, idx, g_properties[idx].default_uint_value); } -void -TargetProperties::SetStandardErrorPath (const char *p) -{ - const uint32_t idx = ePropertyErrorPath; - m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); +FileSpec TargetProperties::GetStandardInputPath() const { + const uint32_t idx = ePropertyInputPath; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); } -bool -TargetProperties::GetBreakpointsConsultPlatformAvoidList () -{ - const uint32_t idx = ePropertyBreakpointUseAvoidList; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +void TargetProperties::SetStandardInputPath(const char *p) { + const uint32_t idx = ePropertyInputPath; + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); } -bool -TargetProperties::GetUseHexImmediates () const -{ - const uint32_t idx = ePropertyUseHexImmediates; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +FileSpec TargetProperties::GetStandardOutputPath() const { + const uint32_t idx = ePropertyOutputPath; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); } -bool -TargetProperties::GetUseFastStepping () const -{ - const uint32_t idx = ePropertyUseFastStepping; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +void TargetProperties::SetStandardOutputPath(const char *p) { + const uint32_t idx = ePropertyOutputPath; + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); } -bool -TargetProperties::GetDisplayExpressionsInCrashlogs () const -{ - const uint32_t idx = ePropertyDisplayExpressionsInCrashlogs; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +FileSpec TargetProperties::GetStandardErrorPath() const { + const uint32_t idx = ePropertyErrorPath; + return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx); } -LoadScriptFromSymFile -TargetProperties::GetLoadScriptFromSymbolFile () const -{ - const uint32_t idx = ePropertyLoadScriptFromSymbolFile; - return (LoadScriptFromSymFile)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +LanguageType TargetProperties::GetLanguage() const { + OptionValueLanguage *value = + m_collection_sp->GetPropertyAtIndexAsOptionValueLanguage( + nullptr, ePropertyLanguage); + if (value) + return value->GetCurrentValue(); + return LanguageType(); } -LoadCWDlldbinitFile -TargetProperties::GetLoadCWDlldbinitFile () const -{ - const uint32_t idx = ePropertyLoadCWDlldbinitFile; - return (LoadCWDlldbinitFile) m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +const char *TargetProperties::GetExpressionPrefixContentsAsCString() { + const uint32_t idx = ePropertyExprPrefix; + OptionValueFileSpec *file = + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpec(nullptr, false, + idx); + if (file) { + const bool null_terminate = true; + DataBufferSP data_sp(file->GetFileContents(null_terminate)); + if (data_sp) + return (const char *)data_sp->GetBytes(); + } + return nullptr; } -Disassembler::HexImmediateStyle -TargetProperties::GetHexImmediateStyle () const -{ - const uint32_t idx = ePropertyHexImmediateStyle; - return (Disassembler::HexImmediateStyle)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +void TargetProperties::SetStandardErrorPath(const char *p) { + const uint32_t idx = ePropertyErrorPath; + m_collection_sp->SetPropertyAtIndexAsString(nullptr, idx, p); } -MemoryModuleLoadLevel -TargetProperties::GetMemoryModuleLoadLevel() const -{ - const uint32_t idx = ePropertyMemoryModuleLoadLevel; - return (MemoryModuleLoadLevel)m_collection_sp->GetPropertyAtIndexAsEnumeration(nullptr, idx, g_properties[idx].default_uint_value); +bool TargetProperties::GetBreakpointsConsultPlatformAvoidList() { + const uint32_t idx = ePropertyBreakpointUseAvoidList; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -TargetProperties::GetUserSpecifiedTrapHandlerNames (Args &args) const -{ - const uint32_t idx = ePropertyTrapHandlerNames; - return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); +bool TargetProperties::GetUseHexImmediates() const { + const uint32_t idx = ePropertyUseHexImmediates; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -TargetProperties::SetUserSpecifiedTrapHandlerNames (const Args &args) -{ - const uint32_t idx = ePropertyTrapHandlerNames; - m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); +bool TargetProperties::GetUseFastStepping() const { + const uint32_t idx = ePropertyUseFastStepping; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -TargetProperties::GetDisplayRuntimeSupportValues () const -{ - const uint32_t idx = ePropertyDisplayRuntimeSupportValues; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); +bool TargetProperties::GetDisplayExpressionsInCrashlogs() const { + const uint32_t idx = ePropertyDisplayExpressionsInCrashlogs; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -void -TargetProperties::SetDisplayRuntimeSupportValues (bool b) -{ - const uint32_t idx = ePropertyDisplayRuntimeSupportValues; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +LoadScriptFromSymFile TargetProperties::GetLoadScriptFromSymbolFile() const { + const uint32_t idx = ePropertyLoadScriptFromSymbolFile; + return (LoadScriptFromSymFile) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -bool -TargetProperties::GetNonStopModeEnabled () const -{ - const uint32_t idx = ePropertyNonStopModeEnabled; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); +LoadCWDlldbinitFile TargetProperties::GetLoadCWDlldbinitFile() const { + const uint32_t idx = ePropertyLoadCWDlldbinitFile; + return (LoadCWDlldbinitFile)m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -void -TargetProperties::SetNonStopModeEnabled (bool b) -{ - const uint32_t idx = ePropertyNonStopModeEnabled; - m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); +Disassembler::HexImmediateStyle TargetProperties::GetHexImmediateStyle() const { + const uint32_t idx = ePropertyHexImmediateStyle; + return (Disassembler::HexImmediateStyle) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -const ProcessLaunchInfo & -TargetProperties::GetProcessLaunchInfo () -{ - m_launch_info.SetArg0(GetArg0()); // FIXME: Arg0 callback doesn't work - return m_launch_info; +MemoryModuleLoadLevel TargetProperties::GetMemoryModuleLoadLevel() const { + const uint32_t idx = ePropertyMemoryModuleLoadLevel; + return (MemoryModuleLoadLevel) + m_collection_sp->GetPropertyAtIndexAsEnumeration( + nullptr, idx, g_properties[idx].default_uint_value); } -void -TargetProperties::SetProcessLaunchInfo(const ProcessLaunchInfo &launch_info) -{ - m_launch_info = launch_info; - SetArg0(launch_info.GetArg0()); - SetRunArguments(launch_info.GetArguments()); - SetEnvironmentFromArgs(launch_info.GetEnvironmentEntries()); - const FileAction *input_file_action = launch_info.GetFileActionForFD(STDIN_FILENO); - if (input_file_action) - { - const char *input_path = input_file_action->GetPath(); - if (input_path) - SetStandardInputPath(input_path); - } - const FileAction *output_file_action = launch_info.GetFileActionForFD(STDOUT_FILENO); - if (output_file_action) - { - const char *output_path = output_file_action->GetPath(); - if (output_path) - SetStandardOutputPath(output_path); - } - const FileAction *error_file_action = launch_info.GetFileActionForFD(STDERR_FILENO); - if (error_file_action) - { - const char *error_path = error_file_action->GetPath(); - if (error_path) - SetStandardErrorPath(error_path); - } - SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError)); - SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)); - SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO)); +bool TargetProperties::GetUserSpecifiedTrapHandlerNames(Args &args) const { + const uint32_t idx = ePropertyTrapHandlerNames; + return m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args); } -void -TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - this_->m_launch_info.SetArg0(this_->GetArg0()); +void TargetProperties::SetUserSpecifiedTrapHandlerNames(const Args &args) { + const uint32_t idx = ePropertyTrapHandlerNames; + m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args); } -void -TargetProperties::RunArgsValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - Args args; - if (this_->GetRunArguments(args)) - this_->m_launch_info.GetArguments() = args; +bool TargetProperties::GetDisplayRuntimeSupportValues() const { + const uint32_t idx = ePropertyDisplayRuntimeSupportValues; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); } -void -TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - Args args; - if (this_->GetEnvironmentAsArgs(args)) - this_->m_launch_info.GetEnvironmentEntries() = args; +void TargetProperties::SetDisplayRuntimeSupportValues(bool b) { + const uint32_t idx = ePropertyDisplayRuntimeSupportValues; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -void -TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - this_->m_launch_info.AppendOpenFileAction(STDIN_FILENO, this_->GetStandardInputPath(), true, false); +bool TargetProperties::GetNonStopModeEnabled() const { + const uint32_t idx = ePropertyNonStopModeEnabled; + return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, false); } -void -TargetProperties::OutputPathValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - this_->m_launch_info.AppendOpenFileAction(STDOUT_FILENO, this_->GetStandardOutputPath(), false, true); +void TargetProperties::SetNonStopModeEnabled(bool b) { + const uint32_t idx = ePropertyNonStopModeEnabled; + m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, b); } -void -TargetProperties::ErrorPathValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - this_->m_launch_info.AppendOpenFileAction(STDERR_FILENO, this_->GetStandardErrorPath(), false, true); +const ProcessLaunchInfo &TargetProperties::GetProcessLaunchInfo() { + m_launch_info.SetArg0(GetArg0()); // FIXME: Arg0 callback doesn't work + return m_launch_info; } -void -TargetProperties::DetachOnErrorValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - if (this_->GetDetachOnError()) - this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDetachOnError); - else - this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDetachOnError); +void TargetProperties::SetProcessLaunchInfo( + const ProcessLaunchInfo &launch_info) { + m_launch_info = launch_info; + SetArg0(launch_info.GetArg0()); + SetRunArguments(launch_info.GetArguments()); + SetEnvironmentFromArgs(launch_info.GetEnvironmentEntries()); + const FileAction *input_file_action = + launch_info.GetFileActionForFD(STDIN_FILENO); + if (input_file_action) { + const char *input_path = input_file_action->GetPath(); + if (input_path) + SetStandardInputPath(input_path); + } + const FileAction *output_file_action = + launch_info.GetFileActionForFD(STDOUT_FILENO); + if (output_file_action) { + const char *output_path = output_file_action->GetPath(); + if (output_path) + SetStandardOutputPath(output_path); + } + const FileAction *error_file_action = + launch_info.GetFileActionForFD(STDERR_FILENO); + if (error_file_action) { + const char *error_path = error_file_action->GetPath(); + if (error_path) + SetStandardErrorPath(error_path); + } + SetDetachOnError(launch_info.GetFlags().Test(lldb::eLaunchFlagDetachOnError)); + SetDisableASLR(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableASLR)); + SetDisableSTDIO(launch_info.GetFlags().Test(lldb::eLaunchFlagDisableSTDIO)); } -void -TargetProperties::DisableASLRValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - if (this_->GetDisableASLR()) - this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableASLR); - else - this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableASLR); +void TargetProperties::Arg0ValueChangedCallback(void *target_property_ptr, + OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + this_->m_launch_info.SetArg0(this_->GetArg0()); +} + +void TargetProperties::RunArgsValueChangedCallback(void *target_property_ptr, + OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + Args args; + if (this_->GetRunArguments(args)) + this_->m_launch_info.GetArguments() = args; +} + +void TargetProperties::EnvVarsValueChangedCallback(void *target_property_ptr, + OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + Args args; + if (this_->GetEnvironmentAsArgs(args)) + this_->m_launch_info.GetEnvironmentEntries() = args; } -void -TargetProperties::DisableSTDIOValueChangedCallback(void *target_property_ptr, OptionValue *) -{ - TargetProperties *this_ = reinterpret_cast<TargetProperties *>(target_property_ptr); - if (this_->GetDisableSTDIO()) - this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableSTDIO); - else - this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableSTDIO); +void TargetProperties::InputPathValueChangedCallback(void *target_property_ptr, + OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + this_->m_launch_info.AppendOpenFileAction( + STDIN_FILENO, this_->GetStandardInputPath(), true, false); +} + +void TargetProperties::OutputPathValueChangedCallback(void *target_property_ptr, + OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + this_->m_launch_info.AppendOpenFileAction( + STDOUT_FILENO, this_->GetStandardOutputPath(), false, true); +} + +void TargetProperties::ErrorPathValueChangedCallback(void *target_property_ptr, + OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + this_->m_launch_info.AppendOpenFileAction( + STDERR_FILENO, this_->GetStandardErrorPath(), false, true); +} + +void TargetProperties::DetachOnErrorValueChangedCallback( + void *target_property_ptr, OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + if (this_->GetDetachOnError()) + this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDetachOnError); + else + this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDetachOnError); +} + +void TargetProperties::DisableASLRValueChangedCallback( + void *target_property_ptr, OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + if (this_->GetDisableASLR()) + this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableASLR); + else + this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableASLR); +} + +void TargetProperties::DisableSTDIOValueChangedCallback( + void *target_property_ptr, OptionValue *) { + TargetProperties *this_ = + reinterpret_cast<TargetProperties *>(target_property_ptr); + if (this_->GetDisableSTDIO()) + this_->m_launch_info.GetFlags().Set(lldb::eLaunchFlagDisableSTDIO); + else + this_->m_launch_info.GetFlags().Clear(lldb::eLaunchFlagDisableSTDIO); } //---------------------------------------------------------------------- // Target::TargetEventData //---------------------------------------------------------------------- -Target::TargetEventData::TargetEventData (const lldb::TargetSP &target_sp) : - EventData (), - m_target_sp (target_sp), - m_module_list () -{ -} +Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp) + : EventData(), m_target_sp(target_sp), m_module_list() {} -Target::TargetEventData::TargetEventData (const lldb::TargetSP &target_sp, const ModuleList &module_list) : - EventData (), - m_target_sp (target_sp), - m_module_list (module_list) -{ -} +Target::TargetEventData::TargetEventData(const lldb::TargetSP &target_sp, + const ModuleList &module_list) + : EventData(), m_target_sp(target_sp), m_module_list(module_list) {} Target::TargetEventData::~TargetEventData() = default; -const ConstString & -Target::TargetEventData::GetFlavorString () -{ - static ConstString g_flavor ("Target::TargetEventData"); - return g_flavor; +const ConstString &Target::TargetEventData::GetFlavorString() { + static ConstString g_flavor("Target::TargetEventData"); + return g_flavor; } -void -Target::TargetEventData::Dump (Stream *s) const -{ - for (size_t i = 0; i < m_module_list.GetSize(); ++i) - { - if (i != 0) - *s << ", "; - m_module_list.GetModuleAtIndex(i)->GetDescription(s, lldb::eDescriptionLevelBrief); - } +void Target::TargetEventData::Dump(Stream *s) const { + for (size_t i = 0; i < m_module_list.GetSize(); ++i) { + if (i != 0) + *s << ", "; + m_module_list.GetModuleAtIndex(i)->GetDescription( + s, lldb::eDescriptionLevelBrief); + } } const Target::TargetEventData * -Target::TargetEventData::GetEventDataFromEvent (const Event *event_ptr) -{ - if (event_ptr) - { - const EventData *event_data = event_ptr->GetData(); - if (event_data && event_data->GetFlavor() == TargetEventData::GetFlavorString()) - return static_cast <const TargetEventData *> (event_ptr->GetData()); - } - return nullptr; +Target::TargetEventData::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr) { + const EventData *event_data = event_ptr->GetData(); + if (event_data && + event_data->GetFlavor() == TargetEventData::GetFlavorString()) + return static_cast<const TargetEventData *>(event_ptr->GetData()); + } + return nullptr; } -TargetSP -Target::TargetEventData::GetTargetFromEvent (const Event *event_ptr) -{ - TargetSP target_sp; - const TargetEventData *event_data = GetEventDataFromEvent (event_ptr); - if (event_data) - target_sp = event_data->m_target_sp; - return target_sp; +TargetSP Target::TargetEventData::GetTargetFromEvent(const Event *event_ptr) { + TargetSP target_sp; + const TargetEventData *event_data = GetEventDataFromEvent(event_ptr); + if (event_data) + target_sp = event_data->m_target_sp; + return target_sp; } ModuleList -Target::TargetEventData::GetModuleListFromEvent (const Event *event_ptr) -{ - ModuleList module_list; - const TargetEventData *event_data = GetEventDataFromEvent (event_ptr); - if (event_data) - module_list = event_data->m_module_list; - return module_list; +Target::TargetEventData::GetModuleListFromEvent(const Event *event_ptr) { + ModuleList module_list; + const TargetEventData *event_data = GetEventDataFromEvent(event_ptr); + if (event_data) + module_list = event_data->m_module_list; + return module_list; } diff --git a/lldb/source/Target/TargetList.cpp b/lldb/source/Target/TargetList.cpp index 6e7577206af..c8bbceecb69 100644 --- a/lldb/source/Target/TargetList.cpp +++ b/lldb/source/Target/TargetList.cpp @@ -32,734 +32,598 @@ using namespace lldb; using namespace lldb_private; -ConstString & -TargetList::GetStaticBroadcasterClass () -{ - static ConstString class_name ("lldb.targetList"); - return class_name; +ConstString &TargetList::GetStaticBroadcasterClass() { + static ConstString class_name("lldb.targetList"); + return class_name; } //---------------------------------------------------------------------- // TargetList constructor //---------------------------------------------------------------------- TargetList::TargetList(Debugger &debugger) - : Broadcaster(debugger.GetBroadcasterManager(), TargetList::GetStaticBroadcasterClass().AsCString()), - m_target_list(), - m_target_list_mutex(), - m_selected_target_idx(0) -{ - CheckInWithManager(); + : Broadcaster(debugger.GetBroadcasterManager(), + TargetList::GetStaticBroadcasterClass().AsCString()), + m_target_list(), m_target_list_mutex(), m_selected_target_idx(0) { + CheckInWithManager(); } //---------------------------------------------------------------------- // Destructor //---------------------------------------------------------------------- -TargetList::~TargetList() -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - m_target_list.clear(); +TargetList::~TargetList() { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + m_target_list.clear(); } -Error -TargetList::CreateTarget (Debugger &debugger, - const char *user_exe_path, - const char *triple_cstr, - bool get_dependent_files, - const OptionGroupPlatform *platform_options, - TargetSP &target_sp) -{ - return CreateTargetInternal (debugger, - user_exe_path, - triple_cstr, - get_dependent_files, - platform_options, - target_sp, - false); +Error TargetList::CreateTarget(Debugger &debugger, const char *user_exe_path, + const char *triple_cstr, + bool get_dependent_files, + const OptionGroupPlatform *platform_options, + TargetSP &target_sp) { + return CreateTargetInternal(debugger, user_exe_path, triple_cstr, + get_dependent_files, platform_options, target_sp, + false); } -Error -TargetList::CreateTarget (Debugger &debugger, - const char *user_exe_path, - const ArchSpec& specified_arch, - bool get_dependent_files, - PlatformSP &platform_sp, - TargetSP &target_sp) -{ - return CreateTargetInternal (debugger, - user_exe_path, - specified_arch, - get_dependent_files, - platform_sp, - target_sp, - false); +Error TargetList::CreateTarget(Debugger &debugger, const char *user_exe_path, + const ArchSpec &specified_arch, + bool get_dependent_files, + PlatformSP &platform_sp, TargetSP &target_sp) { + return CreateTargetInternal(debugger, user_exe_path, specified_arch, + get_dependent_files, platform_sp, target_sp, + false); } -Error -TargetList::CreateTargetInternal (Debugger &debugger, - const char *user_exe_path, - const char *triple_cstr, - bool get_dependent_files, - const OptionGroupPlatform *platform_options, - TargetSP &target_sp, - bool is_dummy_target) -{ - Error error; - PlatformSP platform_sp; - - // This is purposely left empty unless it is specified by triple_cstr. - // If not initialized via triple_cstr, then the currently selected platform - // will set the architecture correctly. - const ArchSpec arch(triple_cstr); - if (triple_cstr && triple_cstr[0]) - { - if (!arch.IsValid()) - { - error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); - return error; - } +Error TargetList::CreateTargetInternal( + Debugger &debugger, const char *user_exe_path, const char *triple_cstr, + bool get_dependent_files, const OptionGroupPlatform *platform_options, + TargetSP &target_sp, bool is_dummy_target) { + Error error; + PlatformSP platform_sp; + + // This is purposely left empty unless it is specified by triple_cstr. + // If not initialized via triple_cstr, then the currently selected platform + // will set the architecture correctly. + const ArchSpec arch(triple_cstr); + if (triple_cstr && triple_cstr[0]) { + if (!arch.IsValid()) { + error.SetErrorStringWithFormat("invalid triple '%s'", triple_cstr); + return error; } - - ArchSpec platform_arch(arch); + } - bool prefer_platform_arch = false; - - CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); + ArchSpec platform_arch(arch); - // let's see if there is already an existing plaform before we go creating another... - platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + bool prefer_platform_arch = false; - if (platform_options && platform_options->PlatformWasSpecified ()) - { - // Create a new platform if it doesn't match the selected platform - if (!platform_options->PlatformMatches(platform_sp)) - { - const bool select_platform = true; - platform_sp = platform_options->CreatePlatformWithOptions (interpreter, - arch, - select_platform, - error, - platform_arch); - if (!platform_sp) - return error; - } + CommandInterpreter &interpreter = debugger.GetCommandInterpreter(); + + // let's see if there is already an existing plaform before we go creating + // another... + platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); + + if (platform_options && platform_options->PlatformWasSpecified()) { + // Create a new platform if it doesn't match the selected platform + if (!platform_options->PlatformMatches(platform_sp)) { + const bool select_platform = true; + platform_sp = platform_options->CreatePlatformWithOptions( + interpreter, arch, select_platform, error, platform_arch); + if (!platform_sp) + return error; } - - if (user_exe_path && user_exe_path[0]) - { - ModuleSpecList module_specs; - ModuleSpec module_spec; - module_spec.GetFileSpec().SetFile(user_exe_path, true); - - // Resolve the executable in case we are given a path to a application bundle - // like a .app bundle on MacOSX - Host::ResolveExecutableInBundle (module_spec.GetFileSpec()); - - lldb::offset_t file_offset = 0; - lldb::offset_t file_size = 0; - const size_t num_specs = ObjectFile::GetModuleSpecifications (module_spec.GetFileSpec(), file_offset, file_size, module_specs); - if (num_specs > 0) - { - ModuleSpec matching_module_spec; - - if (num_specs == 1) - { - if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) - { - if (platform_arch.IsValid()) - { - if (platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture())) - { - // If the OS or vendor weren't specified, then adopt the module's - // architecture so that the platform matching can be more accurate - if (!platform_arch.TripleOSWasSpecified() || !platform_arch.TripleVendorWasSpecified()) - { - prefer_platform_arch = true; - platform_arch = matching_module_spec.GetArchitecture(); - } - } - else - { - StreamString platform_arch_strm; - StreamString module_arch_strm; - - platform_arch.DumpTriple(platform_arch_strm); - matching_module_spec.GetArchitecture().DumpTriple(module_arch_strm); - error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'", - platform_arch_strm.GetString().c_str(), - module_arch_strm.GetString().c_str(), - module_spec.GetFileSpec().GetPath().c_str()); - return error; - } - } - else - { - // Only one arch and none was specified - prefer_platform_arch = true; - platform_arch = matching_module_spec.GetArchitecture(); - } - } + } + + if (user_exe_path && user_exe_path[0]) { + ModuleSpecList module_specs; + ModuleSpec module_spec; + module_spec.GetFileSpec().SetFile(user_exe_path, true); + + // Resolve the executable in case we are given a path to a application + // bundle + // like a .app bundle on MacOSX + Host::ResolveExecutableInBundle(module_spec.GetFileSpec()); + + lldb::offset_t file_offset = 0; + lldb::offset_t file_size = 0; + const size_t num_specs = ObjectFile::GetModuleSpecifications( + module_spec.GetFileSpec(), file_offset, file_size, module_specs); + if (num_specs > 0) { + ModuleSpec matching_module_spec; + + if (num_specs == 1) { + if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec)) { + if (platform_arch.IsValid()) { + if (platform_arch.IsCompatibleMatch( + matching_module_spec.GetArchitecture())) { + // If the OS or vendor weren't specified, then adopt the module's + // architecture so that the platform matching can be more accurate + if (!platform_arch.TripleOSWasSpecified() || + !platform_arch.TripleVendorWasSpecified()) { + prefer_platform_arch = true; + platform_arch = matching_module_spec.GetArchitecture(); + } + } else { + StreamString platform_arch_strm; + StreamString module_arch_strm; + + platform_arch.DumpTriple(platform_arch_strm); + matching_module_spec.GetArchitecture().DumpTriple( + module_arch_strm); + error.SetErrorStringWithFormat( + "the specified architecture '%s' is not compatible with '%s' " + "in '%s'", + platform_arch_strm.GetString().c_str(), + module_arch_strm.GetString().c_str(), + module_spec.GetFileSpec().GetPath().c_str()); + return error; } - else - { - if (arch.IsValid()) - { - module_spec.GetArchitecture() = arch; - if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec)) - { - prefer_platform_arch = true; - platform_arch = matching_module_spec.GetArchitecture(); - } + } else { + // Only one arch and none was specified + prefer_platform_arch = true; + platform_arch = matching_module_spec.GetArchitecture(); + } + } + } else { + if (arch.IsValid()) { + module_spec.GetArchitecture() = arch; + if (module_specs.FindMatchingModuleSpec(module_spec, + matching_module_spec)) { + prefer_platform_arch = true; + platform_arch = matching_module_spec.GetArchitecture(); + } + } else { + // No architecture specified, check if there is only one platform for + // all of the architectures. + + typedef std::vector<PlatformSP> PlatformList; + PlatformList platforms; + PlatformSP host_platform_sp = Platform::GetHostPlatform(); + for (size_t i = 0; i < num_specs; ++i) { + ModuleSpec module_spec; + if (module_specs.GetModuleSpecAtIndex(i, module_spec)) { + // See if there was a selected platform and check that first + // since the user may have specified it. + if (platform_sp) { + if (platform_sp->IsCompatibleArchitecture( + module_spec.GetArchitecture(), false, nullptr)) { + platforms.push_back(platform_sp); + continue; } - else - { - // No architecture specified, check if there is only one platform for - // all of the architectures. - - typedef std::vector<PlatformSP> PlatformList; - PlatformList platforms; - PlatformSP host_platform_sp = Platform::GetHostPlatform(); - for (size_t i=0; i<num_specs; ++i) - { - ModuleSpec module_spec; - if (module_specs.GetModuleSpecAtIndex(i, module_spec)) - { - // See if there was a selected platform and check that first - // since the user may have specified it. - if (platform_sp) - { - if (platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, nullptr)) - { - platforms.push_back(platform_sp); - continue; - } - } - - // Next check the host platform it if wasn't already checked above - if (host_platform_sp && (!platform_sp || host_platform_sp->GetName() != platform_sp->GetName())) - { - if (host_platform_sp->IsCompatibleArchitecture(module_spec.GetArchitecture(), false, nullptr)) - { - platforms.push_back(host_platform_sp); - continue; - } - } - - // Just find a platform that matches the architecture in the executable file - PlatformSP fallback_platform_sp (Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr)); - if (fallback_platform_sp) - { - platforms.push_back(fallback_platform_sp); - } - } - } - - Platform *platform_ptr = nullptr; - bool more_than_one_platforms = false; - for (const auto &the_platform_sp : platforms) - { - if (platform_ptr) - { - if (platform_ptr->GetName() != the_platform_sp->GetName()) - { - more_than_one_platforms = true; - platform_ptr = nullptr; - break; - } - } - else - { - platform_ptr = the_platform_sp.get(); - } - } - - if (platform_ptr) - { - // All platforms for all modules in the exectuable match, so we can select this platform - platform_sp = platforms.front(); - } - else if (more_than_one_platforms == false) - { - // No platforms claim to support this file - error.SetErrorString ("No matching platforms found for this file, specify one with the --platform option"); - return error; - } - else - { - // More than one platform claims to support this file, so the --platform option must be specified - StreamString error_strm; - std::set<Platform *> platform_set; - error_strm.Printf ("more than one platform supports this executable ("); - for (const auto &the_platform_sp : platforms) - { - if (platform_set.find(the_platform_sp.get()) == platform_set.end()) - { - if (!platform_set.empty()) - error_strm.PutCString(", "); - error_strm.PutCString(the_platform_sp->GetName().GetCString()); - platform_set.insert(the_platform_sp.get()); - } - } - error_strm.Printf("), use the --platform option to specify a platform"); - error.SetErrorString(error_strm.GetString().c_str()); - return error; - } + } + + // Next check the host platform it if wasn't already checked above + if (host_platform_sp && + (!platform_sp || + host_platform_sp->GetName() != platform_sp->GetName())) { + if (host_platform_sp->IsCompatibleArchitecture( + module_spec.GetArchitecture(), false, nullptr)) { + platforms.push_back(host_platform_sp); + continue; } + } + + // Just find a platform that matches the architecture in the + // executable file + PlatformSP fallback_platform_sp( + Platform::GetPlatformForArchitecture( + module_spec.GetArchitecture(), nullptr)); + if (fallback_platform_sp) { + platforms.push_back(fallback_platform_sp); + } + } + } + + Platform *platform_ptr = nullptr; + bool more_than_one_platforms = false; + for (const auto &the_platform_sp : platforms) { + if (platform_ptr) { + if (platform_ptr->GetName() != the_platform_sp->GetName()) { + more_than_one_platforms = true; + platform_ptr = nullptr; + break; + } + } else { + platform_ptr = the_platform_sp.get(); } + } + + if (platform_ptr) { + // All platforms for all modules in the exectuable match, so we can + // select this platform + platform_sp = platforms.front(); + } else if (more_than_one_platforms == false) { + // No platforms claim to support this file + error.SetErrorString("No matching platforms found for this file, " + "specify one with the --platform option"); + return error; + } else { + // More than one platform claims to support this file, so the + // --platform option must be specified + StreamString error_strm; + std::set<Platform *> platform_set; + error_strm.Printf( + "more than one platform supports this executable ("); + for (const auto &the_platform_sp : platforms) { + if (platform_set.find(the_platform_sp.get()) == + platform_set.end()) { + if (!platform_set.empty()) + error_strm.PutCString(", "); + error_strm.PutCString(the_platform_sp->GetName().GetCString()); + platform_set.insert(the_platform_sp.get()); + } + } + error_strm.Printf( + "), use the --platform option to specify a platform"); + error.SetErrorString(error_strm.GetString().c_str()); + return error; + } } + } } - - // If we have a valid architecture, make sure the current platform is - // compatible with that architecture - if (!prefer_platform_arch && arch.IsValid()) - { - if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) - { - platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); - if (!is_dummy_target && platform_sp) - debugger.GetPlatformList().SetSelectedPlatform(platform_sp); - } + } + + // If we have a valid architecture, make sure the current platform is + // compatible with that architecture + if (!prefer_platform_arch && arch.IsValid()) { + if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch)) { + platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch); + if (!is_dummy_target && platform_sp) + debugger.GetPlatformList().SetSelectedPlatform(platform_sp); } - else if (platform_arch.IsValid()) - { - // if "arch" isn't valid, yet "platform_arch" is, it means we have an executable file with - // a single architecture which should be used - ArchSpec fixed_platform_arch; - if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch)) - { - platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch); - if (!is_dummy_target && platform_sp) - debugger.GetPlatformList().SetSelectedPlatform(platform_sp); - } + } else if (platform_arch.IsValid()) { + // if "arch" isn't valid, yet "platform_arch" is, it means we have an + // executable file with + // a single architecture which should be used + ArchSpec fixed_platform_arch; + if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, + &fixed_platform_arch)) { + platform_sp = Platform::GetPlatformForArchitecture(platform_arch, + &fixed_platform_arch); + if (!is_dummy_target && platform_sp) + debugger.GetPlatformList().SetSelectedPlatform(platform_sp); } - - if (!platform_arch.IsValid()) - platform_arch = arch; - - error = TargetList::CreateTargetInternal (debugger, - user_exe_path, - platform_arch, - get_dependent_files, - platform_sp, - target_sp, - is_dummy_target); - return error; -} + } -lldb::TargetSP -TargetList::GetDummyTarget (lldb_private::Debugger &debugger) -{ - // FIXME: Maybe the dummy target should be per-Debugger - if (!m_dummy_target_sp || !m_dummy_target_sp->IsValid()) - { - ArchSpec arch(Target::GetDefaultArchitecture()); - if (!arch.IsValid()) - arch = HostInfo::GetArchitecture(); - Error err = CreateDummyTarget(debugger, - arch.GetTriple().getTriple().c_str(), - m_dummy_target_sp); - } + if (!platform_arch.IsValid()) + platform_arch = arch; - return m_dummy_target_sp; + error = TargetList::CreateTargetInternal( + debugger, user_exe_path, platform_arch, get_dependent_files, platform_sp, + target_sp, is_dummy_target); + return error; } -Error -TargetList::CreateDummyTarget (Debugger &debugger, - const char *specified_arch_name, - lldb::TargetSP &target_sp) -{ - PlatformSP host_platform_sp(Platform::GetHostPlatform()); - return CreateTargetInternal (debugger, - (const char *) nullptr, - specified_arch_name, - false, - (const OptionGroupPlatform *) nullptr, - target_sp, - true); +lldb::TargetSP TargetList::GetDummyTarget(lldb_private::Debugger &debugger) { + // FIXME: Maybe the dummy target should be per-Debugger + if (!m_dummy_target_sp || !m_dummy_target_sp->IsValid()) { + ArchSpec arch(Target::GetDefaultArchitecture()); + if (!arch.IsValid()) + arch = HostInfo::GetArchitecture(); + Error err = CreateDummyTarget( + debugger, arch.GetTriple().getTriple().c_str(), m_dummy_target_sp); + } + + return m_dummy_target_sp; } -Error -TargetList::CreateTargetInternal (Debugger &debugger, - const char *user_exe_path, - const ArchSpec& specified_arch, - bool get_dependent_files, - lldb::PlatformSP &platform_sp, - lldb::TargetSP &target_sp, - bool is_dummy_target) -{ - Timer scoped_timer (LLVM_PRETTY_FUNCTION, - "TargetList::CreateTarget (file = '%s', arch = '%s')", - user_exe_path, - specified_arch.GetArchitectureName()); - Error error; - - ArchSpec arch(specified_arch); - - if (arch.IsValid()) - { - if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, nullptr)) - platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); - } - - if (!platform_sp) - platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); +Error TargetList::CreateDummyTarget(Debugger &debugger, + const char *specified_arch_name, + lldb::TargetSP &target_sp) { + PlatformSP host_platform_sp(Platform::GetHostPlatform()); + return CreateTargetInternal( + debugger, (const char *)nullptr, specified_arch_name, false, + (const OptionGroupPlatform *)nullptr, target_sp, true); +} - if (!arch.IsValid()) - arch = specified_arch; - - FileSpec file (user_exe_path, false); - if (!file.Exists() && user_exe_path && user_exe_path[0] == '~') - { - // we want to expand the tilde but we don't want to resolve any symbolic links - // so we can't use the FileSpec constructor's resolve flag - llvm::SmallString<64> unglobbed_path(user_exe_path); - FileSpec::ResolveUsername(unglobbed_path); - - if (unglobbed_path.empty()) - file = FileSpec(user_exe_path, false); - else - file = FileSpec(unglobbed_path.c_str(), false); - } +Error TargetList::CreateTargetInternal(Debugger &debugger, + const char *user_exe_path, + const ArchSpec &specified_arch, + bool get_dependent_files, + lldb::PlatformSP &platform_sp, + lldb::TargetSP &target_sp, + bool is_dummy_target) { + Timer scoped_timer(LLVM_PRETTY_FUNCTION, + "TargetList::CreateTarget (file = '%s', arch = '%s')", + user_exe_path, specified_arch.GetArchitectureName()); + Error error; + + ArchSpec arch(specified_arch); + + if (arch.IsValid()) { + if (!platform_sp || + !platform_sp->IsCompatibleArchitecture(arch, false, nullptr)) + platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch); + } + + if (!platform_sp) + platform_sp = debugger.GetPlatformList().GetSelectedPlatform(); - bool user_exe_path_is_bundle = false; - char resolved_bundle_exe_path[PATH_MAX]; - resolved_bundle_exe_path[0] = '\0'; - if (file) - { - if (file.GetFileType() == FileSpec::eFileTypeDirectory) - user_exe_path_is_bundle = true; - - if (file.IsRelative() && user_exe_path) - { - // Ignore paths that start with "./" and "../" - if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') || - (user_exe_path[0] == '.' && user_exe_path[1] == '.' && user_exe_path[2] == '/'))) - { - char cwd[PATH_MAX]; - if (getcwd (cwd, sizeof(cwd))) - { - std::string cwd_user_exe_path (cwd); - cwd_user_exe_path += '/'; - cwd_user_exe_path += user_exe_path; - FileSpec cwd_file (cwd_user_exe_path.c_str(), false); - if (cwd_file.Exists()) - file = cwd_file; - } - } - } + if (!arch.IsValid()) + arch = specified_arch; - ModuleSP exe_module_sp; - if (platform_sp) - { - FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths()); - ModuleSpec module_spec(file, arch); - error = platform_sp->ResolveExecutable(module_spec, - exe_module_sp, - executable_search_paths.GetSize() ? &executable_search_paths : nullptr); - } + FileSpec file(user_exe_path, false); + if (!file.Exists() && user_exe_path && user_exe_path[0] == '~') { + // we want to expand the tilde but we don't want to resolve any symbolic + // links + // so we can't use the FileSpec constructor's resolve flag + llvm::SmallString<64> unglobbed_path(user_exe_path); + FileSpec::ResolveUsername(unglobbed_path); - if (error.Success() && exe_module_sp) - { - if (exe_module_sp->GetObjectFile() == nullptr) - { - if (arch.IsValid()) - { - error.SetErrorStringWithFormat("\"%s\" doesn't contain architecture %s", - file.GetPath().c_str(), - arch.GetArchitectureName()); - } - else - { - error.SetErrorStringWithFormat("unsupported file type \"%s\"", - file.GetPath().c_str()); - } - return error; - } - target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); - target_sp->SetExecutableModule (exe_module_sp, get_dependent_files); - if (user_exe_path_is_bundle) - exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path)); + if (unglobbed_path.empty()) + file = FileSpec(user_exe_path, false); + else + file = FileSpec(unglobbed_path.c_str(), false); + } + + bool user_exe_path_is_bundle = false; + char resolved_bundle_exe_path[PATH_MAX]; + resolved_bundle_exe_path[0] = '\0'; + if (file) { + if (file.GetFileType() == FileSpec::eFileTypeDirectory) + user_exe_path_is_bundle = true; + + if (file.IsRelative() && user_exe_path) { + // Ignore paths that start with "./" and "../" + if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') || + (user_exe_path[0] == '.' && user_exe_path[1] == '.' && + user_exe_path[2] == '/'))) { + char cwd[PATH_MAX]; + if (getcwd(cwd, sizeof(cwd))) { + std::string cwd_user_exe_path(cwd); + cwd_user_exe_path += '/'; + cwd_user_exe_path += user_exe_path; + FileSpec cwd_file(cwd_user_exe_path.c_str(), false); + if (cwd_file.Exists()) + file = cwd_file; } + } } - else - { - // No file was specified, just create an empty target with any arch - // if a valid arch was specified - target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); + + ModuleSP exe_module_sp; + if (platform_sp) { + FileSpecList executable_search_paths( + Target::GetDefaultExecutableSearchPaths()); + ModuleSpec module_spec(file, arch); + error = platform_sp->ResolveExecutable(module_spec, exe_module_sp, + executable_search_paths.GetSize() + ? &executable_search_paths + : nullptr); } - if (target_sp) - { - // Set argv0 with what the user typed, unless the user specified a - // directory. If the user specified a directory, then it is probably a - // bundle that was resolved and we need to use the resolved bundle path - if (user_exe_path) - { - // Use exactly what the user typed as the first argument when we exec or posix_spawn - if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) - { - target_sp->SetArg0 (resolved_bundle_exe_path); - } - else - { - // Use resolved path - target_sp->SetArg0 (file.GetPath().c_str()); - } - } - if (file.GetDirectory()) - { - FileSpec file_dir; - file_dir.GetDirectory() = file.GetDirectory(); - target_sp->GetExecutableSearchPaths ().Append (file_dir); + if (error.Success() && exe_module_sp) { + if (exe_module_sp->GetObjectFile() == nullptr) { + if (arch.IsValid()) { + error.SetErrorStringWithFormat( + "\"%s\" doesn't contain architecture %s", file.GetPath().c_str(), + arch.GetArchitectureName()); + } else { + error.SetErrorStringWithFormat("unsupported file type \"%s\"", + file.GetPath().c_str()); } + return error; + } + target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); + target_sp->SetExecutableModule(exe_module_sp, get_dependent_files); + if (user_exe_path_is_bundle) + exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, + sizeof(resolved_bundle_exe_path)); + } + } else { + // No file was specified, just create an empty target with any arch + // if a valid arch was specified + target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target)); + } + + if (target_sp) { + // Set argv0 with what the user typed, unless the user specified a + // directory. If the user specified a directory, then it is probably a + // bundle that was resolved and we need to use the resolved bundle path + if (user_exe_path) { + // Use exactly what the user typed as the first argument when we exec or + // posix_spawn + if (user_exe_path_is_bundle && resolved_bundle_exe_path[0]) { + target_sp->SetArg0(resolved_bundle_exe_path); + } else { + // Use resolved path + target_sp->SetArg0(file.GetPath().c_str()); + } + } + if (file.GetDirectory()) { + FileSpec file_dir; + file_dir.GetDirectory() = file.GetDirectory(); + target_sp->GetExecutableSearchPaths().Append(file_dir); + } - // Don't put the dummy target in the target list, it's held separately. - if (!is_dummy_target) - { - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - m_selected_target_idx = m_target_list.size(); - m_target_list.push_back(target_sp); - // Now prime this from the dummy target: - target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget()); - } - else - { - m_dummy_target_sp = target_sp; - } + // Don't put the dummy target in the target list, it's held separately. + if (!is_dummy_target) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + m_selected_target_idx = m_target_list.size(); + m_target_list.push_back(target_sp); + // Now prime this from the dummy target: + target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget()); + } else { + m_dummy_target_sp = target_sp; } + } - return error; + return error; } -bool -TargetList::DeleteTarget (TargetSP &target_sp) -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - collection::iterator pos, end = m_target_list.end(); +bool TargetList::DeleteTarget(TargetSP &target_sp) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + collection::iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) - { - if (pos->get() == target_sp.get()) - { - m_target_list.erase(pos); - return true; - } + for (pos = m_target_list.begin(); pos != end; ++pos) { + if (pos->get() == target_sp.get()) { + m_target_list.erase(pos); + return true; } - return false; + } + return false; } -TargetSP -TargetList::FindTargetWithExecutableAndArchitecture(const FileSpec &exe_file_spec, - const ArchSpec *exe_arch_ptr) const -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - TargetSP target_sp; - bool full_match = (bool)exe_file_spec.GetDirectory(); - - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) - { - Module *exe_module = (*pos)->GetExecutableModulePointer(); - - if (exe_module) - { - if (FileSpec::Equal (exe_file_spec, exe_module->GetFileSpec(), full_match)) - { - if (exe_arch_ptr) - { - if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture())) - continue; - } - target_sp = *pos; - break; - } +TargetSP TargetList::FindTargetWithExecutableAndArchitecture( + const FileSpec &exe_file_spec, const ArchSpec *exe_arch_ptr) const { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + TargetSP target_sp; + bool full_match = (bool)exe_file_spec.GetDirectory(); + + collection::const_iterator pos, end = m_target_list.end(); + for (pos = m_target_list.begin(); pos != end; ++pos) { + Module *exe_module = (*pos)->GetExecutableModulePointer(); + + if (exe_module) { + if (FileSpec::Equal(exe_file_spec, exe_module->GetFileSpec(), + full_match)) { + if (exe_arch_ptr) { + if (!exe_arch_ptr->IsCompatibleMatch(exe_module->GetArchitecture())) + continue; } + target_sp = *pos; + break; + } } - return target_sp; + } + return target_sp; } -TargetSP -TargetList::FindTargetWithProcessID (lldb::pid_t pid) const -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - TargetSP target_sp; - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) - { - Process* process = (*pos)->GetProcessSP().get(); - if (process && process->GetID() == pid) - { - target_sp = *pos; - break; - } +TargetSP TargetList::FindTargetWithProcessID(lldb::pid_t pid) const { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + TargetSP target_sp; + collection::const_iterator pos, end = m_target_list.end(); + for (pos = m_target_list.begin(); pos != end; ++pos) { + Process *process = (*pos)->GetProcessSP().get(); + if (process && process->GetID() == pid) { + target_sp = *pos; + break; } - return target_sp; + } + return target_sp; } -TargetSP -TargetList::FindTargetWithProcess (Process *process) const -{ - TargetSP target_sp; - if (process) - { - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) - { - if (process == (*pos)->GetProcessSP().get()) - { - target_sp = *pos; - break; - } - } +TargetSP TargetList::FindTargetWithProcess(Process *process) const { + TargetSP target_sp; + if (process) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + collection::const_iterator pos, end = m_target_list.end(); + for (pos = m_target_list.begin(); pos != end; ++pos) { + if (process == (*pos)->GetProcessSP().get()) { + target_sp = *pos; + break; + } } - return target_sp; + } + return target_sp; } -TargetSP -TargetList::GetTargetSP (Target *target) const -{ - TargetSP target_sp; - if (target) - { - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - collection::const_iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) - { - if (target == (*pos).get()) - { - target_sp = *pos; - break; - } - } +TargetSP TargetList::GetTargetSP(Target *target) const { + TargetSP target_sp; + if (target) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + collection::const_iterator pos, end = m_target_list.end(); + for (pos = m_target_list.begin(); pos != end; ++pos) { + if (target == (*pos).get()) { + target_sp = *pos; + break; + } } - return target_sp; + } + return target_sp; } -uint32_t -TargetList::SendAsyncInterrupt (lldb::pid_t pid) -{ - uint32_t num_async_interrupts_sent = 0; - - if (pid != LLDB_INVALID_PROCESS_ID) - { - TargetSP target_sp(FindTargetWithProcessID (pid)); - if (target_sp) - { - Process* process = target_sp->GetProcessSP().get(); - if (process) - { - process->SendAsyncInterrupt(); - ++num_async_interrupts_sent; - } - } - } - else - { - // We don't have a valid pid to broadcast to, so broadcast to the target - // list's async broadcaster... - BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr); +uint32_t TargetList::SendAsyncInterrupt(lldb::pid_t pid) { + uint32_t num_async_interrupts_sent = 0; + + if (pid != LLDB_INVALID_PROCESS_ID) { + TargetSP target_sp(FindTargetWithProcessID(pid)); + if (target_sp) { + Process *process = target_sp->GetProcessSP().get(); + if (process) { + process->SendAsyncInterrupt(); + ++num_async_interrupts_sent; + } } + } else { + // We don't have a valid pid to broadcast to, so broadcast to the target + // list's async broadcaster... + BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr); + } - return num_async_interrupts_sent; + return num_async_interrupts_sent; } -uint32_t -TargetList::SignalIfRunning (lldb::pid_t pid, int signo) -{ - uint32_t num_signals_sent = 0; - Process *process = nullptr; - if (pid == LLDB_INVALID_PROCESS_ID) - { - // Signal all processes with signal - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - collection::iterator pos, end = m_target_list.end(); - for (pos = m_target_list.begin(); pos != end; ++pos) - { - process = (*pos)->GetProcessSP().get(); - if (process) - { - if (process->IsAlive()) - { - ++num_signals_sent; - process->Signal (signo); - } - } +uint32_t TargetList::SignalIfRunning(lldb::pid_t pid, int signo) { + uint32_t num_signals_sent = 0; + Process *process = nullptr; + if (pid == LLDB_INVALID_PROCESS_ID) { + // Signal all processes with signal + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + collection::iterator pos, end = m_target_list.end(); + for (pos = m_target_list.begin(); pos != end; ++pos) { + process = (*pos)->GetProcessSP().get(); + if (process) { + if (process->IsAlive()) { + ++num_signals_sent; + process->Signal(signo); } + } } - else - { - // Signal a specific process with signal - TargetSP target_sp(FindTargetWithProcessID (pid)); - if (target_sp) - { - process = target_sp->GetProcessSP().get(); - if (process) - { - if (process->IsAlive()) - { - ++num_signals_sent; - process->Signal (signo); - } - } + } else { + // Signal a specific process with signal + TargetSP target_sp(FindTargetWithProcessID(pid)); + if (target_sp) { + process = target_sp->GetProcessSP().get(); + if (process) { + if (process->IsAlive()) { + ++num_signals_sent; + process->Signal(signo); } + } } - return num_signals_sent; + } + return num_signals_sent; } -int -TargetList::GetNumTargets () const -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - return m_target_list.size(); +int TargetList::GetNumTargets() const { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + return m_target_list.size(); } -lldb::TargetSP -TargetList::GetTargetAtIndex (uint32_t idx) const -{ - TargetSP target_sp; - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - if (idx < m_target_list.size()) - target_sp = m_target_list[idx]; - return target_sp; +lldb::TargetSP TargetList::GetTargetAtIndex(uint32_t idx) const { + TargetSP target_sp; + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + if (idx < m_target_list.size()) + target_sp = m_target_list[idx]; + return target_sp; } -uint32_t -TargetList::GetIndexOfTarget (lldb::TargetSP target_sp) const -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - size_t num_targets = m_target_list.size(); - for (size_t idx = 0; idx < num_targets; idx++) - { - if (target_sp == m_target_list[idx]) - return idx; - } - return UINT32_MAX; +uint32_t TargetList::GetIndexOfTarget(lldb::TargetSP target_sp) const { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + size_t num_targets = m_target_list.size(); + for (size_t idx = 0; idx < num_targets; idx++) { + if (target_sp == m_target_list[idx]) + return idx; + } + return UINT32_MAX; } -uint32_t -TargetList::SetSelectedTarget (Target* target) -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - collection::const_iterator pos, - begin = m_target_list.begin(), - end = m_target_list.end(); - for (pos = begin; pos != end; ++pos) - { - if (pos->get() == target) - { - m_selected_target_idx = std::distance (begin, pos); - return m_selected_target_idx; - } +uint32_t TargetList::SetSelectedTarget(Target *target) { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + collection::const_iterator pos, begin = m_target_list.begin(), + end = m_target_list.end(); + for (pos = begin; pos != end; ++pos) { + if (pos->get() == target) { + m_selected_target_idx = std::distance(begin, pos); + return m_selected_target_idx; } - m_selected_target_idx = 0; - return m_selected_target_idx; + } + m_selected_target_idx = 0; + return m_selected_target_idx; } -lldb::TargetSP -TargetList::GetSelectedTarget () -{ - std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); - if (m_selected_target_idx >= m_target_list.size()) - m_selected_target_idx = 0; - return GetTargetAtIndex (m_selected_target_idx); +lldb::TargetSP TargetList::GetSelectedTarget() { + std::lock_guard<std::recursive_mutex> guard(m_target_list_mutex); + if (m_selected_target_idx >= m_target_list.size()) + m_selected_target_idx = 0; + return GetTargetAtIndex(m_selected_target_idx); } diff --git a/lldb/source/Target/Thread.cpp b/lldb/source/Target/Thread.cpp index 26502f2eb4b..676bbf09b5e 100644 --- a/lldb/source/Target/Thread.cpp +++ b/lldb/source/Target/Thread.cpp @@ -11,15 +11,18 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/Target/Thread.h" +#include "Plugins/Process/Utility/UnwindLLDB.h" +#include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h" #include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Core/Debugger.h" -#include "lldb/Core/Log.h" #include "lldb/Core/FormatEntity.h" +#include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Core/RegularExpression.h" #include "lldb/Core/State.h" #include "lldb/Core/Stream.h" #include "lldb/Core/StreamString.h" -#include "lldb/Core/RegularExpression.h" #include "lldb/Core/ValueObject.h" #include "lldb/Host/Host.h" #include "lldb/Interpreter/OptionValueFileSpecList.h" @@ -34,2478 +37,2141 @@ #include "lldb/Target/StopInfo.h" #include "lldb/Target/SystemRuntime.h" #include "lldb/Target/Target.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" -#include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanBase.h" +#include "lldb/Target/ThreadPlanCallFunction.h" #include "lldb/Target/ThreadPlanPython.h" +#include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Target/ThreadPlanStepInRange.h" #include "lldb/Target/ThreadPlanStepInstruction.h" #include "lldb/Target/ThreadPlanStepOut.h" #include "lldb/Target/ThreadPlanStepOverBreakpoint.h" -#include "lldb/Target/ThreadPlanStepThrough.h" -#include "lldb/Target/ThreadPlanStepInRange.h" #include "lldb/Target/ThreadPlanStepOverRange.h" -#include "lldb/Target/ThreadPlanRunToAddress.h" +#include "lldb/Target/ThreadPlanStepThrough.h" #include "lldb/Target/ThreadPlanStepUntil.h" #include "lldb/Target/ThreadSpec.h" #include "lldb/Target/Unwind.h" -#include "Plugins/Process/Utility/UnwindLLDB.h" -#include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h" using namespace lldb; using namespace lldb_private; -const ThreadPropertiesSP & -Thread::GetGlobalProperties() -{ - // NOTE: intentional leak so we don't crash if global destructor chain gets - // called as other threads still use the result of this function - static ThreadPropertiesSP *g_settings_sp_ptr = nullptr; - static std::once_flag g_once_flag; - std::call_once(g_once_flag, []() { - g_settings_sp_ptr = new ThreadPropertiesSP(new ThreadProperties (true)); - }); - return *g_settings_sp_ptr; -} - -static PropertyDefinition -g_properties[] = -{ - { "step-in-avoid-nodebug", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, step-in will not stop in functions with no debug information." }, - { "step-out-avoid-nodebug", OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, when step-in/step-out/step-over leave the current frame, they will continue to step out till they come to a function with " - "debug information. Passing a frame argument to step-out will override this option." }, - { "step-avoid-regexp", OptionValue::eTypeRegex , true , 0, "^std::", nullptr, "A regular expression defining functions step-in won't stop in." }, - { "step-avoid-libraries", OptionValue::eTypeFileSpecList , true , 0, nullptr, nullptr, "A list of libraries that source stepping won't stop in." }, - { "trace-thread", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, "If true, this thread will single-step and log execution." }, - { nullptr , OptionValue::eTypeInvalid, false, 0 , nullptr, nullptr, nullptr } -}; +const ThreadPropertiesSP &Thread::GetGlobalProperties() { + // NOTE: intentional leak so we don't crash if global destructor chain gets + // called as other threads still use the result of this function + static ThreadPropertiesSP *g_settings_sp_ptr = nullptr; + static std::once_flag g_once_flag; + std::call_once(g_once_flag, []() { + g_settings_sp_ptr = new ThreadPropertiesSP(new ThreadProperties(true)); + }); + return *g_settings_sp_ptr; +} + +static PropertyDefinition g_properties[] = { + {"step-in-avoid-nodebug", OptionValue::eTypeBoolean, true, true, nullptr, + nullptr, + "If true, step-in will not stop in functions with no debug information."}, + {"step-out-avoid-nodebug", OptionValue::eTypeBoolean, true, false, nullptr, + nullptr, "If true, when step-in/step-out/step-over leave the current " + "frame, they will continue to step out till they come to a " + "function with " + "debug information. Passing a frame argument to step-out will " + "override this option."}, + {"step-avoid-regexp", OptionValue::eTypeRegex, true, 0, "^std::", nullptr, + "A regular expression defining functions step-in won't stop in."}, + {"step-avoid-libraries", OptionValue::eTypeFileSpecList, true, 0, nullptr, + nullptr, "A list of libraries that source stepping won't stop in."}, + {"trace-thread", OptionValue::eTypeBoolean, false, false, nullptr, nullptr, + "If true, this thread will single-step and log execution."}, + {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}}; enum { - ePropertyStepInAvoidsNoDebug, - ePropertyStepOutAvoidsNoDebug, - ePropertyStepAvoidRegex, - ePropertyStepAvoidLibraries, - ePropertyEnableThreadTrace + ePropertyStepInAvoidsNoDebug, + ePropertyStepOutAvoidsNoDebug, + ePropertyStepAvoidRegex, + ePropertyStepAvoidLibraries, + ePropertyEnableThreadTrace }; -class ThreadOptionValueProperties : public OptionValueProperties -{ +class ThreadOptionValueProperties : public OptionValueProperties { public: - ThreadOptionValueProperties (const ConstString &name) : - OptionValueProperties (name) - { - } - - // This constructor is used when creating ThreadOptionValueProperties when it - // is part of a new lldb_private::Thread instance. It will copy all current - // global property values as needed - ThreadOptionValueProperties (ThreadProperties *global_properties) : - OptionValueProperties(*global_properties->GetValueProperties()) - { - } - - const Property * - GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override - { - // When getting the value for a key from the thread options, we will always - // try and grab the setting from the current thread if there is one. Else we just - // use the one from this instance. - if (exe_ctx) - { - Thread *thread = exe_ctx->GetThreadPtr(); - if (thread) - { - ThreadOptionValueProperties *instance_properties = static_cast<ThreadOptionValueProperties *>(thread->GetValueProperties().get()); - if (this != instance_properties) - return instance_properties->ProtectedGetPropertyAtIndex (idx); - } - } - return ProtectedGetPropertyAtIndex (idx); - } + ThreadOptionValueProperties(const ConstString &name) + : OptionValueProperties(name) {} + + // This constructor is used when creating ThreadOptionValueProperties when it + // is part of a new lldb_private::Thread instance. It will copy all current + // global property values as needed + ThreadOptionValueProperties(ThreadProperties *global_properties) + : OptionValueProperties(*global_properties->GetValueProperties()) {} + + const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx, + bool will_modify, + uint32_t idx) const override { + // When getting the value for a key from the thread options, we will always + // try and grab the setting from the current thread if there is one. Else we + // just + // use the one from this instance. + if (exe_ctx) { + Thread *thread = exe_ctx->GetThreadPtr(); + if (thread) { + ThreadOptionValueProperties *instance_properties = + static_cast<ThreadOptionValueProperties *>( + thread->GetValueProperties().get()); + if (this != instance_properties) + return instance_properties->ProtectedGetPropertyAtIndex(idx); + } + } + return ProtectedGetPropertyAtIndex(idx); + } }; -ThreadProperties::ThreadProperties (bool is_global) : - Properties () -{ - if (is_global) - { - m_collection_sp.reset (new ThreadOptionValueProperties(ConstString("thread"))); - m_collection_sp->Initialize(g_properties); - } - else - m_collection_sp.reset (new ThreadOptionValueProperties(Thread::GetGlobalProperties().get())); +ThreadProperties::ThreadProperties(bool is_global) : Properties() { + if (is_global) { + m_collection_sp.reset( + new ThreadOptionValueProperties(ConstString("thread"))); + m_collection_sp->Initialize(g_properties); + } else + m_collection_sp.reset( + new ThreadOptionValueProperties(Thread::GetGlobalProperties().get())); } ThreadProperties::~ThreadProperties() = default; -const RegularExpression * -ThreadProperties::GetSymbolsToAvoidRegexp() -{ - const uint32_t idx = ePropertyStepAvoidRegex; - return m_collection_sp->GetPropertyAtIndexAsOptionValueRegex(nullptr, idx); +const RegularExpression *ThreadProperties::GetSymbolsToAvoidRegexp() { + const uint32_t idx = ePropertyStepAvoidRegex; + return m_collection_sp->GetPropertyAtIndexAsOptionValueRegex(nullptr, idx); } -FileSpecList & -ThreadProperties::GetLibrariesToAvoid() const -{ - const uint32_t idx = ePropertyStepAvoidLibraries; - OptionValueFileSpecList *option_value = m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, false, idx); - assert(option_value); - return option_value->GetCurrentValue(); +FileSpecList &ThreadProperties::GetLibrariesToAvoid() const { + const uint32_t idx = ePropertyStepAvoidLibraries; + OptionValueFileSpecList *option_value = + m_collection_sp->GetPropertyAtIndexAsOptionValueFileSpecList(nullptr, + false, idx); + assert(option_value); + return option_value->GetCurrentValue(); } -bool -ThreadProperties::GetTraceEnabledState() const -{ - const uint32_t idx = ePropertyEnableThreadTrace; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool ThreadProperties::GetTraceEnabledState() const { + const uint32_t idx = ePropertyEnableThreadTrace; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -ThreadProperties::GetStepInAvoidsNoDebug() const -{ - const uint32_t idx = ePropertyStepInAvoidsNoDebug; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool ThreadProperties::GetStepInAvoidsNoDebug() const { + const uint32_t idx = ePropertyStepInAvoidsNoDebug; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } -bool -ThreadProperties::GetStepOutAvoidsNoDebug() const -{ - const uint32_t idx = ePropertyStepOutAvoidsNoDebug; - return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0); +bool ThreadProperties::GetStepOutAvoidsNoDebug() const { + const uint32_t idx = ePropertyStepOutAvoidsNoDebug; + return m_collection_sp->GetPropertyAtIndexAsBoolean( + nullptr, idx, g_properties[idx].default_uint_value != 0); } //------------------------------------------------------------------ // Thread Event Data //------------------------------------------------------------------ -const ConstString & -Thread::ThreadEventData::GetFlavorString () -{ - static ConstString g_flavor ("Thread::ThreadEventData"); - return g_flavor; +const ConstString &Thread::ThreadEventData::GetFlavorString() { + static ConstString g_flavor("Thread::ThreadEventData"); + return g_flavor; } -Thread::ThreadEventData::ThreadEventData (const lldb::ThreadSP thread_sp) : - m_thread_sp (thread_sp), - m_stack_id () -{ -} +Thread::ThreadEventData::ThreadEventData(const lldb::ThreadSP thread_sp) + : m_thread_sp(thread_sp), m_stack_id() {} -Thread::ThreadEventData::ThreadEventData (const lldb::ThreadSP thread_sp, const StackID &stack_id) : - m_thread_sp (thread_sp), - m_stack_id (stack_id) -{ -} +Thread::ThreadEventData::ThreadEventData(const lldb::ThreadSP thread_sp, + const StackID &stack_id) + : m_thread_sp(thread_sp), m_stack_id(stack_id) {} -Thread::ThreadEventData::ThreadEventData () : - m_thread_sp (), - m_stack_id () -{ -} +Thread::ThreadEventData::ThreadEventData() : m_thread_sp(), m_stack_id() {} Thread::ThreadEventData::~ThreadEventData() = default; -void -Thread::ThreadEventData::Dump (Stream *s) const -{ -} +void Thread::ThreadEventData::Dump(Stream *s) const {} const Thread::ThreadEventData * -Thread::ThreadEventData::GetEventDataFromEvent (const Event *event_ptr) -{ - if (event_ptr) - { - const EventData *event_data = event_ptr->GetData(); - if (event_data && event_data->GetFlavor() == ThreadEventData::GetFlavorString()) - return static_cast <const ThreadEventData *> (event_ptr->GetData()); - } - return nullptr; +Thread::ThreadEventData::GetEventDataFromEvent(const Event *event_ptr) { + if (event_ptr) { + const EventData *event_data = event_ptr->GetData(); + if (event_data && + event_data->GetFlavor() == ThreadEventData::GetFlavorString()) + return static_cast<const ThreadEventData *>(event_ptr->GetData()); + } + return nullptr; } -ThreadSP -Thread::ThreadEventData::GetThreadFromEvent (const Event *event_ptr) -{ - ThreadSP thread_sp; - const ThreadEventData *event_data = GetEventDataFromEvent (event_ptr); - if (event_data) - thread_sp = event_data->GetThread(); - return thread_sp; +ThreadSP Thread::ThreadEventData::GetThreadFromEvent(const Event *event_ptr) { + ThreadSP thread_sp; + const ThreadEventData *event_data = GetEventDataFromEvent(event_ptr); + if (event_data) + thread_sp = event_data->GetThread(); + return thread_sp; } -StackID -Thread::ThreadEventData::GetStackIDFromEvent (const Event *event_ptr) -{ - StackID stack_id; - const ThreadEventData *event_data = GetEventDataFromEvent (event_ptr); - if (event_data) - stack_id = event_data->GetStackID(); - return stack_id; +StackID Thread::ThreadEventData::GetStackIDFromEvent(const Event *event_ptr) { + StackID stack_id; + const ThreadEventData *event_data = GetEventDataFromEvent(event_ptr); + if (event_data) + stack_id = event_data->GetStackID(); + return stack_id; } StackFrameSP -Thread::ThreadEventData::GetStackFrameFromEvent (const Event *event_ptr) -{ - const ThreadEventData *event_data = GetEventDataFromEvent (event_ptr); - StackFrameSP frame_sp; - if (event_data) - { - ThreadSP thread_sp = event_data->GetThread(); - if (thread_sp) - { - frame_sp = thread_sp->GetStackFrameList()->GetFrameWithStackID (event_data->GetStackID()); - } +Thread::ThreadEventData::GetStackFrameFromEvent(const Event *event_ptr) { + const ThreadEventData *event_data = GetEventDataFromEvent(event_ptr); + StackFrameSP frame_sp; + if (event_data) { + ThreadSP thread_sp = event_data->GetThread(); + if (thread_sp) { + frame_sp = thread_sp->GetStackFrameList()->GetFrameWithStackID( + event_data->GetStackID()); } - return frame_sp; + } + return frame_sp; } //------------------------------------------------------------------ // Thread class //------------------------------------------------------------------ -ConstString & -Thread::GetStaticBroadcasterClass () -{ - static ConstString class_name ("lldb.thread"); - return class_name; +ConstString &Thread::GetStaticBroadcasterClass() { + static ConstString class_name("lldb.thread"); + return class_name; } Thread::Thread(Process &process, lldb::tid_t tid, bool use_invalid_index_id) - : ThreadProperties(false), - UserID(tid), + : ThreadProperties(false), UserID(tid), Broadcaster(process.GetTarget().GetDebugger().GetBroadcasterManager(), Thread::GetStaticBroadcasterClass().AsCString()), - m_process_wp(process.shared_from_this()), - m_stop_info_sp(), - m_stop_info_stop_id(0), - m_stop_info_override_stop_id(0), - m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)), - m_reg_context_sp(), - m_state(eStateUnloaded), - m_state_mutex(), - m_plan_stack(), - m_completed_plan_stack(), - m_frame_mutex(), - m_curr_frames_sp(), - m_prev_frames_sp(), + m_process_wp(process.shared_from_this()), m_stop_info_sp(), + m_stop_info_stop_id(0), m_stop_info_override_stop_id(0), + m_index_id(use_invalid_index_id ? LLDB_INVALID_INDEX32 + : process.GetNextThreadIndexID(tid)), + m_reg_context_sp(), m_state(eStateUnloaded), m_state_mutex(), + m_plan_stack(), m_completed_plan_stack(), m_frame_mutex(), + m_curr_frames_sp(), m_prev_frames_sp(), m_resume_signal(LLDB_INVALID_SIGNAL_NUMBER), - m_resume_state(eStateRunning), - m_temporary_resume_state(eStateRunning), - m_unwinder_ap(), - m_destroy_called(false), + m_resume_state(eStateRunning), m_temporary_resume_state(eStateRunning), + m_unwinder_ap(), m_destroy_called(false), m_override_should_notify(eLazyBoolCalculate), - m_extended_info_fetched(false), - m_extended_info() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", static_cast<void *>(this), GetID()); - - CheckInWithManager(); - QueueFundamentalPlan(true); -} - -Thread::~Thread() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT)); - if (log) - log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", - static_cast<void*>(this), GetID()); - /// If you hit this assert, it means your derived class forgot to call DoDestroy in its destructor. - assert (m_destroy_called); -} - -void -Thread::DestroyThread () -{ - // Tell any plans on the plan stacks that the thread is being destroyed since - // any plans that have a thread go away in the middle of might need - // to do cleanup, or in some cases NOT do cleanup... - for (auto plan : m_plan_stack) - plan->ThreadDestroyed(); - - for (auto plan : m_discarded_plan_stack) - plan->ThreadDestroyed(); - - for (auto plan : m_completed_plan_stack) - plan->ThreadDestroyed(); - - m_destroy_called = true; - m_plan_stack.clear(); - m_discarded_plan_stack.clear(); - m_completed_plan_stack.clear(); - - // Push a ThreadPlanNull on the plan stack. That way we can continue assuming that the - // plan stack is never empty, but if somebody errantly asks questions of a destroyed thread - // without checking first whether it is destroyed, they won't crash. - ThreadPlanSP null_plan_sp(new ThreadPlanNull (*this)); - m_plan_stack.push_back (null_plan_sp); - - m_stop_info_sp.reset(); - m_reg_context_sp.reset(); - m_unwinder_ap.reset(); - std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); - m_curr_frames_sp.reset(); - m_prev_frames_sp.reset(); -} - -void -Thread::BroadcastSelectedFrameChange(StackID &new_frame_id) -{ - if (EventTypeHasListeners(eBroadcastBitSelectedFrameChanged)) - BroadcastEvent(eBroadcastBitSelectedFrameChanged, new ThreadEventData (this->shared_from_this(), new_frame_id)); -} - -lldb::StackFrameSP -Thread::GetSelectedFrame() -{ - StackFrameListSP stack_frame_list_sp(GetStackFrameList()); - StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex (stack_frame_list_sp->GetSelectedFrameIndex()); - FunctionOptimizationWarning (frame_sp.get()); - return frame_sp; -} - -uint32_t -Thread::SetSelectedFrame (lldb_private::StackFrame *frame, bool broadcast) -{ - uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame); + m_extended_info_fetched(false), m_extended_info() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")", + static_cast<void *>(this), GetID()); + + CheckInWithManager(); + QueueFundamentalPlan(true); +} + +Thread::~Thread() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT)); + if (log) + log->Printf("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", + static_cast<void *>(this), GetID()); + /// If you hit this assert, it means your derived class forgot to call + /// DoDestroy in its destructor. + assert(m_destroy_called); +} + +void Thread::DestroyThread() { + // Tell any plans on the plan stacks that the thread is being destroyed since + // any plans that have a thread go away in the middle of might need + // to do cleanup, or in some cases NOT do cleanup... + for (auto plan : m_plan_stack) + plan->ThreadDestroyed(); + + for (auto plan : m_discarded_plan_stack) + plan->ThreadDestroyed(); + + for (auto plan : m_completed_plan_stack) + plan->ThreadDestroyed(); + + m_destroy_called = true; + m_plan_stack.clear(); + m_discarded_plan_stack.clear(); + m_completed_plan_stack.clear(); + + // Push a ThreadPlanNull on the plan stack. That way we can continue assuming + // that the + // plan stack is never empty, but if somebody errantly asks questions of a + // destroyed thread + // without checking first whether it is destroyed, they won't crash. + ThreadPlanSP null_plan_sp(new ThreadPlanNull(*this)); + m_plan_stack.push_back(null_plan_sp); + + m_stop_info_sp.reset(); + m_reg_context_sp.reset(); + m_unwinder_ap.reset(); + std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); + m_curr_frames_sp.reset(); + m_prev_frames_sp.reset(); +} + +void Thread::BroadcastSelectedFrameChange(StackID &new_frame_id) { + if (EventTypeHasListeners(eBroadcastBitSelectedFrameChanged)) + BroadcastEvent(eBroadcastBitSelectedFrameChanged, + new ThreadEventData(this->shared_from_this(), new_frame_id)); +} + +lldb::StackFrameSP Thread::GetSelectedFrame() { + StackFrameListSP stack_frame_list_sp(GetStackFrameList()); + StackFrameSP frame_sp = stack_frame_list_sp->GetFrameAtIndex( + stack_frame_list_sp->GetSelectedFrameIndex()); + FunctionOptimizationWarning(frame_sp.get()); + return frame_sp; +} + +uint32_t Thread::SetSelectedFrame(lldb_private::StackFrame *frame, + bool broadcast) { + uint32_t ret_value = GetStackFrameList()->SetSelectedFrame(frame); + if (broadcast) + BroadcastSelectedFrameChange(frame->GetStackID()); + FunctionOptimizationWarning(frame); + return ret_value; +} + +bool Thread::SetSelectedFrameByIndex(uint32_t frame_idx, bool broadcast) { + StackFrameSP frame_sp(GetStackFrameList()->GetFrameAtIndex(frame_idx)); + if (frame_sp) { + GetStackFrameList()->SetSelectedFrame(frame_sp.get()); if (broadcast) - BroadcastSelectedFrameChange(frame->GetStackID()); - FunctionOptimizationWarning (frame); - return ret_value; -} - -bool -Thread::SetSelectedFrameByIndex (uint32_t frame_idx, bool broadcast) -{ - StackFrameSP frame_sp(GetStackFrameList()->GetFrameAtIndex (frame_idx)); - if (frame_sp) - { - GetStackFrameList()->SetSelectedFrame(frame_sp.get()); - if (broadcast) - BroadcastSelectedFrameChange(frame_sp->GetStackID()); - FunctionOptimizationWarning (frame_sp.get()); - return true; - } - else - return false; -} - -bool -Thread::SetSelectedFrameByIndexNoisily (uint32_t frame_idx, Stream &output_stream) -{ - const bool broadcast = true; - bool success = SetSelectedFrameByIndex (frame_idx, broadcast); - if (success) - { - StackFrameSP frame_sp = GetSelectedFrame(); - if (frame_sp) - { - bool already_shown = false; - SymbolContext frame_sc(frame_sp->GetSymbolContext(eSymbolContextLineEntry)); - if (GetProcess()->GetTarget().GetDebugger().GetUseExternalEditor() && frame_sc.line_entry.file && frame_sc.line_entry.line != 0) - { - already_shown = Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); - } - - bool show_frame_info = true; - bool show_source = !already_shown; - FunctionOptimizationWarning (frame_sp.get()); - return frame_sp->GetStatus (output_stream, show_frame_info, show_source); - } - return false; - } - else - return false; + BroadcastSelectedFrameChange(frame_sp->GetStackID()); + FunctionOptimizationWarning(frame_sp.get()); + return true; + } else + return false; } -void -Thread::FunctionOptimizationWarning (StackFrame *frame) -{ - if (frame && frame->HasDebugInformation() && GetProcess()->GetWarningsOptimization()) - { - SymbolContext sc = frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextModule); - GetProcess()->PrintWarningOptimization (sc); +bool Thread::SetSelectedFrameByIndexNoisily(uint32_t frame_idx, + Stream &output_stream) { + const bool broadcast = true; + bool success = SetSelectedFrameByIndex(frame_idx, broadcast); + if (success) { + StackFrameSP frame_sp = GetSelectedFrame(); + if (frame_sp) { + bool already_shown = false; + SymbolContext frame_sc( + frame_sp->GetSymbolContext(eSymbolContextLineEntry)); + if (GetProcess()->GetTarget().GetDebugger().GetUseExternalEditor() && + frame_sc.line_entry.file && frame_sc.line_entry.line != 0) { + already_shown = Host::OpenFileInExternalEditor( + frame_sc.line_entry.file, frame_sc.line_entry.line); + } + + bool show_frame_info = true; + bool show_source = !already_shown; + FunctionOptimizationWarning(frame_sp.get()); + return frame_sp->GetStatus(output_stream, show_frame_info, show_source); } + return false; + } else + return false; } -lldb::StopInfoSP -Thread::GetStopInfo () -{ - if (m_destroy_called) - return m_stop_info_sp; - - ThreadPlanSP plan_sp (GetCompletedPlan()); - ProcessSP process_sp (GetProcess()); - const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX; - if (plan_sp && plan_sp->PlanSucceeded()) - { - return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject(), GetExpressionVariable()); - } - else - { - if ((m_stop_info_stop_id == stop_id) || // Stop info is valid, just return what we have (even if empty) - (m_stop_info_sp && m_stop_info_sp->IsValid())) // Stop info is valid, just return what we have - { - return m_stop_info_sp; - } - else - { - GetPrivateStopInfo (); - return m_stop_info_sp; - } - } +void Thread::FunctionOptimizationWarning(StackFrame *frame) { + if (frame && frame->HasDebugInformation() && + GetProcess()->GetWarningsOptimization()) { + SymbolContext sc = + frame->GetSymbolContext(eSymbolContextFunction | eSymbolContextModule); + GetProcess()->PrintWarningOptimization(sc); + } } -lldb::StopInfoSP -Thread::GetPrivateStopInfo () -{ - if (m_destroy_called) - return m_stop_info_sp; - - ProcessSP process_sp (GetProcess()); - if (process_sp) - { - const uint32_t process_stop_id = process_sp->GetStopID(); - if (m_stop_info_stop_id != process_stop_id) - { - if (m_stop_info_sp) - { - if (m_stop_info_sp->IsValid() - || IsStillAtLastBreakpointHit() - || GetCurrentPlan()->IsVirtualStep()) - SetStopInfo (m_stop_info_sp); - else - m_stop_info_sp.reset(); - } - - if (!m_stop_info_sp) - { - if (!CalculateStopInfo()) - SetStopInfo (StopInfoSP()); - } - } +lldb::StopInfoSP Thread::GetStopInfo() { + if (m_destroy_called) + return m_stop_info_sp; - // The stop info can be manually set by calling Thread::SetStopInfo() - // prior to this function ever getting called, so we can't rely on - // "m_stop_info_stop_id != process_stop_id" as the condition for - // the if statement below, we must also check the stop info to see - // if we need to override it. See the header documentation in - // Process::GetStopInfoOverrideCallback() for more information on - // the stop info override callback. - if (m_stop_info_override_stop_id != process_stop_id) - { - m_stop_info_override_stop_id = process_stop_id; - if (m_stop_info_sp) - { - ArchSpec::StopInfoOverrideCallbackType callback = GetProcess()->GetStopInfoOverrideCallback(); - if (callback) - callback(*this); - } - } - } + ThreadPlanSP plan_sp(GetCompletedPlan()); + ProcessSP process_sp(GetProcess()); + const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX; + if (plan_sp && plan_sp->PlanSucceeded()) { + return StopInfo::CreateStopReasonWithPlan(plan_sp, GetReturnValueObject(), + GetExpressionVariable()); + } else { + if ((m_stop_info_stop_id == stop_id) || // Stop info is valid, just return + // what we have (even if empty) + (m_stop_info_sp && + m_stop_info_sp + ->IsValid())) // Stop info is valid, just return what we have + { + return m_stop_info_sp; + } else { + GetPrivateStopInfo(); + return m_stop_info_sp; + } + } +} + +lldb::StopInfoSP Thread::GetPrivateStopInfo() { + if (m_destroy_called) return m_stop_info_sp; -} -lldb::StopReason -Thread::GetStopReason() -{ - lldb::StopInfoSP stop_info_sp (GetStopInfo ()); - if (stop_info_sp) - return stop_info_sp->GetStopReason(); - return eStopReasonNone; + ProcessSP process_sp(GetProcess()); + if (process_sp) { + const uint32_t process_stop_id = process_sp->GetStopID(); + if (m_stop_info_stop_id != process_stop_id) { + if (m_stop_info_sp) { + if (m_stop_info_sp->IsValid() || IsStillAtLastBreakpointHit() || + GetCurrentPlan()->IsVirtualStep()) + SetStopInfo(m_stop_info_sp); + else + m_stop_info_sp.reset(); + } + + if (!m_stop_info_sp) { + if (!CalculateStopInfo()) + SetStopInfo(StopInfoSP()); + } + } + + // The stop info can be manually set by calling Thread::SetStopInfo() + // prior to this function ever getting called, so we can't rely on + // "m_stop_info_stop_id != process_stop_id" as the condition for + // the if statement below, we must also check the stop info to see + // if we need to override it. See the header documentation in + // Process::GetStopInfoOverrideCallback() for more information on + // the stop info override callback. + if (m_stop_info_override_stop_id != process_stop_id) { + m_stop_info_override_stop_id = process_stop_id; + if (m_stop_info_sp) { + ArchSpec::StopInfoOverrideCallbackType callback = + GetProcess()->GetStopInfoOverrideCallback(); + if (callback) + callback(*this); + } + } + } + return m_stop_info_sp; +} + +lldb::StopReason Thread::GetStopReason() { + lldb::StopInfoSP stop_info_sp(GetStopInfo()); + if (stop_info_sp) + return stop_info_sp->GetStopReason(); + return eStopReasonNone; +} + +bool Thread::StopInfoIsUpToDate() const { + ProcessSP process_sp(GetProcess()); + if (process_sp) + return m_stop_info_stop_id == process_sp->GetStopID(); + else + return true; // Process is no longer around so stop info is always up to + // date... +} + +void Thread::SetStopInfo(const lldb::StopInfoSP &stop_info_sp) { + m_stop_info_sp = stop_info_sp; + if (m_stop_info_sp) { + m_stop_info_sp->MakeStopInfoValid(); + // If we are overriding the ShouldReportStop, do that here: + if (m_override_should_notify != eLazyBoolCalculate) + m_stop_info_sp->OverrideShouldNotify(m_override_should_notify == + eLazyBoolYes); + } + + ProcessSP process_sp(GetProcess()); + if (process_sp) + m_stop_info_stop_id = process_sp->GetStopID(); + else + m_stop_info_stop_id = UINT32_MAX; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)", + static_cast<void *>(this), GetID(), + stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", + m_stop_info_stop_id); +} + +void Thread::SetShouldReportStop(Vote vote) { + if (vote == eVoteNoOpinion) + return; + else { + m_override_should_notify = (vote == eVoteYes ? eLazyBoolYes : eLazyBoolNo); + if (m_stop_info_sp) + m_stop_info_sp->OverrideShouldNotify(m_override_should_notify == + eLazyBoolYes); + } } -bool -Thread::StopInfoIsUpToDate() const -{ - ProcessSP process_sp (GetProcess()); - if (process_sp) - return m_stop_info_stop_id == process_sp->GetStopID(); - else - return true; // Process is no longer around so stop info is always up to date... +void Thread::SetStopInfoToNothing() { + // Note, we can't just NULL out the private reason, or the native thread + // implementation will try to + // go calculate it again. For now, just set it to a Unix Signal with an + // invalid signal number. + SetStopInfo( + StopInfo::CreateStopReasonWithSignal(*this, LLDB_INVALID_SIGNAL_NUMBER)); } -void -Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp) -{ - m_stop_info_sp = stop_info_sp; - if (m_stop_info_sp) - { - m_stop_info_sp->MakeStopInfoValid(); - // If we are overriding the ShouldReportStop, do that here: - if (m_override_should_notify != eLazyBoolCalculate) - m_stop_info_sp->OverrideShouldNotify (m_override_should_notify == eLazyBoolYes); - } - - ProcessSP process_sp (GetProcess()); - if (process_sp) - m_stop_info_stop_id = process_sp->GetStopID(); - else - m_stop_info_stop_id = UINT32_MAX; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf("%p: tid = 0x%" PRIx64 ": stop info = %s (stop_id = %u)", - static_cast<void*>(this), GetID(), - stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", - m_stop_info_stop_id); +bool Thread::ThreadStoppedForAReason(void) { + return (bool)GetPrivateStopInfo(); } -void -Thread::SetShouldReportStop (Vote vote) -{ - if (vote == eVoteNoOpinion) - return; - else - { - m_override_should_notify = (vote == eVoteYes ? eLazyBoolYes : eLazyBoolNo); - if (m_stop_info_sp) - m_stop_info_sp->OverrideShouldNotify (m_override_should_notify == eLazyBoolYes); +bool Thread::CheckpointThreadState(ThreadStateCheckpoint &saved_state) { + saved_state.register_backup_sp.reset(); + lldb::StackFrameSP frame_sp(GetStackFrameAtIndex(0)); + if (frame_sp) { + lldb::RegisterCheckpointSP reg_checkpoint_sp( + new RegisterCheckpoint(RegisterCheckpoint::Reason::eExpression)); + if (reg_checkpoint_sp) { + lldb::RegisterContextSP reg_ctx_sp(frame_sp->GetRegisterContext()); + if (reg_ctx_sp && reg_ctx_sp->ReadAllRegisterValues(*reg_checkpoint_sp)) + saved_state.register_backup_sp = reg_checkpoint_sp; } -} + } + if (!saved_state.register_backup_sp) + return false; -void -Thread::SetStopInfoToNothing() -{ - // Note, we can't just NULL out the private reason, or the native thread implementation will try to - // go calculate it again. For now, just set it to a Unix Signal with an invalid signal number. - SetStopInfo (StopInfo::CreateStopReasonWithSignal (*this, LLDB_INVALID_SIGNAL_NUMBER)); -} + saved_state.stop_info_sp = GetStopInfo(); + ProcessSP process_sp(GetProcess()); + if (process_sp) + saved_state.orig_stop_id = process_sp->GetStopID(); + saved_state.current_inlined_depth = GetCurrentInlinedDepth(); -bool -Thread::ThreadStoppedForAReason (void) -{ - return (bool) GetPrivateStopInfo (); + return true; } -bool -Thread::CheckpointThreadState (ThreadStateCheckpoint &saved_state) -{ - saved_state.register_backup_sp.reset(); - lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); - if (frame_sp) - { - lldb::RegisterCheckpointSP reg_checkpoint_sp(new RegisterCheckpoint(RegisterCheckpoint::Reason::eExpression)); - if (reg_checkpoint_sp) - { - lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); - if (reg_ctx_sp && reg_ctx_sp->ReadAllRegisterValues (*reg_checkpoint_sp)) - saved_state.register_backup_sp = reg_checkpoint_sp; - } - } - if (!saved_state.register_backup_sp) - return false; - - saved_state.stop_info_sp = GetStopInfo(); - ProcessSP process_sp (GetProcess()); - if (process_sp) - saved_state.orig_stop_id = process_sp->GetStopID(); - saved_state.current_inlined_depth = GetCurrentInlinedDepth(); - - return true; -} +bool Thread::RestoreRegisterStateFromCheckpoint( + ThreadStateCheckpoint &saved_state) { + if (saved_state.register_backup_sp) { + lldb::StackFrameSP frame_sp(GetStackFrameAtIndex(0)); + if (frame_sp) { + lldb::RegisterContextSP reg_ctx_sp(frame_sp->GetRegisterContext()); + if (reg_ctx_sp) { + bool ret = + reg_ctx_sp->WriteAllRegisterValues(*saved_state.register_backup_sp); -bool -Thread::RestoreRegisterStateFromCheckpoint (ThreadStateCheckpoint &saved_state) -{ - if (saved_state.register_backup_sp) - { - lldb::StackFrameSP frame_sp(GetStackFrameAtIndex (0)); - if (frame_sp) - { - lldb::RegisterContextSP reg_ctx_sp (frame_sp->GetRegisterContext()); - if (reg_ctx_sp) - { - bool ret = reg_ctx_sp->WriteAllRegisterValues (*saved_state.register_backup_sp); - - // Clear out all stack frames as our world just changed. - ClearStackFrames(); - reg_ctx_sp->InvalidateIfNeeded(true); - if (m_unwinder_ap.get()) - m_unwinder_ap->Clear(); - return ret; + // Clear out all stack frames as our world just changed. + ClearStackFrames(); + reg_ctx_sp->InvalidateIfNeeded(true); + if (m_unwinder_ap.get()) + m_unwinder_ap->Clear(); + return ret; + } + } + } + return false; +} + +bool Thread::RestoreThreadStateFromCheckpoint( + ThreadStateCheckpoint &saved_state) { + if (saved_state.stop_info_sp) + saved_state.stop_info_sp->MakeStopInfoValid(); + SetStopInfo(saved_state.stop_info_sp); + GetStackFrameList()->SetCurrentInlinedDepth( + saved_state.current_inlined_depth); + return true; +} + +StateType Thread::GetState() const { + // If any other threads access this we will need a mutex for it + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); + return m_state; +} + +void Thread::SetState(StateType state) { + std::lock_guard<std::recursive_mutex> guard(m_state_mutex); + m_state = state; +} + +void Thread::WillStop() { + ThreadPlan *current_plan = GetCurrentPlan(); + + // FIXME: I may decide to disallow threads with no plans. In which + // case this should go to an assert. + + if (!current_plan) + return; + + current_plan->WillStop(); +} + +void Thread::SetupForResume() { + if (GetResumeState() != eStateSuspended) { + // If we're at a breakpoint push the step-over breakpoint plan. Do this + // before + // telling the current plan it will resume, since we might change what the + // current + // plan is. + + lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); + if (reg_ctx_sp) { + const addr_t thread_pc = reg_ctx_sp->GetPC(); + BreakpointSiteSP bp_site_sp = + GetProcess()->GetBreakpointSiteList().FindByAddress(thread_pc); + if (bp_site_sp) { + // Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target + // may not require anything + // special to step over a breakpoint. + + ThreadPlan *cur_plan = GetCurrentPlan(); + + bool push_step_over_bp_plan = false; + if (cur_plan->GetKind() == ThreadPlan::eKindStepOverBreakpoint) { + ThreadPlanStepOverBreakpoint *bp_plan = + (ThreadPlanStepOverBreakpoint *)cur_plan; + if (bp_plan->GetBreakpointLoadAddress() != thread_pc) + push_step_over_bp_plan = true; + } else + push_step_over_bp_plan = true; + + if (push_step_over_bp_plan) { + ThreadPlanSP step_bp_plan_sp(new ThreadPlanStepOverBreakpoint(*this)); + if (step_bp_plan_sp) { + step_bp_plan_sp->SetPrivate(true); + + if (GetCurrentPlan()->RunState() != eStateStepping) { + ThreadPlanStepOverBreakpoint *step_bp_plan = + static_cast<ThreadPlanStepOverBreakpoint *>( + step_bp_plan_sp.get()); + step_bp_plan->SetAutoContinue(true); } + QueueThreadPlan(step_bp_plan_sp, false); + } } + } } - return false; + } } -bool -Thread::RestoreThreadStateFromCheckpoint (ThreadStateCheckpoint &saved_state) -{ - if (saved_state.stop_info_sp) - saved_state.stop_info_sp->MakeStopInfoValid(); - SetStopInfo(saved_state.stop_info_sp); - GetStackFrameList()->SetCurrentInlinedDepth (saved_state.current_inlined_depth); - return true; -} +bool Thread::ShouldResume(StateType resume_state) { + // At this point clear the completed plan stack. + m_completed_plan_stack.clear(); + m_discarded_plan_stack.clear(); + m_override_should_notify = eLazyBoolCalculate; -StateType -Thread::GetState() const -{ - // If any other threads access this we will need a mutex for it - std::lock_guard<std::recursive_mutex> guard(m_state_mutex); - return m_state; -} + StateType prev_resume_state = GetTemporaryResumeState(); -void -Thread::SetState(StateType state) -{ - std::lock_guard<std::recursive_mutex> guard(m_state_mutex); - m_state = state; -} + SetTemporaryResumeState(resume_state); -void -Thread::WillStop() -{ - ThreadPlan *current_plan = GetCurrentPlan(); + lldb::ThreadSP backing_thread_sp(GetBackingThread()); + if (backing_thread_sp) + backing_thread_sp->SetTemporaryResumeState(resume_state); - // FIXME: I may decide to disallow threads with no plans. In which - // case this should go to an assert. + // Make sure m_stop_info_sp is valid. Don't do this for threads we suspended + // in the previous run. + if (prev_resume_state != eStateSuspended) + GetPrivateStopInfo(); - if (!current_plan) - return; + // This is a little dubious, but we are trying to limit how often we actually + // fetch stop info from + // the target, 'cause that slows down single stepping. So assume that if we + // got to the point where + // we're about to resume, and we haven't yet had to fetch the stop reason, + // then it doesn't need to know + // about the fact that we are resuming... + const uint32_t process_stop_id = GetProcess()->GetStopID(); + if (m_stop_info_stop_id == process_stop_id && + (m_stop_info_sp && m_stop_info_sp->IsValid())) { + StopInfo *stop_info = GetPrivateStopInfo().get(); + if (stop_info) + stop_info->WillResume(resume_state); + } - current_plan->WillStop(); -} + // Tell all the plans that we are about to resume in case they need to clear + // any state. + // We distinguish between the plan on the top of the stack and the lower + // plans in case a plan needs to do any special business before it runs. -void -Thread::SetupForResume () -{ - if (GetResumeState() != eStateSuspended) - { - // If we're at a breakpoint push the step-over breakpoint plan. Do this before - // telling the current plan it will resume, since we might change what the current - // plan is. - - lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext()); - if (reg_ctx_sp) - { - const addr_t thread_pc = reg_ctx_sp->GetPC(); - BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(thread_pc); - if (bp_site_sp) - { - // Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything - // special to step over a breakpoint. - - ThreadPlan *cur_plan = GetCurrentPlan(); - - bool push_step_over_bp_plan = false; - if (cur_plan->GetKind() == ThreadPlan::eKindStepOverBreakpoint) - { - ThreadPlanStepOverBreakpoint *bp_plan = (ThreadPlanStepOverBreakpoint *)cur_plan; - if (bp_plan->GetBreakpointLoadAddress() != thread_pc) - push_step_over_bp_plan = true; - } - else - push_step_over_bp_plan = true; - - if (push_step_over_bp_plan) - { - ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this)); - if (step_bp_plan_sp) - { - step_bp_plan_sp->SetPrivate (true); - - if (GetCurrentPlan()->RunState() != eStateStepping) - { - ThreadPlanStepOverBreakpoint *step_bp_plan - = static_cast<ThreadPlanStepOverBreakpoint *>(step_bp_plan_sp.get()); - step_bp_plan->SetAutoContinue(true); - } - QueueThreadPlan (step_bp_plan_sp, false); - } - } - } - } - } -} + bool need_to_resume = false; + ThreadPlan *plan_ptr = GetCurrentPlan(); + if (plan_ptr) { + need_to_resume = plan_ptr->WillResume(resume_state, true); -bool -Thread::ShouldResume (StateType resume_state) -{ - // At this point clear the completed plan stack. - m_completed_plan_stack.clear(); - m_discarded_plan_stack.clear(); - m_override_should_notify = eLazyBoolCalculate; - - StateType prev_resume_state = GetTemporaryResumeState(); - - SetTemporaryResumeState(resume_state); - - lldb::ThreadSP backing_thread_sp (GetBackingThread ()); - if (backing_thread_sp) - backing_thread_sp->SetTemporaryResumeState(resume_state); - - // Make sure m_stop_info_sp is valid. Don't do this for threads we suspended in the previous run. - if (prev_resume_state != eStateSuspended) - GetPrivateStopInfo(); - - // This is a little dubious, but we are trying to limit how often we actually fetch stop info from - // the target, 'cause that slows down single stepping. So assume that if we got to the point where - // we're about to resume, and we haven't yet had to fetch the stop reason, then it doesn't need to know - // about the fact that we are resuming... - const uint32_t process_stop_id = GetProcess()->GetStopID(); - if (m_stop_info_stop_id == process_stop_id && - (m_stop_info_sp && m_stop_info_sp->IsValid())) - { - StopInfo *stop_info = GetPrivateStopInfo().get(); - if (stop_info) - stop_info->WillResume (resume_state); + while ((plan_ptr = GetPreviousPlan(plan_ptr)) != nullptr) { + plan_ptr->WillResume(resume_state, false); } - - // Tell all the plans that we are about to resume in case they need to clear any state. - // We distinguish between the plan on the top of the stack and the lower - // plans in case a plan needs to do any special business before it runs. - - bool need_to_resume = false; - ThreadPlan *plan_ptr = GetCurrentPlan(); - if (plan_ptr) - { - need_to_resume = plan_ptr->WillResume(resume_state, true); - while ((plan_ptr = GetPreviousPlan(plan_ptr)) != nullptr) - { - plan_ptr->WillResume (resume_state, false); - } - - // If the WillResume for the plan says we are faking a resume, then it will have set an appropriate stop info. - // In that case, don't reset it here. - - if (need_to_resume && resume_state != eStateSuspended) - { - m_stop_info_sp.reset(); - } - } + // If the WillResume for the plan says we are faking a resume, then it will + // have set an appropriate stop info. + // In that case, don't reset it here. - if (need_to_resume) - { - ClearStackFrames(); - // Let Thread subclasses do any special work they need to prior to resuming - WillResume (resume_state); + if (need_to_resume && resume_state != eStateSuspended) { + m_stop_info_sp.reset(); } + } - return need_to_resume; -} + if (need_to_resume) { + ClearStackFrames(); + // Let Thread subclasses do any special work they need to prior to resuming + WillResume(resume_state); + } -void -Thread::DidResume () -{ - SetResumeSignal (LLDB_INVALID_SIGNAL_NUMBER); + return need_to_resume; } -void -Thread::DidStop () -{ - SetState (eStateStopped); -} +void Thread::DidResume() { SetResumeSignal(LLDB_INVALID_SIGNAL_NUMBER); } -bool -Thread::ShouldStop (Event* event_ptr) -{ - ThreadPlan *current_plan = GetCurrentPlan(); +void Thread::DidStop() { SetState(eStateStopped); } - bool should_stop = true; +bool Thread::ShouldStop(Event *event_ptr) { + ThreadPlan *current_plan = GetCurrentPlan(); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + bool should_stop = true; - if (GetResumeState () == eStateSuspended) - { - if (log) - log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)", - __FUNCTION__, GetID (), GetProtocolID()); - return false; - } - - if (GetTemporaryResumeState () == eStateSuspended) - { - if (log) - log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", should_stop = 0 (ignore since thread was suspended)", - __FUNCTION__, GetID (), GetProtocolID()); - return false; - } + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - // Based on the current thread plan and process stop info, check if this - // thread caused the process to stop. NOTE: this must take place before - // the plan is moved from the current plan stack to the completed plan - // stack. - if (!ThreadStoppedForAReason()) - { - if (log) - log->Printf ("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64 ", should_stop = 0 (ignore since no stop reason)", - __FUNCTION__, GetID (), GetProtocolID(), - GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS); - return false; - } + if (GetResumeState() == eStateSuspended) { + if (log) + log->Printf("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 + ", should_stop = 0 (ignore since thread was suspended)", + __FUNCTION__, GetID(), GetProtocolID()); + return false; + } + if (GetTemporaryResumeState() == eStateSuspended) { if (log) - { - log->Printf ("Thread::%s(%p) for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 ", pc = 0x%16.16" PRIx64, - __FUNCTION__, static_cast<void*>(this), GetID (), - GetProtocolID (), - GetRegisterContext() - ? GetRegisterContext()->GetPC() - : LLDB_INVALID_ADDRESS); - log->Printf ("^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^"); - StreamString s; - s.IndentMore(); - DumpThreadPlans(&s); - log->Printf ("Plan stack initial state:\n%s", s.GetData()); - } + log->Printf("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 + ", should_stop = 0 (ignore since thread was suspended)", + __FUNCTION__, GetID(), GetProtocolID()); + return false; + } - // The top most plan always gets to do the trace log... - current_plan->DoTraceLog (); + // Based on the current thread plan and process stop info, check if this + // thread caused the process to stop. NOTE: this must take place before + // the plan is moved from the current plan stack to the completed plan + // stack. + if (!ThreadStoppedForAReason()) { + if (log) + log->Printf("Thread::%s for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 + ", pc = 0x%16.16" PRIx64 + ", should_stop = 0 (ignore since no stop reason)", + __FUNCTION__, GetID(), GetProtocolID(), + GetRegisterContext() ? GetRegisterContext()->GetPC() + : LLDB_INVALID_ADDRESS); + return false; + } + + if (log) { + log->Printf("Thread::%s(%p) for tid = 0x%4.4" PRIx64 " 0x%4.4" PRIx64 + ", pc = 0x%16.16" PRIx64, + __FUNCTION__, static_cast<void *>(this), GetID(), + GetProtocolID(), + GetRegisterContext() ? GetRegisterContext()->GetPC() + : LLDB_INVALID_ADDRESS); + log->Printf("^^^^^^^^ Thread::ShouldStop Begin ^^^^^^^^"); + StreamString s; + s.IndentMore(); + DumpThreadPlans(&s); + log->Printf("Plan stack initial state:\n%s", s.GetData()); + } + + // The top most plan always gets to do the trace log... + current_plan->DoTraceLog(); + + // First query the stop info's ShouldStopSynchronous. This handles + // "synchronous" stop reasons, for example the breakpoint + // command on internal breakpoints. If a synchronous stop reason says we + // should not stop, then we don't have to + // do any more work on this stop. + StopInfoSP private_stop_info(GetPrivateStopInfo()); + if (private_stop_info && + !private_stop_info->ShouldStopSynchronous(event_ptr)) { + if (log) + log->Printf("StopInfo::ShouldStop async callback says we should not " + "stop, returning ShouldStop of false."); + return false; + } - // First query the stop info's ShouldStopSynchronous. This handles "synchronous" stop reasons, for example the breakpoint - // command on internal breakpoints. If a synchronous stop reason says we should not stop, then we don't have to - // do any more work on this stop. - StopInfoSP private_stop_info (GetPrivateStopInfo()); - if (private_stop_info && !private_stop_info->ShouldStopSynchronous(event_ptr)) - { - if (log) - log->Printf ("StopInfo::ShouldStop async callback says we should not stop, returning ShouldStop of false."); - return false; - } + // If we've already been restarted, don't query the plans since the state they + // would examine is not current. + if (Process::ProcessEventData::GetRestartedFromEvent(event_ptr)) + return false; - // If we've already been restarted, don't query the plans since the state they would examine is not current. - if (Process::ProcessEventData::GetRestartedFromEvent(event_ptr)) - return false; - - // Before the plans see the state of the world, calculate the current inlined depth. - GetStackFrameList()->CalculateCurrentInlinedDepth(); - - // If the base plan doesn't understand why we stopped, then we have to find a plan that does. - // If that plan is still working, then we don't need to do any more work. If the plan that explains - // the stop is done, then we should pop all the plans below it, and pop it, and then let the plans above it decide - // whether they still need to do more work. - - bool done_processing_current_plan = false; - - if (!current_plan->PlanExplainsStop(event_ptr)) - { - if (current_plan->TracerExplainsStop()) - { + // Before the plans see the state of the world, calculate the current inlined + // depth. + GetStackFrameList()->CalculateCurrentInlinedDepth(); + + // If the base plan doesn't understand why we stopped, then we have to find a + // plan that does. + // If that plan is still working, then we don't need to do any more work. If + // the plan that explains + // the stop is done, then we should pop all the plans below it, and pop it, + // and then let the plans above it decide + // whether they still need to do more work. + + bool done_processing_current_plan = false; + + if (!current_plan->PlanExplainsStop(event_ptr)) { + if (current_plan->TracerExplainsStop()) { + done_processing_current_plan = true; + should_stop = false; + } else { + // If the current plan doesn't explain the stop, then find one that + // does and let it handle the situation. + ThreadPlan *plan_ptr = current_plan; + while ((plan_ptr = GetPreviousPlan(plan_ptr)) != nullptr) { + if (plan_ptr->PlanExplainsStop(event_ptr)) { + should_stop = plan_ptr->ShouldStop(event_ptr); + + // plan_ptr explains the stop, next check whether plan_ptr is done, if + // so, then we should take it + // and all the plans below it off the stack. + + if (plan_ptr->MischiefManaged()) { + // We're going to pop the plans up to and including the plan that + // explains the stop. + ThreadPlan *prev_plan_ptr = GetPreviousPlan(plan_ptr); + + do { + if (should_stop) + current_plan->WillStop(); + PopPlan(); + } while ((current_plan = GetCurrentPlan()) != prev_plan_ptr); + // Now, if the responsible plan was not "Okay to discard" then we're + // done, + // otherwise we forward this to the next plan in the stack below. + done_processing_current_plan = + (plan_ptr->IsMasterPlan() && !plan_ptr->OkayToDiscard()); + } else done_processing_current_plan = true; - should_stop = false; - } - else - { - // If the current plan doesn't explain the stop, then find one that - // does and let it handle the situation. - ThreadPlan *plan_ptr = current_plan; - while ((plan_ptr = GetPreviousPlan(plan_ptr)) != nullptr) - { - if (plan_ptr->PlanExplainsStop(event_ptr)) - { - should_stop = plan_ptr->ShouldStop (event_ptr); - - // plan_ptr explains the stop, next check whether plan_ptr is done, if so, then we should take it - // and all the plans below it off the stack. - - if (plan_ptr->MischiefManaged()) - { - // We're going to pop the plans up to and including the plan that explains the stop. - ThreadPlan *prev_plan_ptr = GetPreviousPlan (plan_ptr); - - do - { - if (should_stop) - current_plan->WillStop(); - PopPlan(); - } - while ((current_plan = GetCurrentPlan()) != prev_plan_ptr); - // Now, if the responsible plan was not "Okay to discard" then we're done, - // otherwise we forward this to the next plan in the stack below. - done_processing_current_plan = (plan_ptr->IsMasterPlan() && !plan_ptr->OkayToDiscard()); - } - else - done_processing_current_plan = true; - - break; - } - } + + break; } + } } + } - if (!done_processing_current_plan) - { - bool over_ride_stop = current_plan->ShouldAutoContinue(event_ptr); + if (!done_processing_current_plan) { + bool over_ride_stop = current_plan->ShouldAutoContinue(event_ptr); - if (log) - log->Printf("Plan %s explains stop, auto-continue %i.", - current_plan->GetName(), over_ride_stop); - - // We're starting from the base plan, so just let it decide; + if (log) + log->Printf("Plan %s explains stop, auto-continue %i.", + current_plan->GetName(), over_ride_stop); + + // We're starting from the base plan, so just let it decide; + if (PlanIsBasePlan(current_plan)) { + should_stop = current_plan->ShouldStop(event_ptr); + if (log) + log->Printf("Base plan says should stop: %i.", should_stop); + } else { + // Otherwise, don't let the base plan override what the other plans say to + // do, since + // presumably if there were other plans they would know what to do... + while (1) { if (PlanIsBasePlan(current_plan)) - { - should_stop = current_plan->ShouldStop (event_ptr); - if (log) - log->Printf("Base plan says should stop: %i.", should_stop); - } - else - { - // Otherwise, don't let the base plan override what the other plans say to do, since - // presumably if there were other plans they would know what to do... - while (1) - { - if (PlanIsBasePlan(current_plan)) - break; - - should_stop = current_plan->ShouldStop(event_ptr); - if (log) - log->Printf("Plan %s should stop: %d.", - current_plan->GetName(), should_stop); - if (current_plan->MischiefManaged()) - { - if (should_stop) - current_plan->WillStop(); - - // If a Master Plan wants to stop, and wants to stick on the stack, we let it. - // Otherwise, see if the plan's parent wants to stop. - - if (should_stop && current_plan->IsMasterPlan() && !current_plan->OkayToDiscard()) - { - PopPlan(); - break; - } - else - { - PopPlan(); - - current_plan = GetCurrentPlan(); - if (current_plan == nullptr) - { - break; - } - } - } - else - { - break; - } - } - } - - if (over_ride_stop) - should_stop = false; - } + break; - // One other potential problem is that we set up a master plan, then stop in before it is complete - for instance - // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up - // past the end point condition of the initial plan. We don't want to strand the original plan on the stack, - // This code clears stale plans off the stack. + should_stop = current_plan->ShouldStop(event_ptr); + if (log) + log->Printf("Plan %s should stop: %d.", current_plan->GetName(), + should_stop); + if (current_plan->MischiefManaged()) { + if (should_stop) + current_plan->WillStop(); + + // If a Master Plan wants to stop, and wants to stick on the stack, we + // let it. + // Otherwise, see if the plan's parent wants to stop. + + if (should_stop && current_plan->IsMasterPlan() && + !current_plan->OkayToDiscard()) { + PopPlan(); + break; + } else { + PopPlan(); - if (should_stop) - { - ThreadPlan *plan_ptr = GetCurrentPlan(); - while (!PlanIsBasePlan(plan_ptr)) - { - bool stale = plan_ptr->IsPlanStale (); - ThreadPlan *examined_plan = plan_ptr; - plan_ptr = GetPreviousPlan (examined_plan); - - if (stale) - { - if (log) - log->Printf("Plan %s being discarded in cleanup, it says it is already done.", - examined_plan->GetName()); - DiscardThreadPlansUpToPlan(examined_plan); + current_plan = GetCurrentPlan(); + if (current_plan == nullptr) { + break; } + } + } else { + break; } + } } - if (log) - { - StreamString s; - s.IndentMore(); - DumpThreadPlans(&s); - log->Printf ("Plan stack final state:\n%s", s.GetData()); - log->Printf ("vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv", should_stop); - } - return should_stop; -} + if (over_ride_stop) + should_stop = false; + } -Vote -Thread::ShouldReportStop (Event* event_ptr) -{ - StateType thread_state = GetResumeState (); - StateType temp_thread_state = GetTemporaryResumeState(); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + // One other potential problem is that we set up a master plan, then stop in + // before it is complete - for instance + // by hitting a breakpoint during a step-over - then do some step/finish/etc + // operations that wind up + // past the end point condition of the initial plan. We don't want to strand + // the original plan on the stack, + // This code clears stale plans off the stack. - if (thread_state == eStateSuspended || thread_state == eStateInvalid) - { - if (log) - log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i (state was suspended or invalid)", GetID(), eVoteNoOpinion); - return eVoteNoOpinion; - } + if (should_stop) { + ThreadPlan *plan_ptr = GetCurrentPlan(); + while (!PlanIsBasePlan(plan_ptr)) { + bool stale = plan_ptr->IsPlanStale(); + ThreadPlan *examined_plan = plan_ptr; + plan_ptr = GetPreviousPlan(examined_plan); - if (temp_thread_state == eStateSuspended || temp_thread_state == eStateInvalid) - { + if (stale) { if (log) - log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i (temporary state was suspended or invalid)", GetID(), eVoteNoOpinion); - return eVoteNoOpinion; + log->Printf( + "Plan %s being discarded in cleanup, it says it is already done.", + examined_plan->GetName()); + DiscardThreadPlansUpToPlan(examined_plan); + } } + } - if (!ThreadStoppedForAReason()) - { - if (log) - log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i (thread didn't stop for a reason.)", GetID(), eVoteNoOpinion); - return eVoteNoOpinion; - } + if (log) { + StreamString s; + s.IndentMore(); + DumpThreadPlans(&s); + log->Printf("Plan stack final state:\n%s", s.GetData()); + log->Printf("vvvvvvvv Thread::ShouldStop End (returning %i) vvvvvvvv", + should_stop); + } + return should_stop; +} - if (m_completed_plan_stack.size() > 0) - { - // Don't use GetCompletedPlan here, since that suppresses private plans. - if (log) - log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote for complete stack's back plan", GetID()); - return m_completed_plan_stack.back()->ShouldReportStop (event_ptr); - } - else - { - Vote thread_vote = eVoteNoOpinion; - ThreadPlan *plan_ptr = GetCurrentPlan(); - while (1) - { - if (plan_ptr->PlanExplainsStop(event_ptr)) - { - thread_vote = plan_ptr->ShouldReportStop(event_ptr); - break; - } - if (PlanIsBasePlan(plan_ptr)) - break; - else - plan_ptr = GetPreviousPlan(plan_ptr); - } - if (log) - log->Printf ("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 ": returning vote %i for current plan", GetID(), thread_vote); +Vote Thread::ShouldReportStop(Event *event_ptr) { + StateType thread_state = GetResumeState(); + StateType temp_thread_state = GetTemporaryResumeState(); - return thread_vote; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (thread_state == eStateSuspended || thread_state == eStateInvalid) { + if (log) + log->Printf("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 + ": returning vote %i (state was suspended or invalid)", + GetID(), eVoteNoOpinion); + return eVoteNoOpinion; + } + + if (temp_thread_state == eStateSuspended || + temp_thread_state == eStateInvalid) { + if (log) + log->Printf( + "Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 + ": returning vote %i (temporary state was suspended or invalid)", + GetID(), eVoteNoOpinion); + return eVoteNoOpinion; + } + + if (!ThreadStoppedForAReason()) { + if (log) + log->Printf("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 + ": returning vote %i (thread didn't stop for a reason.)", + GetID(), eVoteNoOpinion); + return eVoteNoOpinion; + } + + if (m_completed_plan_stack.size() > 0) { + // Don't use GetCompletedPlan here, since that suppresses private plans. + if (log) + log->Printf("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 + ": returning vote for complete stack's back plan", + GetID()); + return m_completed_plan_stack.back()->ShouldReportStop(event_ptr); + } else { + Vote thread_vote = eVoteNoOpinion; + ThreadPlan *plan_ptr = GetCurrentPlan(); + while (1) { + if (plan_ptr->PlanExplainsStop(event_ptr)) { + thread_vote = plan_ptr->ShouldReportStop(event_ptr); + break; + } + if (PlanIsBasePlan(plan_ptr)) + break; + else + plan_ptr = GetPreviousPlan(plan_ptr); } -} + if (log) + log->Printf("Thread::ShouldReportStop() tid = 0x%4.4" PRIx64 + ": returning vote %i for current plan", + GetID(), thread_vote); -Vote -Thread::ShouldReportRun (Event* event_ptr) -{ - StateType thread_state = GetResumeState (); + return thread_vote; + } +} - if (thread_state == eStateSuspended - || thread_state == eStateInvalid) - { - return eVoteNoOpinion; - } +Vote Thread::ShouldReportRun(Event *event_ptr) { + StateType thread_state = GetResumeState(); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (m_completed_plan_stack.size() > 0) - { - // Don't use GetCompletedPlan here, since that suppresses private plans. - if (log) - log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.", - GetIndexID(), static_cast<void*>(this), GetID(), - StateAsCString(GetTemporaryResumeState()), - m_completed_plan_stack.back()->GetName()); + if (thread_state == eStateSuspended || thread_state == eStateInvalid) { + return eVoteNoOpinion; + } - return m_completed_plan_stack.back()->ShouldReportRun (event_ptr); - } - else - { - if (log) - log->Printf ("Current Plan for thread %d(%p) (0x%4.4" PRIx64 ", %s): %s being asked whether we should report run.", - GetIndexID(), static_cast<void*>(this), GetID(), - StateAsCString(GetTemporaryResumeState()), - GetCurrentPlan()->GetName()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (m_completed_plan_stack.size() > 0) { + // Don't use GetCompletedPlan here, since that suppresses private plans. + if (log) + log->Printf("Current Plan for thread %d(%p) (0x%4.4" PRIx64 + ", %s): %s being asked whether we should report run.", + GetIndexID(), static_cast<void *>(this), GetID(), + StateAsCString(GetTemporaryResumeState()), + m_completed_plan_stack.back()->GetName()); + + return m_completed_plan_stack.back()->ShouldReportRun(event_ptr); + } else { + if (log) + log->Printf("Current Plan for thread %d(%p) (0x%4.4" PRIx64 + ", %s): %s being asked whether we should report run.", + GetIndexID(), static_cast<void *>(this), GetID(), + StateAsCString(GetTemporaryResumeState()), + GetCurrentPlan()->GetName()); - return GetCurrentPlan()->ShouldReportRun (event_ptr); - } + return GetCurrentPlan()->ShouldReportRun(event_ptr); + } } -bool -Thread::MatchesSpec (const ThreadSpec *spec) -{ - return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(*this); +bool Thread::MatchesSpec(const ThreadSpec *spec) { + return (spec == nullptr) ? true : spec->ThreadPassesBasicTests(*this); } -void -Thread::PushPlan (ThreadPlanSP &thread_plan_sp) -{ - if (thread_plan_sp) - { - // If the thread plan doesn't already have a tracer, give it its parent's tracer: - if (!thread_plan_sp->GetThreadPlanTracer()) - thread_plan_sp->SetThreadPlanTracer(m_plan_stack.back()->GetThreadPlanTracer()); - m_plan_stack.push_back (thread_plan_sp); +void Thread::PushPlan(ThreadPlanSP &thread_plan_sp) { + if (thread_plan_sp) { + // If the thread plan doesn't already have a tracer, give it its parent's + // tracer: + if (!thread_plan_sp->GetThreadPlanTracer()) + thread_plan_sp->SetThreadPlanTracer( + m_plan_stack.back()->GetThreadPlanTracer()); + m_plan_stack.push_back(thread_plan_sp); - thread_plan_sp->DidPush(); + thread_plan_sp->DidPush(); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - { - StreamString s; - thread_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull); - log->Printf("Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", - static_cast<void*>(this), s.GetData(), - thread_plan_sp->GetThread().GetID()); - } + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + StreamString s; + thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); + log->Printf("Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".", + static_cast<void *>(this), s.GetData(), + thread_plan_sp->GetThread().GetID()); } + } } -void -Thread::PopPlan () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +void Thread::PopPlan() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_plan_stack.size() <= 1) - return; - else - { - ThreadPlanSP &plan = m_plan_stack.back(); - if (log) - { - log->Printf("Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", plan->GetName(), plan->GetThread().GetID()); - } - m_completed_plan_stack.push_back (plan); - plan->WillPop(); - m_plan_stack.pop_back(); + if (m_plan_stack.size() <= 1) + return; + else { + ThreadPlanSP &plan = m_plan_stack.back(); + if (log) { + log->Printf("Popping plan: \"%s\", tid = 0x%4.4" PRIx64 ".", + plan->GetName(), plan->GetThread().GetID()); } + m_completed_plan_stack.push_back(plan); + plan->WillPop(); + m_plan_stack.pop_back(); + } } -void -Thread::DiscardPlan () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (m_plan_stack.size() > 1) - { - ThreadPlanSP &plan = m_plan_stack.back(); - if (log) - log->Printf("Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", plan->GetName(), plan->GetThread().GetID()); +void Thread::DiscardPlan() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (m_plan_stack.size() > 1) { + ThreadPlanSP &plan = m_plan_stack.back(); + if (log) + log->Printf("Discarding plan: \"%s\", tid = 0x%4.4" PRIx64 ".", + plan->GetName(), plan->GetThread().GetID()); - m_discarded_plan_stack.push_back (plan); - plan->WillPop(); - m_plan_stack.pop_back(); - } + m_discarded_plan_stack.push_back(plan); + plan->WillPop(); + m_plan_stack.pop_back(); + } } -ThreadPlan * -Thread::GetCurrentPlan () -{ - // There will always be at least the base plan. If somebody is mucking with a - // thread with an empty plan stack, we should assert right away. - return m_plan_stack.empty() ? nullptr : m_plan_stack.back().get(); +ThreadPlan *Thread::GetCurrentPlan() { + // There will always be at least the base plan. If somebody is mucking with a + // thread with an empty plan stack, we should assert right away. + return m_plan_stack.empty() ? nullptr : m_plan_stack.back().get(); } -ThreadPlanSP -Thread::GetCompletedPlan () -{ - ThreadPlanSP empty_plan_sp; - if (!m_completed_plan_stack.empty()) - { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) - { - ThreadPlanSP completed_plan_sp; - completed_plan_sp = m_completed_plan_stack[i]; - if (!completed_plan_sp->GetPrivate ()) - return completed_plan_sp; - } +ThreadPlanSP Thread::GetCompletedPlan() { + ThreadPlanSP empty_plan_sp; + if (!m_completed_plan_stack.empty()) { + for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { + ThreadPlanSP completed_plan_sp; + completed_plan_sp = m_completed_plan_stack[i]; + if (!completed_plan_sp->GetPrivate()) + return completed_plan_sp; } - return empty_plan_sp; + } + return empty_plan_sp; } -ValueObjectSP -Thread::GetReturnValueObject () -{ - if (!m_completed_plan_stack.empty()) - { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) - { - ValueObjectSP return_valobj_sp; - return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject(); - if (return_valobj_sp) - return return_valobj_sp; - } +ValueObjectSP Thread::GetReturnValueObject() { + if (!m_completed_plan_stack.empty()) { + for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { + ValueObjectSP return_valobj_sp; + return_valobj_sp = m_completed_plan_stack[i]->GetReturnValueObject(); + if (return_valobj_sp) + return return_valobj_sp; } - return ValueObjectSP(); + } + return ValueObjectSP(); } -ExpressionVariableSP -Thread::GetExpressionVariable () -{ - if (!m_completed_plan_stack.empty()) - { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) - { - ExpressionVariableSP expression_variable_sp; - expression_variable_sp = m_completed_plan_stack[i]->GetExpressionVariable(); - if (expression_variable_sp) - return expression_variable_sp; - } +ExpressionVariableSP Thread::GetExpressionVariable() { + if (!m_completed_plan_stack.empty()) { + for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { + ExpressionVariableSP expression_variable_sp; + expression_variable_sp = + m_completed_plan_stack[i]->GetExpressionVariable(); + if (expression_variable_sp) + return expression_variable_sp; } - return ExpressionVariableSP(); + } + return ExpressionVariableSP(); } -bool -Thread::IsThreadPlanDone (ThreadPlan *plan) -{ - if (!m_completed_plan_stack.empty()) - { - for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) - { - if (m_completed_plan_stack[i].get() == plan) - return true; - } +bool Thread::IsThreadPlanDone(ThreadPlan *plan) { + if (!m_completed_plan_stack.empty()) { + for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--) { + if (m_completed_plan_stack[i].get() == plan) + return true; } - return false; + } + return false; } -bool -Thread::WasThreadPlanDiscarded (ThreadPlan *plan) -{ - if (!m_discarded_plan_stack.empty()) - { - for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--) - { - if (m_discarded_plan_stack[i].get() == plan) - return true; - } +bool Thread::WasThreadPlanDiscarded(ThreadPlan *plan) { + if (!m_discarded_plan_stack.empty()) { + for (int i = m_discarded_plan_stack.size() - 1; i >= 0; i--) { + if (m_discarded_plan_stack[i].get() == plan) + return true; } - return false; + } + return false; } -ThreadPlan * -Thread::GetPreviousPlan (ThreadPlan *current_plan) -{ - if (current_plan == nullptr) - return nullptr; +ThreadPlan *Thread::GetPreviousPlan(ThreadPlan *current_plan) { + if (current_plan == nullptr) + return nullptr; - int stack_size = m_completed_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) - { - if (current_plan == m_completed_plan_stack[i].get()) - return m_completed_plan_stack[i-1].get(); - } + int stack_size = m_completed_plan_stack.size(); + for (int i = stack_size - 1; i > 0; i--) { + if (current_plan == m_completed_plan_stack[i].get()) + return m_completed_plan_stack[i - 1].get(); + } - if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan) - { - return GetCurrentPlan(); - } + if (stack_size > 0 && m_completed_plan_stack[0].get() == current_plan) { + return GetCurrentPlan(); + } - stack_size = m_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) - { - if (current_plan == m_plan_stack[i].get()) - return m_plan_stack[i-1].get(); - } - return nullptr; + stack_size = m_plan_stack.size(); + for (int i = stack_size - 1; i > 0; i--) { + if (current_plan == m_plan_stack[i].get()) + return m_plan_stack[i - 1].get(); + } + return nullptr; } -void -Thread::QueueThreadPlan (ThreadPlanSP &thread_plan_sp, bool abort_other_plans) -{ - if (abort_other_plans) - DiscardThreadPlans(true); +void Thread::QueueThreadPlan(ThreadPlanSP &thread_plan_sp, + bool abort_other_plans) { + if (abort_other_plans) + DiscardThreadPlans(true); - PushPlan (thread_plan_sp); + PushPlan(thread_plan_sp); } -void -Thread::EnableTracer (bool value, bool single_stepping) -{ - int stack_size = m_plan_stack.size(); - for (int i = 0; i < stack_size; i++) - { - if (m_plan_stack[i]->GetThreadPlanTracer()) - { - m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value); - m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping); - } +void Thread::EnableTracer(bool value, bool single_stepping) { + int stack_size = m_plan_stack.size(); + for (int i = 0; i < stack_size; i++) { + if (m_plan_stack[i]->GetThreadPlanTracer()) { + m_plan_stack[i]->GetThreadPlanTracer()->EnableTracing(value); + m_plan_stack[i]->GetThreadPlanTracer()->EnableSingleStep(single_stepping); } + } } -void -Thread::SetTracer (lldb::ThreadPlanTracerSP &tracer_sp) -{ - int stack_size = m_plan_stack.size(); - for (int i = 0; i < stack_size; i++) - m_plan_stack[i]->SetThreadPlanTracer(tracer_sp); +void Thread::SetTracer(lldb::ThreadPlanTracerSP &tracer_sp) { + int stack_size = m_plan_stack.size(); + for (int i = 0; i < stack_size; i++) + m_plan_stack[i]->SetThreadPlanTracer(tracer_sp); } -bool -Thread::DiscardUserThreadPlansUpToIndex (uint32_t thread_index) -{ - // Count the user thread plans from the back end to get the number of the one we want - // to discard: +bool Thread::DiscardUserThreadPlansUpToIndex(uint32_t thread_index) { + // Count the user thread plans from the back end to get the number of the one + // we want + // to discard: - uint32_t idx = 0; - ThreadPlan *up_to_plan_ptr = nullptr; + uint32_t idx = 0; + ThreadPlan *up_to_plan_ptr = nullptr; - for (ThreadPlanSP plan_sp : m_plan_stack) - { - if (plan_sp->GetPrivate()) - continue; - if (idx == thread_index) - { - up_to_plan_ptr = plan_sp.get(); - break; - } - else - idx++; - } + for (ThreadPlanSP plan_sp : m_plan_stack) { + if (plan_sp->GetPrivate()) + continue; + if (idx == thread_index) { + up_to_plan_ptr = plan_sp.get(); + break; + } else + idx++; + } - if (up_to_plan_ptr == nullptr) - return false; + if (up_to_plan_ptr == nullptr) + return false; - DiscardThreadPlansUpToPlan(up_to_plan_ptr); - return true; + DiscardThreadPlansUpToPlan(up_to_plan_ptr); + return true; } -void -Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp) -{ - DiscardThreadPlansUpToPlan (up_to_plan_sp.get()); +void Thread::DiscardThreadPlansUpToPlan(lldb::ThreadPlanSP &up_to_plan_sp) { + DiscardThreadPlansUpToPlan(up_to_plan_sp.get()); } -void -Thread::DiscardThreadPlansUpToPlan (ThreadPlan *up_to_plan_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 ", up to %p", - GetID(), static_cast<void*>(up_to_plan_ptr)); +void Thread::DiscardThreadPlansUpToPlan(ThreadPlan *up_to_plan_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Discarding thread plans for thread tid = 0x%4.4" PRIx64 + ", up to %p", + GetID(), static_cast<void *>(up_to_plan_ptr)); - int stack_size = m_plan_stack.size(); + int stack_size = m_plan_stack.size(); - // If the input plan is nullptr, discard all plans. Otherwise make sure this plan is in the - // stack, and if so discard up to and including it. + // If the input plan is nullptr, discard all plans. Otherwise make sure this + // plan is in the + // stack, and if so discard up to and including it. - if (up_to_plan_ptr == nullptr) - { - for (int i = stack_size - 1; i > 0; i--) - DiscardPlan(); - } - else - { - bool found_it = false; - for (int i = stack_size - 1; i > 0; i--) - { - if (m_plan_stack[i].get() == up_to_plan_ptr) - found_it = true; - } - if (found_it) - { - bool last_one = false; - for (int i = stack_size - 1; i > 0 && !last_one ; i--) - { - if (GetCurrentPlan() == up_to_plan_ptr) - last_one = true; - DiscardPlan(); - } - } - } + if (up_to_plan_ptr == nullptr) { + for (int i = stack_size - 1; i > 0; i--) + DiscardPlan(); + } else { + bool found_it = false; + for (int i = stack_size - 1; i > 0; i--) { + if (m_plan_stack[i].get() == up_to_plan_ptr) + found_it = true; + } + if (found_it) { + bool last_one = false; + for (int i = stack_size - 1; i > 0 && !last_one; i--) { + if (GetCurrentPlan() == up_to_plan_ptr) + last_one = true; + DiscardPlan(); + } + } + } +} + +void Thread::DiscardThreadPlans(bool force) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + log->Printf("Discarding thread plans for thread (tid = 0x%4.4" PRIx64 + ", force %d)", + GetID(), force); + } + + if (force) { + int stack_size = m_plan_stack.size(); + for (int i = stack_size - 1; i > 0; i--) { + DiscardPlan(); + } + return; + } + + while (1) { + int master_plan_idx; + bool discard = true; + + // Find the first master plan, see if it wants discarding, and if yes + // discard up to it. + for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0; + master_plan_idx--) { + if (m_plan_stack[master_plan_idx]->IsMasterPlan()) { + discard = m_plan_stack[master_plan_idx]->OkayToDiscard(); + break; + } + } + + if (discard) { + // First pop all the dependent plans: + for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--) { + // FIXME: Do we need a finalize here, or is the rule that + // "PrepareForStop" + // for the plan leaves it in a state that it is safe to pop the plan + // with no more notice? + DiscardPlan(); + } + + // Now discard the master plan itself. + // The bottom-most plan never gets discarded. "OkayToDiscard" for it + // means + // discard it's dependent plans, but not it... + if (master_plan_idx > 0) { + DiscardPlan(); + } + } else { + // If the master plan doesn't want to get discarded, then we're done. + break; + } + } +} + +bool Thread::PlanIsBasePlan(ThreadPlan *plan_ptr) { + if (plan_ptr->IsBasePlan()) + return true; + else if (m_plan_stack.size() == 0) + return false; + else + return m_plan_stack[0].get() == plan_ptr; } -void -Thread::DiscardThreadPlans(bool force) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - { - log->Printf("Discarding thread plans for thread (tid = 0x%4.4" PRIx64 ", force %d)", GetID(), force); - } - - if (force) - { - int stack_size = m_plan_stack.size(); - for (int i = stack_size - 1; i > 0; i--) - { - DiscardPlan(); - } - return; - } +Error Thread::UnwindInnermostExpression() { + Error error; + int stack_size = m_plan_stack.size(); - while (1) - { - int master_plan_idx; - bool discard = true; - - // Find the first master plan, see if it wants discarding, and if yes discard up to it. - for (master_plan_idx = m_plan_stack.size() - 1; master_plan_idx >= 0; master_plan_idx--) - { - if (m_plan_stack[master_plan_idx]->IsMasterPlan()) - { - discard = m_plan_stack[master_plan_idx]->OkayToDiscard(); - break; - } - } + // If the input plan is nullptr, discard all plans. Otherwise make sure this + // plan is in the + // stack, and if so discard up to and including it. - if (discard) - { - // First pop all the dependent plans: - for (int i = m_plan_stack.size() - 1; i > master_plan_idx; i--) - { - // FIXME: Do we need a finalize here, or is the rule that "PrepareForStop" - // for the plan leaves it in a state that it is safe to pop the plan - // with no more notice? - DiscardPlan(); - } - - // Now discard the master plan itself. - // The bottom-most plan never gets discarded. "OkayToDiscard" for it means - // discard it's dependent plans, but not it... - if (master_plan_idx > 0) - { - DiscardPlan(); - } - } - else - { - // If the master plan doesn't want to get discarded, then we're done. - break; - } + for (int i = stack_size - 1; i > 0; i--) { + if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction) { + DiscardThreadPlansUpToPlan(m_plan_stack[i].get()); + return error; } + } + error.SetErrorString("No expressions currently active on this thread"); + return error; } -bool -Thread::PlanIsBasePlan (ThreadPlan *plan_ptr) -{ - if (plan_ptr->IsBasePlan()) - return true; - else if (m_plan_stack.size() == 0) - return false; - else - return m_plan_stack[0].get() == plan_ptr; -} - -Error -Thread::UnwindInnermostExpression() -{ - Error error; - int stack_size = m_plan_stack.size(); - - // If the input plan is nullptr, discard all plans. Otherwise make sure this plan is in the - // stack, and if so discard up to and including it. - - for (int i = stack_size - 1; i > 0; i--) - { - if (m_plan_stack[i]->GetKind() == ThreadPlan::eKindCallFunction) - { - DiscardThreadPlansUpToPlan(m_plan_stack[i].get()); - return error; - } - } - error.SetErrorString("No expressions currently active on this thread"); - return error; +ThreadPlanSP Thread::QueueFundamentalPlan(bool abort_other_plans) { + ThreadPlanSP thread_plan_sp(new ThreadPlanBase(*this)); + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } -ThreadPlanSP -Thread::QueueFundamentalPlan (bool abort_other_plans) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanBase(*this)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; +ThreadPlanSP Thread::QueueThreadPlanForStepSingleInstruction( + bool step_over, bool abort_other_plans, bool stop_other_threads) { + ThreadPlanSP thread_plan_sp(new ThreadPlanStepInstruction( + *this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion)); + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } -ThreadPlanSP -Thread::QueueThreadPlanForStepSingleInstruction(bool step_over, - bool abort_other_plans, - bool stop_other_threads) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanStepInstruction (*this, step_over, stop_other_threads, eVoteNoOpinion, eVoteNoOpinion)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; -} +ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( + bool abort_other_plans, const AddressRange &range, + const SymbolContext &addr_context, lldb::RunMode stop_other_threads, + LazyBool step_out_avoids_code_withoug_debug_info) { + ThreadPlanSP thread_plan_sp; + thread_plan_sp.reset(new ThreadPlanStepOverRange( + *this, range, addr_context, stop_other_threads, + step_out_avoids_code_withoug_debug_info)); -ThreadPlanSP -Thread::QueueThreadPlanForStepOverRange(bool abort_other_plans, - const AddressRange &range, - const SymbolContext &addr_context, - lldb::RunMode stop_other_threads, - LazyBool step_out_avoids_code_withoug_debug_info) -{ - ThreadPlanSP thread_plan_sp; - thread_plan_sp.reset (new ThreadPlanStepOverRange (*this, range, addr_context, stop_other_threads, step_out_avoids_code_withoug_debug_info)); - - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } // Call the QueueThreadPlanForStepOverRange method which takes an address range. -ThreadPlanSP -Thread::QueueThreadPlanForStepOverRange(bool abort_other_plans, - const LineEntry &line_entry, - const SymbolContext &addr_context, - lldb::RunMode stop_other_threads, - LazyBool step_out_avoids_code_withoug_debug_info) -{ - return QueueThreadPlanForStepOverRange (abort_other_plans, - line_entry.GetSameLineContiguousAddressRange(), - addr_context, - stop_other_threads, - step_out_avoids_code_withoug_debug_info); -} - -ThreadPlanSP -Thread::QueueThreadPlanForStepInRange(bool abort_other_plans, - const AddressRange &range, - const SymbolContext &addr_context, - const char *step_in_target, - lldb::RunMode stop_other_threads, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanStepInRange (*this, - range, - addr_context, - stop_other_threads, - step_in_avoids_code_without_debug_info, - step_out_avoids_code_without_debug_info)); - ThreadPlanStepInRange *plan = static_cast<ThreadPlanStepInRange *>(thread_plan_sp.get()); - - if (step_in_target) - plan->SetStepInTarget(step_in_target); - - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; +ThreadPlanSP Thread::QueueThreadPlanForStepOverRange( + bool abort_other_plans, const LineEntry &line_entry, + const SymbolContext &addr_context, lldb::RunMode stop_other_threads, + LazyBool step_out_avoids_code_withoug_debug_info) { + return QueueThreadPlanForStepOverRange( + abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), + addr_context, stop_other_threads, + step_out_avoids_code_withoug_debug_info); +} + +ThreadPlanSP Thread::QueueThreadPlanForStepInRange( + bool abort_other_plans, const AddressRange &range, + const SymbolContext &addr_context, const char *step_in_target, + lldb::RunMode stop_other_threads, + LazyBool step_in_avoids_code_without_debug_info, + LazyBool step_out_avoids_code_without_debug_info) { + ThreadPlanSP thread_plan_sp( + new ThreadPlanStepInRange(*this, range, addr_context, stop_other_threads, + step_in_avoids_code_without_debug_info, + step_out_avoids_code_without_debug_info)); + ThreadPlanStepInRange *plan = + static_cast<ThreadPlanStepInRange *>(thread_plan_sp.get()); + + if (step_in_target) + plan->SetStepInTarget(step_in_target); + + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; } // Call the QueueThreadPlanForStepInRange method which takes an address range. -ThreadPlanSP -Thread::QueueThreadPlanForStepInRange(bool abort_other_plans, - const LineEntry &line_entry, - const SymbolContext &addr_context, - const char *step_in_target, - lldb::RunMode stop_other_threads, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info) -{ - return QueueThreadPlanForStepInRange (abort_other_plans, - line_entry.GetSameLineContiguousAddressRange(), - addr_context, - step_in_target, - stop_other_threads, - step_in_avoids_code_without_debug_info, - step_out_avoids_code_without_debug_info); -} - - -ThreadPlanSP -Thread::QueueThreadPlanForStepOut(bool abort_other_plans, - SymbolContext *addr_context, - bool first_insn, - bool stop_other_threads, - Vote stop_vote, - Vote run_vote, - uint32_t frame_idx, - LazyBool step_out_avoids_code_without_debug_info) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this, - addr_context, - first_insn, - stop_other_threads, - stop_vote, - run_vote, - frame_idx, - step_out_avoids_code_without_debug_info)); - - if (thread_plan_sp->ValidatePlan(nullptr)) - { - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; - } - else - { - return ThreadPlanSP(); - } -} - -ThreadPlanSP -Thread::QueueThreadPlanForStepOutNoShouldStop(bool abort_other_plans, - SymbolContext *addr_context, - bool first_insn, - bool stop_other_threads, - Vote stop_vote, - Vote run_vote, - uint32_t frame_idx, - bool continue_to_next_branch) -{ - const bool calculate_return_value = false; // No need to calculate the return value here. - ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut (*this, - addr_context, - first_insn, - stop_other_threads, - stop_vote, - run_vote, - frame_idx, - eLazyBoolNo, - continue_to_next_branch, - calculate_return_value)); - - ThreadPlanStepOut *new_plan = static_cast<ThreadPlanStepOut *>(thread_plan_sp.get()); - new_plan->ClearShouldStopHereCallbacks(); - - if (thread_plan_sp->ValidatePlan(nullptr)) - { - QueueThreadPlan (thread_plan_sp, abort_other_plans); - return thread_plan_sp; - } - else - { - return ThreadPlanSP(); - } -} - -ThreadPlanSP -Thread::QueueThreadPlanForStepThrough (StackID &return_stack_id, bool abort_other_plans, bool stop_other_threads) -{ - ThreadPlanSP thread_plan_sp(new ThreadPlanStepThrough (*this, return_stack_id, stop_other_threads)); - if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr)) - return ThreadPlanSP(); - - QueueThreadPlan (thread_plan_sp, abort_other_plans); +ThreadPlanSP Thread::QueueThreadPlanForStepInRange( + bool abort_other_plans, const LineEntry &line_entry, + const SymbolContext &addr_context, const char *step_in_target, + lldb::RunMode stop_other_threads, + LazyBool step_in_avoids_code_without_debug_info, + LazyBool step_out_avoids_code_without_debug_info) { + return QueueThreadPlanForStepInRange( + abort_other_plans, line_entry.GetSameLineContiguousAddressRange(), + addr_context, step_in_target, stop_other_threads, + step_in_avoids_code_without_debug_info, + step_out_avoids_code_without_debug_info); +} + +ThreadPlanSP Thread::QueueThreadPlanForStepOut( + bool abort_other_plans, SymbolContext *addr_context, bool first_insn, + bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, + LazyBool step_out_avoids_code_without_debug_info) { + ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( + *this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote, + frame_idx, step_out_avoids_code_without_debug_info)); + + if (thread_plan_sp->ValidatePlan(nullptr)) { + QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; -} - -ThreadPlanSP -Thread::QueueThreadPlanForRunToAddress (bool abort_other_plans, - Address &target_addr, - bool stop_other_threads) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanRunToAddress (*this, target_addr, stop_other_threads)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); + } else { + return ThreadPlanSP(); + } +} + +ThreadPlanSP Thread::QueueThreadPlanForStepOutNoShouldStop( + bool abort_other_plans, SymbolContext *addr_context, bool first_insn, + bool stop_other_threads, Vote stop_vote, Vote run_vote, uint32_t frame_idx, + bool continue_to_next_branch) { + const bool calculate_return_value = + false; // No need to calculate the return value here. + ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut( + *this, addr_context, first_insn, stop_other_threads, stop_vote, run_vote, + frame_idx, eLazyBoolNo, continue_to_next_branch, calculate_return_value)); + + ThreadPlanStepOut *new_plan = + static_cast<ThreadPlanStepOut *>(thread_plan_sp.get()); + new_plan->ClearShouldStopHereCallbacks(); + + if (thread_plan_sp->ValidatePlan(nullptr)) { + QueueThreadPlan(thread_plan_sp, abort_other_plans); return thread_plan_sp; -} - -ThreadPlanSP -Thread::QueueThreadPlanForStepUntil (bool abort_other_plans, - lldb::addr_t *address_list, - size_t num_addresses, - bool stop_other_threads, - uint32_t frame_idx) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanStepUntil (*this, address_list, num_addresses, stop_other_threads, frame_idx)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); + } else { + return ThreadPlanSP(); + } +} + +ThreadPlanSP Thread::QueueThreadPlanForStepThrough(StackID &return_stack_id, + bool abort_other_plans, + bool stop_other_threads) { + ThreadPlanSP thread_plan_sp( + new ThreadPlanStepThrough(*this, return_stack_id, stop_other_threads)); + if (!thread_plan_sp || !thread_plan_sp->ValidatePlan(nullptr)) + return ThreadPlanSP(); + + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; +} + +ThreadPlanSP Thread::QueueThreadPlanForRunToAddress(bool abort_other_plans, + Address &target_addr, + bool stop_other_threads) { + ThreadPlanSP thread_plan_sp( + new ThreadPlanRunToAddress(*this, target_addr, stop_other_threads)); + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; +} + +ThreadPlanSP Thread::QueueThreadPlanForStepUntil(bool abort_other_plans, + lldb::addr_t *address_list, + size_t num_addresses, + bool stop_other_threads, + uint32_t frame_idx) { + ThreadPlanSP thread_plan_sp(new ThreadPlanStepUntil( + *this, address_list, num_addresses, stop_other_threads, frame_idx)); + QueueThreadPlan(thread_plan_sp, abort_other_plans); + return thread_plan_sp; +} + +lldb::ThreadPlanSP Thread::QueueThreadPlanForStepScripted( + bool abort_other_plans, const char *class_name, bool stop_other_threads) { + ThreadPlanSP thread_plan_sp(new ThreadPlanPython(*this, class_name)); + QueueThreadPlan(thread_plan_sp, abort_other_plans); + // This seems a little funny, but I don't want to have to split up the + // constructor and the + // DidPush in the scripted plan, that seems annoying. + // That means the constructor has to be in DidPush. + // So I have to validate the plan AFTER pushing it, and then take it off + // again... + if (!thread_plan_sp->ValidatePlan(nullptr)) { + DiscardThreadPlansUpToPlan(thread_plan_sp); + return ThreadPlanSP(); + } else return thread_plan_sp; - -} - -lldb::ThreadPlanSP -Thread::QueueThreadPlanForStepScripted (bool abort_other_plans, - const char *class_name, - bool stop_other_threads) -{ - ThreadPlanSP thread_plan_sp (new ThreadPlanPython (*this, class_name)); - QueueThreadPlan (thread_plan_sp, abort_other_plans); - // This seems a little funny, but I don't want to have to split up the constructor and the - // DidPush in the scripted plan, that seems annoying. - // That means the constructor has to be in DidPush. - // So I have to validate the plan AFTER pushing it, and then take it off again... - if (!thread_plan_sp->ValidatePlan(nullptr)) - { - DiscardThreadPlansUpToPlan(thread_plan_sp); - return ThreadPlanSP(); - } - else - return thread_plan_sp; -} - -uint32_t -Thread::GetIndexID () const -{ - return m_index_id; -} - -static void -PrintPlanElement (Stream *s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx) -{ - s->IndentMore(); - s->Indent(); - s->Printf ("Element %d: ", elem_idx); - plan->GetDescription (s, desc_level); - s->EOL(); - s->IndentLess(); } -static void -PrintPlanStack (Stream *s, const std::vector<lldb::ThreadPlanSP> &plan_stack, lldb::DescriptionLevel desc_level, bool include_internal) -{ - int32_t print_idx = 0; - for (ThreadPlanSP plan_sp : plan_stack) - { - if (include_internal || !plan_sp->GetPrivate()) - { - PrintPlanElement (s, plan_sp, desc_level, print_idx++); - } - } -} - -void -Thread::DumpThreadPlans (Stream *s, - lldb::DescriptionLevel desc_level, - bool include_internal, - bool ignore_boring_threads) const -{ - uint32_t stack_size; - - if (ignore_boring_threads) - { - uint32_t stack_size = m_plan_stack.size(); - uint32_t completed_stack_size = m_completed_plan_stack.size(); - uint32_t discarded_stack_size = m_discarded_plan_stack.size(); - if (stack_size == 1 && completed_stack_size == 0 && discarded_stack_size == 0) - { - s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID()); - s->IndentMore(); - s->Indent(); - s->Printf("No active thread plans\n"); - s->IndentLess(); - return; - } - } - - s->Indent(); - s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID()); - s->IndentMore(); +uint32_t Thread::GetIndexID() const { return m_index_id; } + +static void PrintPlanElement(Stream *s, const ThreadPlanSP &plan, + lldb::DescriptionLevel desc_level, + int32_t elem_idx) { + s->IndentMore(); + s->Indent(); + s->Printf("Element %d: ", elem_idx); + plan->GetDescription(s, desc_level); + s->EOL(); + s->IndentLess(); +} + +static void PrintPlanStack(Stream *s, + const std::vector<lldb::ThreadPlanSP> &plan_stack, + lldb::DescriptionLevel desc_level, + bool include_internal) { + int32_t print_idx = 0; + for (ThreadPlanSP plan_sp : plan_stack) { + if (include_internal || !plan_sp->GetPrivate()) { + PrintPlanElement(s, plan_sp, desc_level, print_idx++); + } + } +} + +void Thread::DumpThreadPlans(Stream *s, lldb::DescriptionLevel desc_level, + bool include_internal, + bool ignore_boring_threads) const { + uint32_t stack_size; + + if (ignore_boring_threads) { + uint32_t stack_size = m_plan_stack.size(); + uint32_t completed_stack_size = m_completed_plan_stack.size(); + uint32_t discarded_stack_size = m_discarded_plan_stack.size(); + if (stack_size == 1 && completed_stack_size == 0 && + discarded_stack_size == 0) { + s->Printf("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID()); + s->IndentMore(); + s->Indent(); + s->Printf("No active thread plans\n"); + s->IndentLess(); + return; + } + } + + s->Indent(); + s->Printf("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID()); + s->IndentMore(); + s->Indent(); + s->Printf("Active plan stack:\n"); + PrintPlanStack(s, m_plan_stack, desc_level, include_internal); + + stack_size = m_completed_plan_stack.size(); + if (stack_size > 0) { s->Indent(); - s->Printf ("Active plan stack:\n"); - PrintPlanStack (s, m_plan_stack, desc_level, include_internal); + s->Printf("Completed Plan Stack:\n"); + PrintPlanStack(s, m_completed_plan_stack, desc_level, include_internal); + } - stack_size = m_completed_plan_stack.size(); - if (stack_size > 0) - { - s->Indent(); - s->Printf ("Completed Plan Stack:\n"); - PrintPlanStack (s, m_completed_plan_stack, desc_level, include_internal); - } - - stack_size = m_discarded_plan_stack.size(); - if (stack_size > 0) - { - s->Indent(); - s->Printf ("Discarded Plan Stack:\n"); - PrintPlanStack (s, m_discarded_plan_stack, desc_level, include_internal); - } + stack_size = m_discarded_plan_stack.size(); + if (stack_size > 0) { + s->Indent(); + s->Printf("Discarded Plan Stack:\n"); + PrintPlanStack(s, m_discarded_plan_stack, desc_level, include_internal); + } - s->IndentLess(); + s->IndentLess(); } -TargetSP -Thread::CalculateTarget () -{ - TargetSP target_sp; - ProcessSP process_sp(GetProcess()); - if (process_sp) - target_sp = process_sp->CalculateTarget(); - return target_sp; +TargetSP Thread::CalculateTarget() { + TargetSP target_sp; + ProcessSP process_sp(GetProcess()); + if (process_sp) + target_sp = process_sp->CalculateTarget(); + return target_sp; } -ProcessSP -Thread::CalculateProcess () -{ - return GetProcess(); -} +ProcessSP Thread::CalculateProcess() { return GetProcess(); } -ThreadSP -Thread::CalculateThread () -{ - return shared_from_this(); -} +ThreadSP Thread::CalculateThread() { return shared_from_this(); } -StackFrameSP -Thread::CalculateStackFrame () -{ - return StackFrameSP(); -} +StackFrameSP Thread::CalculateStackFrame() { return StackFrameSP(); } -void -Thread::CalculateExecutionContext (ExecutionContext &exe_ctx) -{ - exe_ctx.SetContext (shared_from_this()); +void Thread::CalculateExecutionContext(ExecutionContext &exe_ctx) { + exe_ctx.SetContext(shared_from_this()); } -StackFrameListSP -Thread::GetStackFrameList () -{ - StackFrameListSP frame_list_sp; - std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); - if (m_curr_frames_sp) - { - frame_list_sp = m_curr_frames_sp; - } - else - { - frame_list_sp.reset(new StackFrameList (*this, m_prev_frames_sp, true)); - m_curr_frames_sp = frame_list_sp; - } - return frame_list_sp; +StackFrameListSP Thread::GetStackFrameList() { + StackFrameListSP frame_list_sp; + std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); + if (m_curr_frames_sp) { + frame_list_sp = m_curr_frames_sp; + } else { + frame_list_sp.reset(new StackFrameList(*this, m_prev_frames_sp, true)); + m_curr_frames_sp = frame_list_sp; + } + return frame_list_sp; } -void -Thread::ClearStackFrames () -{ - std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); +void Thread::ClearStackFrames() { + std::lock_guard<std::recursive_mutex> guard(m_frame_mutex); - Unwind *unwinder = GetUnwinder (); - if (unwinder) - unwinder->Clear(); + Unwind *unwinder = GetUnwinder(); + if (unwinder) + unwinder->Clear(); - // Only store away the old "reference" StackFrameList if we got all its frames: - // FIXME: At some point we can try to splice in the frames we have fetched into - // the new frame as we make it, but let's not try that now. - if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched()) - m_prev_frames_sp.swap (m_curr_frames_sp); - m_curr_frames_sp.reset(); + // Only store away the old "reference" StackFrameList if we got all its + // frames: + // FIXME: At some point we can try to splice in the frames we have fetched + // into + // the new frame as we make it, but let's not try that now. + if (m_curr_frames_sp && m_curr_frames_sp->GetAllFramesFetched()) + m_prev_frames_sp.swap(m_curr_frames_sp); + m_curr_frames_sp.reset(); - m_extended_info.reset(); - m_extended_info_fetched = false; + m_extended_info.reset(); + m_extended_info_fetched = false; } -lldb::StackFrameSP -Thread::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx) -{ - return GetStackFrameList()->GetFrameWithConcreteFrameIndex (unwind_idx); +lldb::StackFrameSP Thread::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) { + return GetStackFrameList()->GetFrameWithConcreteFrameIndex(unwind_idx); } -Error -Thread::ReturnFromFrameWithIndex (uint32_t frame_idx, lldb::ValueObjectSP return_value_sp, bool broadcast) -{ - StackFrameSP frame_sp = GetStackFrameAtIndex (frame_idx); - Error return_error; - - if (!frame_sp) - { - return_error.SetErrorStringWithFormat("Could not find frame with index %d in thread 0x%" PRIx64 ".", frame_idx, GetID()); - } - - return ReturnFromFrame(frame_sp, return_value_sp, broadcast); -} +Error Thread::ReturnFromFrameWithIndex(uint32_t frame_idx, + lldb::ValueObjectSP return_value_sp, + bool broadcast) { + StackFrameSP frame_sp = GetStackFrameAtIndex(frame_idx); + Error return_error; -Error -Thread::ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return_value_sp, bool broadcast) -{ - Error return_error; - - if (!frame_sp) - { - return_error.SetErrorString("Can't return to a null frame."); - return return_error; - } - - Thread *thread = frame_sp->GetThread().get(); - uint32_t older_frame_idx = frame_sp->GetFrameIndex() + 1; - StackFrameSP older_frame_sp = thread->GetStackFrameAtIndex(older_frame_idx); - if (!older_frame_sp) - { - return_error.SetErrorString("No older frame to return to."); - return return_error; - } - - if (return_value_sp) - { - lldb::ABISP abi = thread->GetProcess()->GetABI(); - if (!abi) - { - return_error.SetErrorString("Could not find ABI to set return value."); - return return_error; - } - SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextFunction); - - // FIXME: ValueObject::Cast doesn't currently work correctly, at least not for scalars. - // Turn that back on when that works. - if (/* DISABLES CODE */ (0) && sc.function != nullptr) - { - Type *function_type = sc.function->GetType(); - if (function_type) - { - CompilerType return_type = sc.function->GetCompilerType().GetFunctionReturnType(); - if (return_type) - { - StreamString s; - return_type.DumpTypeDescription(&s); - ValueObjectSP cast_value_sp = return_value_sp->Cast(return_type); - if (cast_value_sp) - { - cast_value_sp->SetFormat(eFormatHex); - return_value_sp = cast_value_sp; - } - } - } - } - - return_error = abi->SetReturnValueObject(older_frame_sp, return_value_sp); - if (!return_error.Success()) - return return_error; - } - - // Now write the return registers for the chosen frame: - // Note, we can't use ReadAllRegisterValues->WriteAllRegisterValues, since the read & write - // cook their data - - StackFrameSP youngest_frame_sp = thread->GetStackFrameAtIndex(0); - if (youngest_frame_sp) - { - lldb::RegisterContextSP reg_ctx_sp (youngest_frame_sp->GetRegisterContext()); - if (reg_ctx_sp) - { - bool copy_success = reg_ctx_sp->CopyFromRegisterContext(older_frame_sp->GetRegisterContext()); - if (copy_success) - { - thread->DiscardThreadPlans(true); - thread->ClearStackFrames(); - if (broadcast && EventTypeHasListeners(eBroadcastBitStackChanged)) - BroadcastEvent(eBroadcastBitStackChanged, new ThreadEventData (this->shared_from_this())); - } - else - { - return_error.SetErrorString("Could not reset register values."); - } - } - else - { - return_error.SetErrorString("Frame has no register context."); - } - } - else - { - return_error.SetErrorString("Returned past top frame."); - } - return return_error; -} + if (!frame_sp) { + return_error.SetErrorStringWithFormat( + "Could not find frame with index %d in thread 0x%" PRIx64 ".", + frame_idx, GetID()); + } -static void DumpAddressList (Stream &s, const std::vector<Address> &list, ExecutionContextScope *exe_scope) -{ - for (size_t n=0;n<list.size();n++) - { - s << "\t"; - list[n].Dump (&s, exe_scope, Address::DumpStyleResolvedDescription, Address::DumpStyleSectionNameOffset); - s << "\n"; - } + return ReturnFromFrame(frame_sp, return_value_sp, broadcast); } -Error -Thread::JumpToLine (const FileSpec &file, uint32_t line, bool can_leave_function, std::string *warnings) -{ - ExecutionContext exe_ctx (GetStackFrameAtIndex(0)); - Target *target = exe_ctx.GetTargetPtr(); - TargetSP target_sp = exe_ctx.GetTargetSP(); - RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); - StackFrame *frame = exe_ctx.GetFramePtr(); - const SymbolContext &sc = frame->GetSymbolContext(eSymbolContextFunction); - - // Find candidate locations. - std::vector<Address> candidates, within_function, outside_function; - target->GetImages().FindAddressesForLine (target_sp, file, line, sc.function, within_function, outside_function); - - // If possible, we try and stay within the current function. - // Within a function, we accept multiple locations (optimized code may do this, - // there's no solution here so we do the best we can). - // However if we're trying to leave the function, we don't know how to pick the - // right location, so if there's more than one then we bail. - if (!within_function.empty()) - candidates = within_function; - else if (outside_function.size() == 1 && can_leave_function) - candidates = outside_function; - - // Check if we got anything. - if (candidates.empty()) - { - if (outside_function.empty()) - { - return Error("Cannot locate an address for %s:%i.", - file.GetFilename().AsCString(), line); - } - else if (outside_function.size() == 1) - { - return Error("%s:%i is outside the current function.", - file.GetFilename().AsCString(), line); - } - else - { - StreamString sstr; - DumpAddressList(sstr, outside_function, target); - return Error("%s:%i has multiple candidate locations:\n%s", - file.GetFilename().AsCString(), line, sstr.GetString().c_str()); - } - } +Error Thread::ReturnFromFrame(lldb::StackFrameSP frame_sp, + lldb::ValueObjectSP return_value_sp, + bool broadcast) { + Error return_error; - // Accept the first location, warn about any others. - Address dest = candidates[0]; - if (warnings && candidates.size() > 1) - { - StreamString sstr; - sstr.Printf("%s:%i appears multiple times in this function, selecting the first location:\n", - file.GetFilename().AsCString(), line); - DumpAddressList(sstr, candidates, target); - *warnings = sstr.GetString(); - } - - if (!reg_ctx->SetPC (dest)) - return Error("Cannot change PC to target address."); - - return Error(); -} + if (!frame_sp) { + return_error.SetErrorString("Can't return to a null frame."); + return return_error; + } -void -Thread::DumpUsingSettingsFormat (Stream &strm, uint32_t frame_idx) -{ - ExecutionContext exe_ctx (shared_from_this()); - Process *process = exe_ctx.GetProcessPtr(); - if (process == nullptr) - return; - - StackFrameSP frame_sp; - SymbolContext frame_sc; - if (frame_idx != LLDB_INVALID_FRAME_ID) - { - frame_sp = GetStackFrameAtIndex (frame_idx); - if (frame_sp) - { - exe_ctx.SetFrameSP(frame_sp); - frame_sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + Thread *thread = frame_sp->GetThread().get(); + uint32_t older_frame_idx = frame_sp->GetFrameIndex() + 1; + StackFrameSP older_frame_sp = thread->GetStackFrameAtIndex(older_frame_idx); + if (!older_frame_sp) { + return_error.SetErrorString("No older frame to return to."); + return return_error; + } + + if (return_value_sp) { + lldb::ABISP abi = thread->GetProcess()->GetABI(); + if (!abi) { + return_error.SetErrorString("Could not find ABI to set return value."); + return return_error; + } + SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextFunction); + + // FIXME: ValueObject::Cast doesn't currently work correctly, at least not + // for scalars. + // Turn that back on when that works. + if (/* DISABLES CODE */ (0) && sc.function != nullptr) { + Type *function_type = sc.function->GetType(); + if (function_type) { + CompilerType return_type = + sc.function->GetCompilerType().GetFunctionReturnType(); + if (return_type) { + StreamString s; + return_type.DumpTypeDescription(&s); + ValueObjectSP cast_value_sp = return_value_sp->Cast(return_type); + if (cast_value_sp) { + cast_value_sp->SetFormat(eFormatHex); + return_value_sp = cast_value_sp; + } } - } - - const FormatEntity::Entry *thread_format = exe_ctx.GetTargetRef().GetDebugger().GetThreadFormat(); - assert (thread_format); - - FormatEntity::Format(*thread_format, - strm, - frame_sp ? &frame_sc : nullptr, - &exe_ctx, - nullptr, - nullptr, - false, - false); -} - -void -Thread::SettingsInitialize () -{ -} - -void -Thread::SettingsTerminate () -{ -} - -lldb::addr_t -Thread::GetThreadPointer () -{ + } + } + + return_error = abi->SetReturnValueObject(older_frame_sp, return_value_sp); + if (!return_error.Success()) + return return_error; + } + + // Now write the return registers for the chosen frame: + // Note, we can't use ReadAllRegisterValues->WriteAllRegisterValues, since the + // read & write + // cook their data + + StackFrameSP youngest_frame_sp = thread->GetStackFrameAtIndex(0); + if (youngest_frame_sp) { + lldb::RegisterContextSP reg_ctx_sp(youngest_frame_sp->GetRegisterContext()); + if (reg_ctx_sp) { + bool copy_success = reg_ctx_sp->CopyFromRegisterContext( + older_frame_sp->GetRegisterContext()); + if (copy_success) { + thread->DiscardThreadPlans(true); + thread->ClearStackFrames(); + if (broadcast && EventTypeHasListeners(eBroadcastBitStackChanged)) + BroadcastEvent(eBroadcastBitStackChanged, + new ThreadEventData(this->shared_from_this())); + } else { + return_error.SetErrorString("Could not reset register values."); + } + } else { + return_error.SetErrorString("Frame has no register context."); + } + } else { + return_error.SetErrorString("Returned past top frame."); + } + return return_error; +} + +static void DumpAddressList(Stream &s, const std::vector<Address> &list, + ExecutionContextScope *exe_scope) { + for (size_t n = 0; n < list.size(); n++) { + s << "\t"; + list[n].Dump(&s, exe_scope, Address::DumpStyleResolvedDescription, + Address::DumpStyleSectionNameOffset); + s << "\n"; + } +} + +Error Thread::JumpToLine(const FileSpec &file, uint32_t line, + bool can_leave_function, std::string *warnings) { + ExecutionContext exe_ctx(GetStackFrameAtIndex(0)); + Target *target = exe_ctx.GetTargetPtr(); + TargetSP target_sp = exe_ctx.GetTargetSP(); + RegisterContext *reg_ctx = exe_ctx.GetRegisterContext(); + StackFrame *frame = exe_ctx.GetFramePtr(); + const SymbolContext &sc = frame->GetSymbolContext(eSymbolContextFunction); + + // Find candidate locations. + std::vector<Address> candidates, within_function, outside_function; + target->GetImages().FindAddressesForLine(target_sp, file, line, sc.function, + within_function, outside_function); + + // If possible, we try and stay within the current function. + // Within a function, we accept multiple locations (optimized code may do + // this, + // there's no solution here so we do the best we can). + // However if we're trying to leave the function, we don't know how to pick + // the + // right location, so if there's more than one then we bail. + if (!within_function.empty()) + candidates = within_function; + else if (outside_function.size() == 1 && can_leave_function) + candidates = outside_function; + + // Check if we got anything. + if (candidates.empty()) { + if (outside_function.empty()) { + return Error("Cannot locate an address for %s:%i.", + file.GetFilename().AsCString(), line); + } else if (outside_function.size() == 1) { + return Error("%s:%i is outside the current function.", + file.GetFilename().AsCString(), line); + } else { + StreamString sstr; + DumpAddressList(sstr, outside_function, target); + return Error("%s:%i has multiple candidate locations:\n%s", + file.GetFilename().AsCString(), line, + sstr.GetString().c_str()); + } + } + + // Accept the first location, warn about any others. + Address dest = candidates[0]; + if (warnings && candidates.size() > 1) { + StreamString sstr; + sstr.Printf("%s:%i appears multiple times in this function, selecting the " + "first location:\n", + file.GetFilename().AsCString(), line); + DumpAddressList(sstr, candidates, target); + *warnings = sstr.GetString(); + } + + if (!reg_ctx->SetPC(dest)) + return Error("Cannot change PC to target address."); + + return Error(); +} + +void Thread::DumpUsingSettingsFormat(Stream &strm, uint32_t frame_idx) { + ExecutionContext exe_ctx(shared_from_this()); + Process *process = exe_ctx.GetProcessPtr(); + if (process == nullptr) + return; + + StackFrameSP frame_sp; + SymbolContext frame_sc; + if (frame_idx != LLDB_INVALID_FRAME_ID) { + frame_sp = GetStackFrameAtIndex(frame_idx); + if (frame_sp) { + exe_ctx.SetFrameSP(frame_sp); + frame_sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + } + } + + const FormatEntity::Entry *thread_format = + exe_ctx.GetTargetRef().GetDebugger().GetThreadFormat(); + assert(thread_format); + + FormatEntity::Format(*thread_format, strm, frame_sp ? &frame_sc : nullptr, + &exe_ctx, nullptr, nullptr, false, false); +} + +void Thread::SettingsInitialize() {} + +void Thread::SettingsTerminate() {} + +lldb::addr_t Thread::GetThreadPointer() { return LLDB_INVALID_ADDRESS; } + +addr_t Thread::GetThreadLocalData(const ModuleSP module, + lldb::addr_t tls_file_addr) { + // The default implementation is to ask the dynamic loader for it. + // This can be overridden for specific platforms. + DynamicLoader *loader = GetProcess()->GetDynamicLoader(); + if (loader) + return loader->GetThreadLocalData(module, shared_from_this(), + tls_file_addr); + else return LLDB_INVALID_ADDRESS; } -addr_t -Thread::GetThreadLocalData(const ModuleSP module, lldb::addr_t tls_file_addr) -{ - // The default implementation is to ask the dynamic loader for it. - // This can be overridden for specific platforms. - DynamicLoader *loader = GetProcess()->GetDynamicLoader(); - if (loader) - return loader->GetThreadLocalData(module, shared_from_this(), tls_file_addr); - else - return LLDB_INVALID_ADDRESS; -} - -bool -Thread::SafeToCallFunctions () -{ - Process *process = GetProcess().get(); - if (process) - { - SystemRuntime *runtime = process->GetSystemRuntime (); - if (runtime) - { - return runtime->SafeToCallFunctionsOnThisThread (shared_from_this()); - } +bool Thread::SafeToCallFunctions() { + Process *process = GetProcess().get(); + if (process) { + SystemRuntime *runtime = process->GetSystemRuntime(); + if (runtime) { + return runtime->SafeToCallFunctionsOnThisThread(shared_from_this()); } - return true; + } + return true; } lldb::StackFrameSP -Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr) -{ - return GetStackFrameList()->GetStackFrameSPForStackFramePtr (stack_frame_ptr); -} - -const char * -Thread::StopReasonAsCString (lldb::StopReason reason) -{ - switch (reason) - { - case eStopReasonInvalid: return "invalid"; - case eStopReasonNone: return "none"; - case eStopReasonTrace: return "trace"; - case eStopReasonBreakpoint: return "breakpoint"; - case eStopReasonWatchpoint: return "watchpoint"; - case eStopReasonSignal: return "signal"; - case eStopReasonException: return "exception"; - case eStopReasonExec: return "exec"; - case eStopReasonPlanComplete: return "plan complete"; - case eStopReasonThreadExiting: return "thread exiting"; - case eStopReasonInstrumentation: return "instrumentation break"; - } - - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof (unknown_state_string), "StopReason = %i", reason); - return unknown_state_string; -} - -const char * -Thread::RunModeAsCString (lldb::RunMode mode) -{ - switch (mode) - { - case eOnlyThisThread: return "only this thread"; - case eAllThreads: return "all threads"; - case eOnlyDuringStepping: return "only during stepping"; - } - - static char unknown_state_string[64]; - snprintf(unknown_state_string, sizeof (unknown_state_string), "RunMode = %i", mode); - return unknown_state_string; -} +Thread::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) { + return GetStackFrameList()->GetStackFrameSPForStackFramePtr(stack_frame_ptr); +} + +const char *Thread::StopReasonAsCString(lldb::StopReason reason) { + switch (reason) { + case eStopReasonInvalid: + return "invalid"; + case eStopReasonNone: + return "none"; + case eStopReasonTrace: + return "trace"; + case eStopReasonBreakpoint: + return "breakpoint"; + case eStopReasonWatchpoint: + return "watchpoint"; + case eStopReasonSignal: + return "signal"; + case eStopReasonException: + return "exception"; + case eStopReasonExec: + return "exec"; + case eStopReasonPlanComplete: + return "plan complete"; + case eStopReasonThreadExiting: + return "thread exiting"; + case eStopReasonInstrumentation: + return "instrumentation break"; + } + + static char unknown_state_string[64]; + snprintf(unknown_state_string, sizeof(unknown_state_string), + "StopReason = %i", reason); + return unknown_state_string; +} + +const char *Thread::RunModeAsCString(lldb::RunMode mode) { + switch (mode) { + case eOnlyThisThread: + return "only this thread"; + case eAllThreads: + return "all threads"; + case eOnlyDuringStepping: + return "only during stepping"; + } + + static char unknown_state_string[64]; + snprintf(unknown_state_string, sizeof(unknown_state_string), "RunMode = %i", + mode); + return unknown_state_string; +} + +size_t Thread::GetStatus(Stream &strm, uint32_t start_frame, + uint32_t num_frames, uint32_t num_frames_with_source) { + ExecutionContext exe_ctx(shared_from_this()); + Target *target = exe_ctx.GetTargetPtr(); + Process *process = exe_ctx.GetProcessPtr(); + size_t num_frames_shown = 0; + strm.Indent(); + bool is_selected = false; + if (process) { + if (process->GetThreadList().GetSelectedThread().get() == this) + is_selected = true; + } + strm.Printf("%c ", is_selected ? '*' : ' '); + if (target && target->GetDebugger().GetUseExternalEditor()) { + StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame); + if (frame_sp) { + SymbolContext frame_sc( + frame_sp->GetSymbolContext(eSymbolContextLineEntry)); + if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) { + Host::OpenFileInExternalEditor(frame_sc.line_entry.file, + frame_sc.line_entry.line); + } + } + } + + DumpUsingSettingsFormat(strm, start_frame); + + if (num_frames > 0) { + strm.IndentMore(); + + const bool show_frame_info = true; + + const char *selected_frame_marker = nullptr; + if (num_frames == 1 || + (GetID() != GetProcess()->GetThreadList().GetSelectedThread()->GetID())) + strm.IndentMore(); + else + selected_frame_marker = "* "; -size_t -Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint32_t num_frames_with_source) -{ - ExecutionContext exe_ctx (shared_from_this()); - Target *target = exe_ctx.GetTargetPtr(); - Process *process = exe_ctx.GetProcessPtr(); - size_t num_frames_shown = 0; - strm.Indent(); - bool is_selected = false; - if (process) - { - if (process->GetThreadList().GetSelectedThread().get() == this) - is_selected = true; - } - strm.Printf("%c ", is_selected ? '*' : ' '); - if (target && target->GetDebugger().GetUseExternalEditor()) - { - StackFrameSP frame_sp = GetStackFrameAtIndex(start_frame); - if (frame_sp) - { - SymbolContext frame_sc(frame_sp->GetSymbolContext (eSymbolContextLineEntry)); - if (frame_sc.line_entry.line != 0 && frame_sc.line_entry.file) - { - Host::OpenFileInExternalEditor (frame_sc.line_entry.file, frame_sc.line_entry.line); - } - } - } - - DumpUsingSettingsFormat (strm, start_frame); - - if (num_frames > 0) - { - strm.IndentMore(); - - const bool show_frame_info = true; - - const char *selected_frame_marker = nullptr; - if (num_frames == 1 || (GetID() != GetProcess()->GetThreadList().GetSelectedThread()->GetID())) - strm.IndentMore (); - else - selected_frame_marker = "* "; - - num_frames_shown = GetStackFrameList ()->GetStatus (strm, - start_frame, - num_frames, - show_frame_info, - num_frames_with_source, - selected_frame_marker); - if (num_frames == 1) - strm.IndentLess(); - strm.IndentLess(); - } - return num_frames_shown; + num_frames_shown = GetStackFrameList()->GetStatus( + strm, start_frame, num_frames, show_frame_info, num_frames_with_source, + selected_frame_marker); + if (num_frames == 1) + strm.IndentLess(); + strm.IndentLess(); + } + return num_frames_shown; } -bool -Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json_thread, bool print_json_stopinfo) -{ - DumpUsingSettingsFormat (strm, 0); - strm.Printf("\n"); +bool Thread::GetDescription(Stream &strm, lldb::DescriptionLevel level, + bool print_json_thread, bool print_json_stopinfo) { + DumpUsingSettingsFormat(strm, 0); + strm.Printf("\n"); - StructuredData::ObjectSP thread_info = GetExtendedInfo(); - - if (print_json_thread || print_json_stopinfo) - { - if (thread_info && print_json_thread) - { - thread_info->Dump (strm); - strm.Printf("\n"); - } - - if (print_json_stopinfo && m_stop_info_sp) - { - StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo(); - if (stop_info) - { - stop_info->Dump (strm); - strm.Printf("\n"); - } - } + StructuredData::ObjectSP thread_info = GetExtendedInfo(); - return true; + if (print_json_thread || print_json_stopinfo) { + if (thread_info && print_json_thread) { + thread_info->Dump(strm); + strm.Printf("\n"); } - if (thread_info) - { - StructuredData::ObjectSP activity = thread_info->GetObjectForDotSeparatedPath("activity"); - StructuredData::ObjectSP breadcrumb = thread_info->GetObjectForDotSeparatedPath("breadcrumb"); - StructuredData::ObjectSP messages = thread_info->GetObjectForDotSeparatedPath("trace_messages"); - - bool printed_activity = false; - if (activity && activity->GetType() == StructuredData::Type::eTypeDictionary) - { - StructuredData::Dictionary *activity_dict = activity->GetAsDictionary(); - StructuredData::ObjectSP id = activity_dict->GetValueForKey("id"); - StructuredData::ObjectSP name = activity_dict->GetValueForKey("name"); - if (name && name->GetType() == StructuredData::Type::eTypeString - && id && id->GetType() == StructuredData::Type::eTypeInteger) - { - strm.Printf(" Activity '%s', 0x%" PRIx64 "\n", name->GetAsString()->GetValue().c_str(), id->GetAsInteger()->GetValue()); - } - printed_activity = true; - } - bool printed_breadcrumb = false; - if (breadcrumb && breadcrumb->GetType() == StructuredData::Type::eTypeDictionary) - { - if (printed_activity) - strm.Printf ("\n"); - StructuredData::Dictionary *breadcrumb_dict = breadcrumb->GetAsDictionary(); - StructuredData::ObjectSP breadcrumb_text = breadcrumb_dict->GetValueForKey ("name"); - if (breadcrumb_text && breadcrumb_text->GetType() == StructuredData::Type::eTypeString) - { - strm.Printf (" Current Breadcrumb: %s\n", breadcrumb_text->GetAsString()->GetValue().c_str()); - } - printed_breadcrumb = true; - } - if (messages && messages->GetType() == StructuredData::Type::eTypeArray) - { - if (printed_breadcrumb) - strm.Printf("\n"); - StructuredData::Array *messages_array = messages->GetAsArray(); - const size_t msg_count = messages_array->GetSize(); - if (msg_count > 0) - { - strm.Printf (" %zu trace messages:\n", msg_count); - for (size_t i = 0; i < msg_count; i++) - { - StructuredData::ObjectSP message = messages_array->GetItemAtIndex(i); - if (message && message->GetType() == StructuredData::Type::eTypeDictionary) - { - StructuredData::Dictionary *message_dict = message->GetAsDictionary(); - StructuredData::ObjectSP message_text = message_dict->GetValueForKey ("message"); - if (message_text && message_text->GetType() == StructuredData::Type::eTypeString) - { - strm.Printf (" %s\n", message_text->GetAsString()->GetValue().c_str()); - } - } - } - } - } + if (print_json_stopinfo && m_stop_info_sp) { + StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo(); + if (stop_info) { + stop_info->Dump(strm); + strm.Printf("\n"); + } } return true; -} - -size_t -Thread::GetStackFrameStatus (Stream& strm, - uint32_t first_frame, - uint32_t num_frames, - bool show_frame_info, - uint32_t num_frames_with_source) -{ - return GetStackFrameList()->GetStatus (strm, - first_frame, - num_frames, - show_frame_info, - num_frames_with_source); -} - -Unwind * -Thread::GetUnwinder () -{ - if (!m_unwinder_ap) - { - const ArchSpec target_arch (CalculateTarget()->GetArchitecture ()); - const llvm::Triple::ArchType machine = target_arch.GetMachine(); - switch (machine) - { - case llvm::Triple::x86_64: - case llvm::Triple::x86: - case llvm::Triple::arm: - case llvm::Triple::aarch64: - case llvm::Triple::thumb: - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::ppc: - case llvm::Triple::ppc64: - case llvm::Triple::systemz: - case llvm::Triple::hexagon: - m_unwinder_ap.reset (new UnwindLLDB (*this)); - break; - - default: - if (target_arch.GetTriple().getVendor() == llvm::Triple::Apple) - m_unwinder_ap.reset (new UnwindMacOSXFrameBackchain (*this)); - break; - } - } - return m_unwinder_ap.get(); -} - -void -Thread::Flush () -{ - ClearStackFrames (); - m_reg_context_sp.reset(); -} - -bool -Thread::IsStillAtLastBreakpointHit () -{ - // If we are currently stopped at a breakpoint, always return that stopinfo and don't reset it. - // This allows threads to maintain their breakpoint stopinfo, such as when thread-stepping in - // multithreaded programs. - if (m_stop_info_sp) { - StopReason stop_reason = m_stop_info_sp->GetStopReason(); - if (stop_reason == lldb::eStopReasonBreakpoint) { - uint64_t value = m_stop_info_sp->GetValue(); - lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext()); - if (reg_ctx_sp) - { - lldb::addr_t pc = reg_ctx_sp->GetPC(); - BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(pc); - if (bp_site_sp && - static_cast<break_id_t>(value) == bp_site_sp->GetID()) - return true; + } + + if (thread_info) { + StructuredData::ObjectSP activity = + thread_info->GetObjectForDotSeparatedPath("activity"); + StructuredData::ObjectSP breadcrumb = + thread_info->GetObjectForDotSeparatedPath("breadcrumb"); + StructuredData::ObjectSP messages = + thread_info->GetObjectForDotSeparatedPath("trace_messages"); + + bool printed_activity = false; + if (activity && + activity->GetType() == StructuredData::Type::eTypeDictionary) { + StructuredData::Dictionary *activity_dict = activity->GetAsDictionary(); + StructuredData::ObjectSP id = activity_dict->GetValueForKey("id"); + StructuredData::ObjectSP name = activity_dict->GetValueForKey("name"); + if (name && name->GetType() == StructuredData::Type::eTypeString && id && + id->GetType() == StructuredData::Type::eTypeInteger) { + strm.Printf(" Activity '%s', 0x%" PRIx64 "\n", + name->GetAsString()->GetValue().c_str(), + id->GetAsInteger()->GetValue()); + } + printed_activity = true; + } + bool printed_breadcrumb = false; + if (breadcrumb && + breadcrumb->GetType() == StructuredData::Type::eTypeDictionary) { + if (printed_activity) + strm.Printf("\n"); + StructuredData::Dictionary *breadcrumb_dict = + breadcrumb->GetAsDictionary(); + StructuredData::ObjectSP breadcrumb_text = + breadcrumb_dict->GetValueForKey("name"); + if (breadcrumb_text && + breadcrumb_text->GetType() == StructuredData::Type::eTypeString) { + strm.Printf(" Current Breadcrumb: %s\n", + breadcrumb_text->GetAsString()->GetValue().c_str()); + } + printed_breadcrumb = true; + } + if (messages && messages->GetType() == StructuredData::Type::eTypeArray) { + if (printed_breadcrumb) + strm.Printf("\n"); + StructuredData::Array *messages_array = messages->GetAsArray(); + const size_t msg_count = messages_array->GetSize(); + if (msg_count > 0) { + strm.Printf(" %zu trace messages:\n", msg_count); + for (size_t i = 0; i < msg_count; i++) { + StructuredData::ObjectSP message = messages_array->GetItemAtIndex(i); + if (message && + message->GetType() == StructuredData::Type::eTypeDictionary) { + StructuredData::Dictionary *message_dict = + message->GetAsDictionary(); + StructuredData::ObjectSP message_text = + message_dict->GetValueForKey("message"); + if (message_text && + message_text->GetType() == StructuredData::Type::eTypeString) { + strm.Printf(" %s\n", + message_text->GetAsString()->GetValue().c_str()); } + } } - } - return false; -} - -Error -Thread::StepIn (bool source_step, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info) - -{ - Error error; - Process *process = GetProcess().get(); - if (StateIsStoppedState (process->GetState(), true)) - { - StackFrameSP frame_sp = GetStackFrameAtIndex (0); - ThreadPlanSP new_plan_sp; - const lldb::RunMode run_mode = eOnlyThisThread; - const bool abort_other_plans = false; - - if (source_step && frame_sp && frame_sp->HasDebugInformation ()) - { - SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); - new_plan_sp = QueueThreadPlanForStepInRange(abort_other_plans, - sc.line_entry, - sc, - nullptr, - run_mode, - step_in_avoids_code_without_debug_info, - step_out_avoids_code_without_debug_info); - } - else - { - new_plan_sp = QueueThreadPlanForStepSingleInstruction (false, - abort_other_plans, - run_mode); - } - - new_plan_sp->SetIsMasterPlan(true); - new_plan_sp->SetOkayToDiscard(false); - - // Why do we need to set the current thread by ID here??? - process->GetThreadList().SetSelectedThreadByID (GetID()); - error = process->Resume(); - } - else - { - error.SetErrorString("process not stopped"); - } - return error; -} - -Error -Thread::StepOver (bool source_step, - LazyBool step_out_avoids_code_without_debug_info) -{ - Error error; - Process *process = GetProcess().get(); - if (StateIsStoppedState (process->GetState(), true)) - { - StackFrameSP frame_sp = GetStackFrameAtIndex (0); - ThreadPlanSP new_plan_sp; - - const lldb::RunMode run_mode = eOnlyThisThread; - const bool abort_other_plans = false; - - if (source_step && frame_sp && frame_sp->HasDebugInformation ()) - { - SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); - new_plan_sp = QueueThreadPlanForStepOverRange (abort_other_plans, - sc.line_entry, - sc, - run_mode, - step_out_avoids_code_without_debug_info); - } - else - { - new_plan_sp = QueueThreadPlanForStepSingleInstruction (true, - abort_other_plans, - run_mode); - } - - new_plan_sp->SetIsMasterPlan(true); - new_plan_sp->SetOkayToDiscard(false); - - // Why do we need to set the current thread by ID here??? - process->GetThreadList().SetSelectedThreadByID (GetID()); - error = process->Resume(); - } - else - { - error.SetErrorString("process not stopped"); - } - return error; -} - -Error -Thread::StepOut () -{ - Error error; - Process *process = GetProcess().get(); - if (StateIsStoppedState (process->GetState(), true)) - { - const bool first_instruction = false; - const bool stop_other_threads = false; - const bool abort_other_plans = false; - - ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut(abort_other_plans, - nullptr, - first_instruction, - stop_other_threads, - eVoteYes, - eVoteNoOpinion, - 0)); - - new_plan_sp->SetIsMasterPlan(true); - new_plan_sp->SetOkayToDiscard(false); - - // Why do we need to set the current thread by ID here??? - process->GetThreadList().SetSelectedThreadByID (GetID()); - error = process->Resume(); - } - else - { - error.SetErrorString("process not stopped"); - } - return error; + } + } + } + + return true; +} + +size_t Thread::GetStackFrameStatus(Stream &strm, uint32_t first_frame, + uint32_t num_frames, bool show_frame_info, + uint32_t num_frames_with_source) { + return GetStackFrameList()->GetStatus( + strm, first_frame, num_frames, show_frame_info, num_frames_with_source); +} + +Unwind *Thread::GetUnwinder() { + if (!m_unwinder_ap) { + const ArchSpec target_arch(CalculateTarget()->GetArchitecture()); + const llvm::Triple::ArchType machine = target_arch.GetMachine(); + switch (machine) { + case llvm::Triple::x86_64: + case llvm::Triple::x86: + case llvm::Triple::arm: + case llvm::Triple::aarch64: + case llvm::Triple::thumb: + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + case llvm::Triple::ppc: + case llvm::Triple::ppc64: + case llvm::Triple::systemz: + case llvm::Triple::hexagon: + m_unwinder_ap.reset(new UnwindLLDB(*this)); + break; + + default: + if (target_arch.GetTriple().getVendor() == llvm::Triple::Apple) + m_unwinder_ap.reset(new UnwindMacOSXFrameBackchain(*this)); + break; + } + } + return m_unwinder_ap.get(); +} + +void Thread::Flush() { + ClearStackFrames(); + m_reg_context_sp.reset(); +} + +bool Thread::IsStillAtLastBreakpointHit() { + // If we are currently stopped at a breakpoint, always return that stopinfo + // and don't reset it. + // This allows threads to maintain their breakpoint stopinfo, such as when + // thread-stepping in + // multithreaded programs. + if (m_stop_info_sp) { + StopReason stop_reason = m_stop_info_sp->GetStopReason(); + if (stop_reason == lldb::eStopReasonBreakpoint) { + uint64_t value = m_stop_info_sp->GetValue(); + lldb::RegisterContextSP reg_ctx_sp(GetRegisterContext()); + if (reg_ctx_sp) { + lldb::addr_t pc = reg_ctx_sp->GetPC(); + BreakpointSiteSP bp_site_sp = + GetProcess()->GetBreakpointSiteList().FindByAddress(pc); + if (bp_site_sp && static_cast<break_id_t>(value) == bp_site_sp->GetID()) + return true; + } + } + } + return false; +} + +Error Thread::StepIn(bool source_step, + LazyBool step_in_avoids_code_without_debug_info, + LazyBool step_out_avoids_code_without_debug_info) + +{ + Error error; + Process *process = GetProcess().get(); + if (StateIsStoppedState(process->GetState(), true)) { + StackFrameSP frame_sp = GetStackFrameAtIndex(0); + ThreadPlanSP new_plan_sp; + const lldb::RunMode run_mode = eOnlyThisThread; + const bool abort_other_plans = false; + + if (source_step && frame_sp && frame_sp->HasDebugInformation()) { + SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); + new_plan_sp = QueueThreadPlanForStepInRange( + abort_other_plans, sc.line_entry, sc, nullptr, run_mode, + step_in_avoids_code_without_debug_info, + step_out_avoids_code_without_debug_info); + } else { + new_plan_sp = QueueThreadPlanForStepSingleInstruction( + false, abort_other_plans, run_mode); + } + + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID(GetID()); + error = process->Resume(); + } else { + error.SetErrorString("process not stopped"); + } + return error; +} + +Error Thread::StepOver(bool source_step, + LazyBool step_out_avoids_code_without_debug_info) { + Error error; + Process *process = GetProcess().get(); + if (StateIsStoppedState(process->GetState(), true)) { + StackFrameSP frame_sp = GetStackFrameAtIndex(0); + ThreadPlanSP new_plan_sp; + + const lldb::RunMode run_mode = eOnlyThisThread; + const bool abort_other_plans = false; + + if (source_step && frame_sp && frame_sp->HasDebugInformation()) { + SymbolContext sc(frame_sp->GetSymbolContext(eSymbolContextEverything)); + new_plan_sp = QueueThreadPlanForStepOverRange( + abort_other_plans, sc.line_entry, sc, run_mode, + step_out_avoids_code_without_debug_info); + } else { + new_plan_sp = QueueThreadPlanForStepSingleInstruction( + true, abort_other_plans, run_mode); + } + + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID(GetID()); + error = process->Resume(); + } else { + error.SetErrorString("process not stopped"); + } + return error; +} + +Error Thread::StepOut() { + Error error; + Process *process = GetProcess().get(); + if (StateIsStoppedState(process->GetState(), true)) { + const bool first_instruction = false; + const bool stop_other_threads = false; + const bool abort_other_plans = false; + + ThreadPlanSP new_plan_sp(QueueThreadPlanForStepOut( + abort_other_plans, nullptr, first_instruction, stop_other_threads, + eVoteYes, eVoteNoOpinion, 0)); + + new_plan_sp->SetIsMasterPlan(true); + new_plan_sp->SetOkayToDiscard(false); + + // Why do we need to set the current thread by ID here??? + process->GetThreadList().SetSelectedThreadByID(GetID()); + error = process->Resume(); + } else { + error.SetErrorString("process not stopped"); + } + return error; } diff --git a/lldb/source/Target/ThreadCollection.cpp b/lldb/source/Target/ThreadCollection.cpp index d8d622e9387..2d63b67a6db 100644 --- a/lldb/source/Target/ThreadCollection.cpp +++ b/lldb/source/Target/ThreadCollection.cpp @@ -11,72 +11,56 @@ #include <algorithm> #include <mutex> -#include "lldb/Target/ThreadCollection.h" #include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadCollection.h" using namespace lldb; using namespace lldb_private; -ThreadCollection::ThreadCollection() : - m_threads(), - m_mutex() -{ -} +ThreadCollection::ThreadCollection() : m_threads(), m_mutex() {} -ThreadCollection::ThreadCollection(collection threads) : - m_threads(threads), - m_mutex() -{ -} +ThreadCollection::ThreadCollection(collection threads) + : m_threads(threads), m_mutex() {} -void -ThreadCollection::AddThread (const ThreadSP &thread_sp) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_threads.push_back (thread_sp); +void ThreadCollection::AddThread(const ThreadSP &thread_sp) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + m_threads.push_back(thread_sp); } -void -ThreadCollection::AddThreadSortedByIndexID (const ThreadSP &thread_sp) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - // Make sure we always keep the threads sorted by thread index ID - const uint32_t thread_index_id = thread_sp->GetIndexID(); - if (m_threads.empty() || m_threads.back()->GetIndexID() < thread_index_id) - m_threads.push_back (thread_sp); - else - { - m_threads.insert(std::upper_bound(m_threads.begin(), m_threads.end(), thread_sp, - [] (const ThreadSP &lhs, const ThreadSP &rhs) -> bool - { - return lhs->GetIndexID() < rhs->GetIndexID(); - }), thread_sp); - } +void ThreadCollection::AddThreadSortedByIndexID(const ThreadSP &thread_sp) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + // Make sure we always keep the threads sorted by thread index ID + const uint32_t thread_index_id = thread_sp->GetIndexID(); + if (m_threads.empty() || m_threads.back()->GetIndexID() < thread_index_id) + m_threads.push_back(thread_sp); + else { + m_threads.insert( + std::upper_bound(m_threads.begin(), m_threads.end(), thread_sp, + [](const ThreadSP &lhs, const ThreadSP &rhs) -> bool { + return lhs->GetIndexID() < rhs->GetIndexID(); + }), + thread_sp); + } } -void -ThreadCollection::InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - if (idx < m_threads.size()) - m_threads.insert(m_threads.begin() + idx, thread_sp); - else - m_threads.push_back (thread_sp); +void ThreadCollection::InsertThread(const lldb::ThreadSP &thread_sp, + uint32_t idx) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + if (idx < m_threads.size()) + m_threads.insert(m_threads.begin() + idx, thread_sp); + else + m_threads.push_back(thread_sp); } -uint32_t -ThreadCollection::GetSize () -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - return m_threads.size(); +uint32_t ThreadCollection::GetSize() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + return m_threads.size(); } -ThreadSP -ThreadCollection::GetThreadAtIndex (uint32_t idx) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - ThreadSP thread_sp; - if (idx < m_threads.size()) - thread_sp = m_threads[idx]; - return thread_sp; +ThreadSP ThreadCollection::GetThreadAtIndex(uint32_t idx) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + ThreadSP thread_sp; + if (idx < m_threads.size()) + thread_sp = m_threads[idx]; + return thread_sp; } diff --git a/lldb/source/Target/ThreadList.cpp b/lldb/source/Target/ThreadList.cpp index 23e9f780732..15388a5afa1 100644 --- a/lldb/source/Target/ThreadList.cpp +++ b/lldb/source/Target/ThreadList.cpp @@ -17,856 +17,748 @@ // Project includes #include "lldb/Core/Log.h" #include "lldb/Core/State.h" +#include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" -#include "lldb/Target/ThreadList.h" #include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadList.h" #include "lldb/Target/ThreadPlan.h" -#include "lldb/Target/Process.h" #include "lldb/Utility/ConvertEnum.h" #include "lldb/Utility/LLDBAssert.h" using namespace lldb; using namespace lldb_private; -ThreadList::ThreadList (Process *process) : - ThreadCollection(), - m_process (process), - m_stop_id (0), - m_selected_tid (LLDB_INVALID_THREAD_ID) -{ -} - -ThreadList::ThreadList (const ThreadList &rhs) : - ThreadCollection(), - m_process (rhs.m_process), - m_stop_id (rhs.m_stop_id), - m_selected_tid () -{ - // Use the assignment operator since it uses the mutex - *this = rhs; -} - -const ThreadList& -ThreadList::operator = (const ThreadList& rhs) -{ - if (this != &rhs) - { - // Lock both mutexes to make sure neither side changes anyone on us - // while the assignment occurs - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - - m_process = rhs.m_process; - m_stop_id = rhs.m_stop_id; - m_threads = rhs.m_threads; - m_selected_tid = rhs.m_selected_tid; - } - return *this; +ThreadList::ThreadList(Process *process) + : ThreadCollection(), m_process(process), m_stop_id(0), + m_selected_tid(LLDB_INVALID_THREAD_ID) {} + +ThreadList::ThreadList(const ThreadList &rhs) + : ThreadCollection(), m_process(rhs.m_process), m_stop_id(rhs.m_stop_id), + m_selected_tid() { + // Use the assignment operator since it uses the mutex + *this = rhs; } +const ThreadList &ThreadList::operator=(const ThreadList &rhs) { + if (this != &rhs) { + // Lock both mutexes to make sure neither side changes anyone on us + // while the assignment occurs + std::lock_guard<std::recursive_mutex> guard(GetMutex()); -ThreadList::~ThreadList() -{ - // Clear the thread list. Clear will take the mutex lock - // which will ensure that if anyone is using the list - // they won't get it removed while using it. - Clear(); + m_process = rhs.m_process; + m_stop_id = rhs.m_stop_id; + m_threads = rhs.m_threads; + m_selected_tid = rhs.m_selected_tid; + } + return *this; } -lldb::ThreadSP -ThreadList::GetExpressionExecutionThread() -{ - if (m_expression_tid_stack.empty()) - return GetSelectedThread(); - ThreadSP expr_thread_sp = FindThreadByID(m_expression_tid_stack.back()); - if (expr_thread_sp) - return expr_thread_sp; - else - return GetSelectedThread(); +ThreadList::~ThreadList() { + // Clear the thread list. Clear will take the mutex lock + // which will ensure that if anyone is using the list + // they won't get it removed while using it. + Clear(); } -void -ThreadList::PushExpressionExecutionThread(lldb::tid_t tid) -{ - m_expression_tid_stack.push_back(tid); +lldb::ThreadSP ThreadList::GetExpressionExecutionThread() { + if (m_expression_tid_stack.empty()) + return GetSelectedThread(); + ThreadSP expr_thread_sp = FindThreadByID(m_expression_tid_stack.back()); + if (expr_thread_sp) + return expr_thread_sp; + else + return GetSelectedThread(); } - -void -ThreadList::PopExpressionExecutionThread(lldb::tid_t tid) -{ - assert(m_expression_tid_stack.back() == tid); - m_expression_tid_stack.pop_back(); + +void ThreadList::PushExpressionExecutionThread(lldb::tid_t tid) { + m_expression_tid_stack.push_back(tid); } -uint32_t -ThreadList::GetStopID () const -{ - return m_stop_id; +void ThreadList::PopExpressionExecutionThread(lldb::tid_t tid) { + assert(m_expression_tid_stack.back() == tid); + m_expression_tid_stack.pop_back(); } -void -ThreadList::SetStopID (uint32_t stop_id) -{ - m_stop_id = stop_id; +uint32_t ThreadList::GetStopID() const { return m_stop_id; } + +void ThreadList::SetStopID(uint32_t stop_id) { m_stop_id = stop_id; } + +uint32_t ThreadList::GetSize(bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + + if (can_update) + m_process->UpdateThreadListIfNeeded(); + return m_threads.size(); } -uint32_t -ThreadList::GetSize (bool can_update) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +ThreadSP ThreadList::GetThreadAtIndex(uint32_t idx, bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - if (can_update) - m_process->UpdateThreadListIfNeeded(); - return m_threads.size(); + if (can_update) + m_process->UpdateThreadListIfNeeded(); + + ThreadSP thread_sp; + if (idx < m_threads.size()) + thread_sp = m_threads[idx]; + return thread_sp; } -ThreadSP -ThreadList::GetThreadAtIndex (uint32_t idx, bool can_update) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +ThreadSP ThreadList::FindThreadByID(lldb::tid_t tid, bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - if (can_update) - m_process->UpdateThreadListIfNeeded(); + if (can_update) + m_process->UpdateThreadListIfNeeded(); - ThreadSP thread_sp; - if (idx < m_threads.size()) - thread_sp = m_threads[idx]; - return thread_sp; + ThreadSP thread_sp; + uint32_t idx = 0; + const uint32_t num_threads = m_threads.size(); + for (idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetID() == tid) { + thread_sp = m_threads[idx]; + break; + } + } + return thread_sp; } -ThreadSP -ThreadList::FindThreadByID (lldb::tid_t tid, bool can_update) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +ThreadSP ThreadList::FindThreadByProtocolID(lldb::tid_t tid, bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - if (can_update) - m_process->UpdateThreadListIfNeeded(); + if (can_update) + m_process->UpdateThreadListIfNeeded(); - ThreadSP thread_sp; - uint32_t idx = 0; - const uint32_t num_threads = m_threads.size(); - for (idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetID() == tid) - { - thread_sp = m_threads[idx]; - break; - } + ThreadSP thread_sp; + uint32_t idx = 0; + const uint32_t num_threads = m_threads.size(); + for (idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetProtocolID() == tid) { + thread_sp = m_threads[idx]; + break; } - return thread_sp; + } + return thread_sp; } -ThreadSP -ThreadList::FindThreadByProtocolID (lldb::tid_t tid, bool can_update) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +ThreadSP ThreadList::RemoveThreadByID(lldb::tid_t tid, bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - if (can_update) - m_process->UpdateThreadListIfNeeded(); - - ThreadSP thread_sp; - uint32_t idx = 0; - const uint32_t num_threads = m_threads.size(); - for (idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetProtocolID() == tid) - { - thread_sp = m_threads[idx]; - break; - } + if (can_update) + m_process->UpdateThreadListIfNeeded(); + + ThreadSP thread_sp; + uint32_t idx = 0; + const uint32_t num_threads = m_threads.size(); + for (idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetID() == tid) { + thread_sp = m_threads[idx]; + m_threads.erase(m_threads.begin() + idx); + break; } - return thread_sp; + } + return thread_sp; } +ThreadSP ThreadList::RemoveThreadByProtocolID(lldb::tid_t tid, + bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); -ThreadSP -ThreadList::RemoveThreadByID (lldb::tid_t tid, bool can_update) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); + if (can_update) + m_process->UpdateThreadListIfNeeded(); - if (can_update) - m_process->UpdateThreadListIfNeeded(); - - ThreadSP thread_sp; - uint32_t idx = 0; - const uint32_t num_threads = m_threads.size(); - for (idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetID() == tid) - { - thread_sp = m_threads[idx]; - m_threads.erase(m_threads.begin()+idx); - break; - } + ThreadSP thread_sp; + uint32_t idx = 0; + const uint32_t num_threads = m_threads.size(); + for (idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetProtocolID() == tid) { + thread_sp = m_threads[idx]; + m_threads.erase(m_threads.begin() + idx); + break; } - return thread_sp; + } + return thread_sp; } -ThreadSP -ThreadList::RemoveThreadByProtocolID (lldb::tid_t tid, bool can_update) -{ +ThreadSP ThreadList::GetThreadSPForThreadPtr(Thread *thread_ptr) { + ThreadSP thread_sp; + if (thread_ptr) { std::lock_guard<std::recursive_mutex> guard(GetMutex()); - if (can_update) - m_process->UpdateThreadListIfNeeded(); - - ThreadSP thread_sp; uint32_t idx = 0; const uint32_t num_threads = m_threads.size(); - for (idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetProtocolID() == tid) - { - thread_sp = m_threads[idx]; - m_threads.erase(m_threads.begin()+idx); - break; - } + for (idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx].get() == thread_ptr) { + thread_sp = m_threads[idx]; + break; + } } - return thread_sp; -} - -ThreadSP -ThreadList::GetThreadSPForThreadPtr (Thread *thread_ptr) -{ - ThreadSP thread_sp; - if (thread_ptr) - { - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - - uint32_t idx = 0; - const uint32_t num_threads = m_threads.size(); - for (idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx].get() == thread_ptr) - { - thread_sp = m_threads[idx]; - break; - } - } + } + return thread_sp; +} + +ThreadSP ThreadList::FindThreadByIndexID(uint32_t index_id, bool can_update) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + + if (can_update) + m_process->UpdateThreadListIfNeeded(); + + ThreadSP thread_sp; + const uint32_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + if (m_threads[idx]->GetIndexID() == index_id) { + thread_sp = m_threads[idx]; + break; } - return thread_sp; + } + return thread_sp; } +bool ThreadList::ShouldStop(Event *event_ptr) { + // Running events should never stop, obviously... + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); -ThreadSP -ThreadList::FindThreadByIndexID (uint32_t index_id, bool can_update) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); + // The ShouldStop method of the threads can do a whole lot of work, + // figuring out whether the thread plan conditions are met. So we don't want + // to keep the ThreadList locked the whole time we are doing this. + // FIXME: It is possible that running code could cause new threads + // to be created. If that happens, we will miss asking them whether + // they should stop. This is not a big deal since we haven't had + // a chance to hang any interesting operations on those threads yet. - if (can_update) - m_process->UpdateThreadListIfNeeded(); + collection threads_copy; + { + // Scope for locker + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - ThreadSP thread_sp; - const uint32_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - if (m_threads[idx]->GetIndexID() == index_id) - { - thread_sp = m_threads[idx]; - break; - } + m_process->UpdateThreadListIfNeeded(); + for (lldb::ThreadSP thread_sp : m_threads) { + // This is an optimization... If we didn't let a thread run in between + // the previous stop and this + // one, we shouldn't have to consult it for ShouldStop. So just leave it + // off the list we are going to + // inspect. + // On Linux, if a thread-specific conditional breakpoint was hit, it won't + // necessarily be the thread + // that hit the breakpoint itself that evaluates the conditional + // expression, so the thread that hit + // the breakpoint could still be asked to stop, even though it hasn't been + // allowed to run since the + // previous stop. + if (thread_sp->GetTemporaryResumeState() != eStateSuspended || + thread_sp->IsStillAtLastBreakpointHit()) + threads_copy.push_back(thread_sp); } - return thread_sp; -} - -bool -ThreadList::ShouldStop (Event *event_ptr) -{ - // Running events should never stop, obviously... - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - // The ShouldStop method of the threads can do a whole lot of work, - // figuring out whether the thread plan conditions are met. So we don't want - // to keep the ThreadList locked the whole time we are doing this. - // FIXME: It is possible that running code could cause new threads - // to be created. If that happens, we will miss asking them whether - // they should stop. This is not a big deal since we haven't had - // a chance to hang any interesting operations on those threads yet. - - collection threads_copy; - { - // Scope for locker - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - - m_process->UpdateThreadListIfNeeded(); - for (lldb::ThreadSP thread_sp : m_threads) - { - // This is an optimization... If we didn't let a thread run in between the previous stop and this - // one, we shouldn't have to consult it for ShouldStop. So just leave it off the list we are going to - // inspect. - // On Linux, if a thread-specific conditional breakpoint was hit, it won't necessarily be the thread - // that hit the breakpoint itself that evaluates the conditional expression, so the thread that hit - // the breakpoint could still be asked to stop, even though it hasn't been allowed to run since the - // previous stop. - if (thread_sp->GetTemporaryResumeState () != eStateSuspended || thread_sp->IsStillAtLastBreakpointHit()) - threads_copy.push_back(thread_sp); - } - // It is possible the threads we were allowing to run all exited and then maybe the user interrupted - // or something, then fall back on looking at all threads: + // It is possible the threads we were allowing to run all exited and then + // maybe the user interrupted + // or something, then fall back on looking at all threads: - if (threads_copy.size() == 0) - threads_copy = m_threads; - } + if (threads_copy.size() == 0) + threads_copy = m_threads; + } + + collection::iterator pos, end = threads_copy.end(); - collection::iterator pos, end = threads_copy.end(); + if (log) { + log->PutCString(""); + log->Printf("ThreadList::%s: %" PRIu64 " threads, %" PRIu64 + " unsuspended threads", + __FUNCTION__, (uint64_t)m_threads.size(), + (uint64_t)threads_copy.size()); + } + bool did_anybody_stop_for_a_reason = false; + + // If the event is an Interrupt event, then we're going to stop no matter + // what. Otherwise, presume we won't stop. + bool should_stop = false; + if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) { if (log) - { - log->PutCString(""); - log->Printf ("ThreadList::%s: %" PRIu64 " threads, %" PRIu64 " unsuspended threads", - __FUNCTION__, - (uint64_t)m_threads.size(), - (uint64_t)threads_copy.size()); - } + log->Printf( + "ThreadList::%s handling interrupt event, should stop set to true", + __FUNCTION__); + + should_stop = true; + } + + // Now we run through all the threads and get their stop info's. We want to + // make sure to do this first before + // we start running the ShouldStop, because one thread's ShouldStop could + // destroy information (like deleting a + // thread specific breakpoint another thread had stopped at) which could lead + // us to compute the StopInfo incorrectly. + // We don't need to use it here, we just want to make sure it gets computed. + + for (pos = threads_copy.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + thread_sp->GetStopInfo(); + } + + for (pos = threads_copy.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + + // We should never get a stop for which no thread had a stop reason, but + // sometimes we do see this - + // for instance when we first connect to a remote stub. In that case we + // should stop, since we can't figure out + // the right thing to do and stopping gives the user control over what to do + // in this instance. + // + // Note, this causes a problem when you have a thread specific breakpoint, + // and a bunch of threads hit the breakpoint, + // but not the thread which we are waiting for. All the threads that are + // not "supposed" to hit the breakpoint + // are marked as having no stop reason, which is right, they should not show + // a stop reason. But that triggers this + // code and causes us to stop seemingly for no reason. + // + // Since the only way we ever saw this error was on first attach, I'm only + // going to trigger set did_anybody_stop_for_a_reason + // to true unless this is the first stop. + // + // If this becomes a problem, we'll have to have another StopReason like + // "StopInfoHidden" which will look invalid + // everywhere but at this check. + + if (thread_sp->GetProcess()->GetStopID() > 1) + did_anybody_stop_for_a_reason = true; + else + did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason(); - bool did_anybody_stop_for_a_reason = false; - - // If the event is an Interrupt event, then we're going to stop no matter what. Otherwise, presume we won't stop. - bool should_stop = false; - if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) - { - if (log) - log->Printf("ThreadList::%s handling interrupt event, should stop set to true", __FUNCTION__); - - should_stop = true; - } - - // Now we run through all the threads and get their stop info's. We want to make sure to do this first before - // we start running the ShouldStop, because one thread's ShouldStop could destroy information (like deleting a - // thread specific breakpoint another thread had stopped at) which could lead us to compute the StopInfo incorrectly. - // We don't need to use it here, we just want to make sure it gets computed. - - for (pos = threads_copy.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - thread_sp->GetStopInfo(); - } - - for (pos = threads_copy.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - - // We should never get a stop for which no thread had a stop reason, but sometimes we do see this - - // for instance when we first connect to a remote stub. In that case we should stop, since we can't figure out - // the right thing to do and stopping gives the user control over what to do in this instance. - // - // Note, this causes a problem when you have a thread specific breakpoint, and a bunch of threads hit the breakpoint, - // but not the thread which we are waiting for. All the threads that are not "supposed" to hit the breakpoint - // are marked as having no stop reason, which is right, they should not show a stop reason. But that triggers this - // code and causes us to stop seemingly for no reason. - // - // Since the only way we ever saw this error was on first attach, I'm only going to trigger set did_anybody_stop_for_a_reason - // to true unless this is the first stop. - // - // If this becomes a problem, we'll have to have another StopReason like "StopInfoHidden" which will look invalid - // everywhere but at this check. - - if (thread_sp->GetProcess()->GetStopID() > 1) - did_anybody_stop_for_a_reason = true; - else - did_anybody_stop_for_a_reason |= thread_sp->ThreadStoppedForAReason(); - - const bool thread_should_stop = thread_sp->ShouldStop(event_ptr); - if (thread_should_stop) - should_stop |= true; - } + const bool thread_should_stop = thread_sp->ShouldStop(event_ptr); + if (thread_should_stop) + should_stop |= true; + } - if (!should_stop && !did_anybody_stop_for_a_reason) - { - should_stop = true; - if (log) - log->Printf ("ThreadList::%s we stopped but no threads had a stop reason, overriding should_stop and stopping.", __FUNCTION__); - } - + if (!should_stop && !did_anybody_stop_for_a_reason) { + should_stop = true; if (log) - log->Printf ("ThreadList::%s overall should_stop = %i", __FUNCTION__, should_stop); - - if (should_stop) - { - for (pos = threads_copy.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - thread_sp->WillStop (); - } + log->Printf("ThreadList::%s we stopped but no threads had a stop reason, " + "overriding should_stop and stopping.", + __FUNCTION__); + } + + if (log) + log->Printf("ThreadList::%s overall should_stop = %i", __FUNCTION__, + should_stop); + + if (should_stop) { + for (pos = threads_copy.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + thread_sp->WillStop(); } + } - return should_stop; + return should_stop; } -Vote -ThreadList::ShouldReportStop (Event *event_ptr) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +Vote ThreadList::ShouldReportStop(Event *event_ptr) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - Vote result = eVoteNoOpinion; - m_process->UpdateThreadListIfNeeded(); - collection::iterator pos, end = m_threads.end(); + Vote result = eVoteNoOpinion; + m_process->UpdateThreadListIfNeeded(); + collection::iterator pos, end = m_threads.end(); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("ThreadList::%s %" PRIu64 " threads", __FUNCTION__, (uint64_t)m_threads.size()); - - // Run through the threads and ask whether we should report this event. - // For stopping, a YES vote wins over everything. A NO vote wins over NO opinion. - for (pos = m_threads.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - const Vote vote = thread_sp->ShouldReportStop (event_ptr); - switch (vote) - { - case eVoteNoOpinion: - continue; - - case eVoteYes: - result = eVoteYes; - break; - - case eVoteNo: - if (result == eVoteNoOpinion) - { - result = eVoteNo; - } - else - { - if (log) - log->Printf ("ThreadList::%s thread 0x%4.4" PRIx64 ": voted %s, but lost out because result was %s", - __FUNCTION__, - thread_sp->GetID (), - GetVoteAsCString (vote), - GetVoteAsCString (result)); - } - break; - } + if (log) + log->Printf("ThreadList::%s %" PRIu64 " threads", __FUNCTION__, + (uint64_t)m_threads.size()); + + // Run through the threads and ask whether we should report this event. + // For stopping, a YES vote wins over everything. A NO vote wins over NO + // opinion. + for (pos = m_threads.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + const Vote vote = thread_sp->ShouldReportStop(event_ptr); + switch (vote) { + case eVoteNoOpinion: + continue; + + case eVoteYes: + result = eVoteYes; + break; + + case eVoteNo: + if (result == eVoteNoOpinion) { + result = eVoteNo; + } else { + if (log) + log->Printf("ThreadList::%s thread 0x%4.4" PRIx64 + ": voted %s, but lost out because result was %s", + __FUNCTION__, thread_sp->GetID(), GetVoteAsCString(vote), + GetVoteAsCString(result)); + } + break; } - if (log) - log->Printf ("ThreadList::%s returning %s", __FUNCTION__, GetVoteAsCString (result)); - return result; + } + if (log) + log->Printf("ThreadList::%s returning %s", __FUNCTION__, + GetVoteAsCString(result)); + return result; } -void -ThreadList::SetShouldReportStop (Vote vote) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +void ThreadList::SetShouldReportStop(Vote vote) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); - collection::iterator pos, end = m_threads.end(); - for (pos = m_threads.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - thread_sp->SetShouldReportStop (vote); - } + m_process->UpdateThreadListIfNeeded(); + collection::iterator pos, end = m_threads.end(); + for (pos = m_threads.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + thread_sp->SetShouldReportStop(vote); + } } -Vote -ThreadList::ShouldReportRun (Event *event_ptr) -{ +Vote ThreadList::ShouldReportRun(Event *event_ptr) { - std::lock_guard<std::recursive_mutex> guard(GetMutex()); + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - Vote result = eVoteNoOpinion; - m_process->UpdateThreadListIfNeeded(); - collection::iterator pos, end = m_threads.end(); - - // Run through the threads and ask whether we should report this event. - // The rule is NO vote wins over everything, a YES vote wins over no opinion. - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - for (pos = m_threads.begin(); pos != end; ++pos) - { - if ((*pos)->GetResumeState () != eStateSuspended) - { - switch ((*pos)->ShouldReportRun (event_ptr)) - { - case eVoteNoOpinion: - continue; - case eVoteYes: - if (result == eVoteNoOpinion) - result = eVoteYes; - break; - case eVoteNo: - if (log) - log->Printf ("ThreadList::ShouldReportRun() thread %d (0x%4.4" PRIx64 ") says don't report.", - (*pos)->GetIndexID(), - (*pos)->GetID()); - result = eVoteNo; - break; - } - } + Vote result = eVoteNoOpinion; + m_process->UpdateThreadListIfNeeded(); + collection::iterator pos, end = m_threads.end(); + + // Run through the threads and ask whether we should report this event. + // The rule is NO vote wins over everything, a YES vote wins over no opinion. + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + for (pos = m_threads.begin(); pos != end; ++pos) { + if ((*pos)->GetResumeState() != eStateSuspended) { + switch ((*pos)->ShouldReportRun(event_ptr)) { + case eVoteNoOpinion: + continue; + case eVoteYes: + if (result == eVoteNoOpinion) + result = eVoteYes; + break; + case eVoteNo: + if (log) + log->Printf("ThreadList::ShouldReportRun() thread %d (0x%4.4" PRIx64 + ") says don't report.", + (*pos)->GetIndexID(), (*pos)->GetID()); + result = eVoteNo; + break; + } } - return result; + } + return result; } -void -ThreadList::Clear() -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_stop_id = 0; - m_threads.clear(); - m_selected_tid = LLDB_INVALID_THREAD_ID; +void ThreadList::Clear() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + m_stop_id = 0; + m_threads.clear(); + m_selected_tid = LLDB_INVALID_THREAD_ID; } -void -ThreadList::Destroy() -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - const uint32_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - m_threads[idx]->DestroyThread(); - } +void ThreadList::Destroy() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + const uint32_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + m_threads[idx]->DestroyThread(); + } } -void -ThreadList::RefreshStateAfterStop () -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); +void ThreadList::RefreshStateAfterStop() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("Turning off notification of new threads while single stepping a thread."); + m_process->UpdateThreadListIfNeeded(); - collection::iterator pos, end = m_threads.end(); - for (pos = m_threads.begin(); pos != end; ++pos) - (*pos)->RefreshStateAfterStop (); -} + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf("Turning off notification of new threads while single stepping " + "a thread."); -void -ThreadList::DiscardThreadPlans () -{ - // You don't need to update the thread list here, because only threads - // that you currently know about have any thread plans. - std::lock_guard<std::recursive_mutex> guard(GetMutex()); + collection::iterator pos, end = m_threads.end(); + for (pos = m_threads.begin(); pos != end; ++pos) + (*pos)->RefreshStateAfterStop(); +} - collection::iterator pos, end = m_threads.end(); - for (pos = m_threads.begin(); pos != end; ++pos) - (*pos)->DiscardThreadPlans (true); +void ThreadList::DiscardThreadPlans() { + // You don't need to update the thread list here, because only threads + // that you currently know about have any thread plans. + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + collection::iterator pos, end = m_threads.end(); + for (pos = m_threads.begin(); pos != end; ++pos) + (*pos)->DiscardThreadPlans(true); } -bool -ThreadList::WillResume () -{ - // Run through the threads and perform their momentary actions. - // But we only do this for threads that are running, user suspended - // threads stay where they are. +bool ThreadList::WillResume() { + // Run through the threads and perform their momentary actions. + // But we only do this for threads that are running, user suspended + // threads stay where they are. - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - m_process->UpdateThreadListIfNeeded(); + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + m_process->UpdateThreadListIfNeeded(); - collection::iterator pos, end = m_threads.end(); - - // See if any thread wants to run stopping others. If it does, then we won't - // setup the other threads for resume, since they aren't going to get a chance - // to run. This is necessary because the SetupForResume might add "StopOthers" - // plans which would then get to be part of the who-gets-to-run negotiation, but - // they're coming in after the fact, and the threads that are already set up should - // take priority. - - bool wants_solo_run = false; - - for (pos = m_threads.begin(); pos != end; ++pos) - { - lldbassert((*pos)->GetCurrentPlan() && "thread should not have null thread plan"); - if ((*pos)->GetResumeState() != eStateSuspended && - (*pos)->GetCurrentPlan()->StopOthers()) - { - if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread()) - continue; - wants_solo_run = true; - break; - } - } - - if (wants_solo_run) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("Turning on notification of new threads while single stepping a thread."); - m_process->StartNoticingNewThreads(); - } - else - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log && log->GetVerbose()) - log->Printf ("Turning off notification of new threads while single stepping a thread."); - m_process->StopNoticingNewThreads(); - } - - // Give all the threads that are likely to run a last chance to set up their state before we - // negotiate who is actually going to get a chance to run... - // Don't set to resume suspended threads, and if any thread wanted to stop others, only - // call setup on the threads that request StopOthers... - - for (pos = m_threads.begin(); pos != end; ++pos) - { - if ((*pos)->GetResumeState() != eStateSuspended - && (!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers())) - { - if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread()) - continue; - (*pos)->SetupForResume (); - } - } + collection::iterator pos, end = m_threads.end(); - // Now go through the threads and see if any thread wants to run just itself. - // if so then pick one and run it. - - ThreadList run_me_only_list (m_process); - - run_me_only_list.SetStopID(m_process->GetStopID()); - - bool run_only_current_thread = false; - - for (pos = m_threads.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - if (thread_sp->GetResumeState() != eStateSuspended && - thread_sp->GetCurrentPlan()->StopOthers()) - { - if ((*pos)->IsOperatingSystemPluginThread() && !(*pos)->GetBackingThread()) - continue; - - // You can't say "stop others" and also want yourself to be suspended. - assert (thread_sp->GetCurrentPlan()->RunState() != eStateSuspended); - - if (thread_sp == GetSelectedThread()) - { - // If the currently selected thread wants to run on its own, always let it. - run_only_current_thread = true; - run_me_only_list.Clear(); - run_me_only_list.AddThread (thread_sp); - break; - } - - run_me_only_list.AddThread (thread_sp); - } + // See if any thread wants to run stopping others. If it does, then we won't + // setup the other threads for resume, since they aren't going to get a chance + // to run. This is necessary because the SetupForResume might add + // "StopOthers" + // plans which would then get to be part of the who-gets-to-run negotiation, + // but + // they're coming in after the fact, and the threads that are already set up + // should + // take priority. + + bool wants_solo_run = false; + for (pos = m_threads.begin(); pos != end; ++pos) { + lldbassert((*pos)->GetCurrentPlan() && + "thread should not have null thread plan"); + if ((*pos)->GetResumeState() != eStateSuspended && + (*pos)->GetCurrentPlan()->StopOthers()) { + if ((*pos)->IsOperatingSystemPluginThread() && + !(*pos)->GetBackingThread()) + continue; + wants_solo_run = true; + break; } + } - bool need_to_resume = true; - - if (run_me_only_list.GetSize (false) == 0) - { - // Everybody runs as they wish: - for (pos = m_threads.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - StateType run_state; - if (thread_sp->GetResumeState() != eStateSuspended) - run_state = thread_sp->GetCurrentPlan()->RunState(); - else - run_state = eStateSuspended; - if (!thread_sp->ShouldResume(run_state)) - need_to_resume = false; - } + if (wants_solo_run) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf("Turning on notification of new threads while single " + "stepping a thread."); + m_process->StartNoticingNewThreads(); + } else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log && log->GetVerbose()) + log->Printf("Turning off notification of new threads while single " + "stepping a thread."); + m_process->StopNoticingNewThreads(); + } + + // Give all the threads that are likely to run a last chance to set up their + // state before we + // negotiate who is actually going to get a chance to run... + // Don't set to resume suspended threads, and if any thread wanted to stop + // others, only + // call setup on the threads that request StopOthers... + + for (pos = m_threads.begin(); pos != end; ++pos) { + if ((*pos)->GetResumeState() != eStateSuspended && + (!wants_solo_run || (*pos)->GetCurrentPlan()->StopOthers())) { + if ((*pos)->IsOperatingSystemPluginThread() && + !(*pos)->GetBackingThread()) + continue; + (*pos)->SetupForResume(); } - else - { - ThreadSP thread_to_run; + } - if (run_only_current_thread) - { - thread_to_run = GetSelectedThread(); - } - else if (run_me_only_list.GetSize (false) == 1) - { - thread_to_run = run_me_only_list.GetThreadAtIndex (0); - } - else - { - int random_thread = (int) - ((run_me_only_list.GetSize (false) * (double) rand ()) / (RAND_MAX + 1.0)); - thread_to_run = run_me_only_list.GetThreadAtIndex (random_thread); - } + // Now go through the threads and see if any thread wants to run just itself. + // if so then pick one and run it. - for (pos = m_threads.begin(); pos != end; ++pos) - { - ThreadSP thread_sp(*pos); - if (thread_sp == thread_to_run) - { - if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState())) - need_to_resume = false; - } - else - thread_sp->ShouldResume (eStateSuspended); - } - } + ThreadList run_me_only_list(m_process); - return need_to_resume; -} + run_me_only_list.SetStopID(m_process->GetStopID()); -void -ThreadList::DidResume () -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - collection::iterator pos, end = m_threads.end(); - for (pos = m_threads.begin(); pos != end; ++pos) - { - // Don't clear out threads that aren't going to get a chance to run, rather - // leave their state for the next time around. - ThreadSP thread_sp(*pos); - if (thread_sp->GetResumeState() != eStateSuspended) - thread_sp->DidResume (); - } -} + bool run_only_current_thread = false; -void -ThreadList::DidStop () -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - collection::iterator pos, end = m_threads.end(); - for (pos = m_threads.begin(); pos != end; ++pos) - { - // Notify threads that the process just stopped. - // Note, this currently assumes that all threads in the list - // stop when the process stops. In the future we will want to support - // a debugging model where some threads continue to run while others - // are stopped. We either need to handle that somehow here or - // create a special thread list containing only threads which will - // stop in the code that calls this method (currently - // Process::SetPrivateState). - ThreadSP thread_sp(*pos); - if (StateIsRunningState(thread_sp->GetState())) - thread_sp->DidStop (); + for (pos = m_threads.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + if (thread_sp->GetResumeState() != eStateSuspended && + thread_sp->GetCurrentPlan()->StopOthers()) { + if ((*pos)->IsOperatingSystemPluginThread() && + !(*pos)->GetBackingThread()) + continue; + + // You can't say "stop others" and also want yourself to be suspended. + assert(thread_sp->GetCurrentPlan()->RunState() != eStateSuspended); + + if (thread_sp == GetSelectedThread()) { + // If the currently selected thread wants to run on its own, always let + // it. + run_only_current_thread = true; + run_me_only_list.Clear(); + run_me_only_list.AddThread(thread_sp); + break; + } + + run_me_only_list.AddThread(thread_sp); + } + } + + bool need_to_resume = true; + + if (run_me_only_list.GetSize(false) == 0) { + // Everybody runs as they wish: + for (pos = m_threads.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + StateType run_state; + if (thread_sp->GetResumeState() != eStateSuspended) + run_state = thread_sp->GetCurrentPlan()->RunState(); + else + run_state = eStateSuspended; + if (!thread_sp->ShouldResume(run_state)) + need_to_resume = false; + } + } else { + ThreadSP thread_to_run; + + if (run_only_current_thread) { + thread_to_run = GetSelectedThread(); + } else if (run_me_only_list.GetSize(false) == 1) { + thread_to_run = run_me_only_list.GetThreadAtIndex(0); + } else { + int random_thread = + (int)((run_me_only_list.GetSize(false) * (double)rand()) / + (RAND_MAX + 1.0)); + thread_to_run = run_me_only_list.GetThreadAtIndex(random_thread); } -} -ThreadSP -ThreadList::GetSelectedThread () -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - ThreadSP thread_sp = FindThreadByID(m_selected_tid); - if (!thread_sp.get()) - { - if (m_threads.size() == 0) - return thread_sp; - m_selected_tid = m_threads[0]->GetID(); - thread_sp = m_threads[0]; + for (pos = m_threads.begin(); pos != end; ++pos) { + ThreadSP thread_sp(*pos); + if (thread_sp == thread_to_run) { + if (!thread_sp->ShouldResume(thread_sp->GetCurrentPlan()->RunState())) + need_to_resume = false; + } else + thread_sp->ShouldResume(eStateSuspended); } - return thread_sp; + } + + return need_to_resume; +} + +void ThreadList::DidResume() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + collection::iterator pos, end = m_threads.end(); + for (pos = m_threads.begin(); pos != end; ++pos) { + // Don't clear out threads that aren't going to get a chance to run, rather + // leave their state for the next time around. + ThreadSP thread_sp(*pos); + if (thread_sp->GetResumeState() != eStateSuspended) + thread_sp->DidResume(); + } +} + +void ThreadList::DidStop() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + collection::iterator pos, end = m_threads.end(); + for (pos = m_threads.begin(); pos != end; ++pos) { + // Notify threads that the process just stopped. + // Note, this currently assumes that all threads in the list + // stop when the process stops. In the future we will want to support + // a debugging model where some threads continue to run while others + // are stopped. We either need to handle that somehow here or + // create a special thread list containing only threads which will + // stop in the code that calls this method (currently + // Process::SetPrivateState). + ThreadSP thread_sp(*pos); + if (StateIsRunningState(thread_sp->GetState())) + thread_sp->DidStop(); + } +} + +ThreadSP ThreadList::GetSelectedThread() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + ThreadSP thread_sp = FindThreadByID(m_selected_tid); + if (!thread_sp.get()) { + if (m_threads.size() == 0) + return thread_sp; + m_selected_tid = m_threads[0]->GetID(); + thread_sp = m_threads[0]; + } + return thread_sp; +} + +bool ThreadList::SetSelectedThreadByID(lldb::tid_t tid, bool notify) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + ThreadSP selected_thread_sp(FindThreadByID(tid)); + if (selected_thread_sp) { + m_selected_tid = tid; + selected_thread_sp->SetDefaultFileAndLineToSelectedFrame(); + } else + m_selected_tid = LLDB_INVALID_THREAD_ID; + + if (notify) + NotifySelectedThreadChanged(m_selected_tid); + + return m_selected_tid != LLDB_INVALID_THREAD_ID; } -bool -ThreadList::SetSelectedThreadByID (lldb::tid_t tid, bool notify) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - ThreadSP selected_thread_sp(FindThreadByID(tid)); - if (selected_thread_sp) - { - m_selected_tid = tid; - selected_thread_sp->SetDefaultFileAndLineToSelectedFrame(); - } - else - m_selected_tid = LLDB_INVALID_THREAD_ID; +bool ThreadList::SetSelectedThreadByIndexID(uint32_t index_id, bool notify) { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + ThreadSP selected_thread_sp(FindThreadByIndexID(index_id)); + if (selected_thread_sp.get()) { + m_selected_tid = selected_thread_sp->GetID(); + selected_thread_sp->SetDefaultFileAndLineToSelectedFrame(); + } else + m_selected_tid = LLDB_INVALID_THREAD_ID; + + if (notify) + NotifySelectedThreadChanged(m_selected_tid); - if (notify) - NotifySelectedThreadChanged(m_selected_tid); - - return m_selected_tid != LLDB_INVALID_THREAD_ID; + return m_selected_tid != LLDB_INVALID_THREAD_ID; } -bool -ThreadList::SetSelectedThreadByIndexID (uint32_t index_id, bool notify) -{ - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - ThreadSP selected_thread_sp (FindThreadByIndexID(index_id)); - if (selected_thread_sp.get()) - { - m_selected_tid = selected_thread_sp->GetID(); - selected_thread_sp->SetDefaultFileAndLineToSelectedFrame(); - } - else - m_selected_tid = LLDB_INVALID_THREAD_ID; - - if (notify) - NotifySelectedThreadChanged(m_selected_tid); - - return m_selected_tid != LLDB_INVALID_THREAD_ID; -} - -void -ThreadList::NotifySelectedThreadChanged (lldb::tid_t tid) -{ - ThreadSP selected_thread_sp (FindThreadByID(tid)); - if (selected_thread_sp->EventTypeHasListeners(Thread::eBroadcastBitThreadSelected)) - selected_thread_sp->BroadcastEvent(Thread::eBroadcastBitThreadSelected, - new Thread::ThreadEventData(selected_thread_sp)); -} - -void -ThreadList::Update (ThreadList &rhs) -{ - if (this != &rhs) - { - // Lock both mutexes to make sure neither side changes anyone on us - // while the assignment occurs - std::lock_guard<std::recursive_mutex> guard(GetMutex()); - - m_process = rhs.m_process; - m_stop_id = rhs.m_stop_id; - m_threads.swap(rhs.m_threads); - m_selected_tid = rhs.m_selected_tid; - - - // Now we look for threads that we are done with and - // make sure to clear them up as much as possible so - // anyone with a shared pointer will still have a reference, - // but the thread won't be of much use. Using std::weak_ptr - // for all backward references (such as a thread to a process) - // will eventually solve this issue for us, but for now, we - // need to work around the issue - collection::iterator rhs_pos, rhs_end = rhs.m_threads.end(); - for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos) - { - const lldb::tid_t tid = (*rhs_pos)->GetID(); - bool thread_is_alive = false; - const uint32_t num_threads = m_threads.size(); - for (uint32_t idx = 0; idx < num_threads; ++idx) - { - ThreadSP backing_thread = m_threads[idx]->GetBackingThread(); - if (m_threads[idx]->GetID() == tid || (backing_thread && backing_thread->GetID() == tid)) - { - thread_is_alive = true; - break; - } - } - if (!thread_is_alive) - (*rhs_pos)->DestroyThread(); - } - } +void ThreadList::NotifySelectedThreadChanged(lldb::tid_t tid) { + ThreadSP selected_thread_sp(FindThreadByID(tid)); + if (selected_thread_sp->EventTypeHasListeners( + Thread::eBroadcastBitThreadSelected)) + selected_thread_sp->BroadcastEvent( + Thread::eBroadcastBitThreadSelected, + new Thread::ThreadEventData(selected_thread_sp)); } -void -ThreadList::Flush () -{ +void ThreadList::Update(ThreadList &rhs) { + if (this != &rhs) { + // Lock both mutexes to make sure neither side changes anyone on us + // while the assignment occurs std::lock_guard<std::recursive_mutex> guard(GetMutex()); - collection::iterator pos, end = m_threads.end(); - for (pos = m_threads.begin(); pos != end; ++pos) - (*pos)->Flush (); -} - -std::recursive_mutex & -ThreadList::GetMutex() -{ - return m_process->m_thread_mutex; -} - -ThreadList::ExpressionExecutionThreadPusher::ExpressionExecutionThreadPusher (lldb::ThreadSP thread_sp) : - m_thread_list(nullptr), - m_tid(LLDB_INVALID_THREAD_ID) -{ - if (thread_sp) - { - m_tid = thread_sp->GetID(); - m_thread_list = &thread_sp->GetProcess()->GetThreadList(); - m_thread_list->PushExpressionExecutionThread(m_tid); + + m_process = rhs.m_process; + m_stop_id = rhs.m_stop_id; + m_threads.swap(rhs.m_threads); + m_selected_tid = rhs.m_selected_tid; + + // Now we look for threads that we are done with and + // make sure to clear them up as much as possible so + // anyone with a shared pointer will still have a reference, + // but the thread won't be of much use. Using std::weak_ptr + // for all backward references (such as a thread to a process) + // will eventually solve this issue for us, but for now, we + // need to work around the issue + collection::iterator rhs_pos, rhs_end = rhs.m_threads.end(); + for (rhs_pos = rhs.m_threads.begin(); rhs_pos != rhs_end; ++rhs_pos) { + const lldb::tid_t tid = (*rhs_pos)->GetID(); + bool thread_is_alive = false; + const uint32_t num_threads = m_threads.size(); + for (uint32_t idx = 0; idx < num_threads; ++idx) { + ThreadSP backing_thread = m_threads[idx]->GetBackingThread(); + if (m_threads[idx]->GetID() == tid || + (backing_thread && backing_thread->GetID() == tid)) { + thread_is_alive = true; + break; + } + } + if (!thread_is_alive) + (*rhs_pos)->DestroyThread(); } + } } +void ThreadList::Flush() { + std::lock_guard<std::recursive_mutex> guard(GetMutex()); + collection::iterator pos, end = m_threads.end(); + for (pos = m_threads.begin(); pos != end; ++pos) + (*pos)->Flush(); +} + +std::recursive_mutex &ThreadList::GetMutex() { + return m_process->m_thread_mutex; +} +ThreadList::ExpressionExecutionThreadPusher::ExpressionExecutionThreadPusher( + lldb::ThreadSP thread_sp) + : m_thread_list(nullptr), m_tid(LLDB_INVALID_THREAD_ID) { + if (thread_sp) { + m_tid = thread_sp->GetID(); + m_thread_list = &thread_sp->GetProcess()->GetThreadList(); + m_thread_list->PushExpressionExecutionThread(m_tid); + } +} diff --git a/lldb/source/Target/ThreadPlan.cpp b/lldb/source/Target/ThreadPlan.cpp index f86d10dca34..6b997476d92 100644 --- a/lldb/source/Target/ThreadPlan.cpp +++ b/lldb/source/Target/ThreadPlan.cpp @@ -15,10 +15,10 @@ #include "lldb/Core/Debugger.h" #include "lldb/Core/Log.h" #include "lldb/Core/State.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" #include "lldb/Utility/ConvertEnum.h" using namespace lldb; @@ -27,21 +27,14 @@ using namespace lldb_private; //---------------------------------------------------------------------- // ThreadPlan constructor //---------------------------------------------------------------------- -ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vote stop_vote, Vote run_vote) - : m_thread(thread), - m_stop_vote(stop_vote), - m_run_vote(run_vote), - m_kind(kind), - m_name(name), - m_plan_complete_mutex(), - m_cached_plan_explains_stop(eLazyBoolCalculate), - m_plan_complete(false), - m_plan_private(false), - m_okay_to_discard(true), - m_is_master_plan(false), - m_plan_succeeded(true) -{ - SetID(GetNextID()); +ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, + Vote stop_vote, Vote run_vote) + : m_thread(thread), m_stop_vote(stop_vote), m_run_vote(run_vote), + m_kind(kind), m_name(name), m_plan_complete_mutex(), + m_cached_plan_explains_stop(eLazyBoolCalculate), m_plan_complete(false), + m_plan_private(false), m_okay_to_discard(true), m_is_master_plan(false), + m_plan_succeeded(true) { + SetID(GetNextID()); } //---------------------------------------------------------------------- @@ -49,306 +42,249 @@ ThreadPlan::ThreadPlan(ThreadPlanKind kind, const char *name, Thread &thread, Vo //---------------------------------------------------------------------- ThreadPlan::~ThreadPlan() = default; -bool -ThreadPlan::PlanExplainsStop (Event *event_ptr) -{ - if (m_cached_plan_explains_stop == eLazyBoolCalculate) - { - bool actual_value = DoPlanExplainsStop(event_ptr); - m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; - return actual_value; - } - else - { - return m_cached_plan_explains_stop == eLazyBoolYes; - } +bool ThreadPlan::PlanExplainsStop(Event *event_ptr) { + if (m_cached_plan_explains_stop == eLazyBoolCalculate) { + bool actual_value = DoPlanExplainsStop(event_ptr); + m_cached_plan_explains_stop = actual_value ? eLazyBoolYes : eLazyBoolNo; + return actual_value; + } else { + return m_cached_plan_explains_stop == eLazyBoolYes; + } } -bool -ThreadPlan::IsPlanComplete () -{ - std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); - return m_plan_complete; +bool ThreadPlan::IsPlanComplete() { + std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); + return m_plan_complete; } -void -ThreadPlan::SetPlanComplete (bool success) -{ - std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); - m_plan_complete = true; - m_plan_succeeded = success; +void ThreadPlan::SetPlanComplete(bool success) { + std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); + m_plan_complete = true; + m_plan_succeeded = success; } -bool -ThreadPlan::MischiefManaged () -{ - std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); - // Mark the plan is complete, but don't override the success flag. - m_plan_complete = true; - return true; +bool ThreadPlan::MischiefManaged() { + std::lock_guard<std::recursive_mutex> guard(m_plan_complete_mutex); + // Mark the plan is complete, but don't override the success flag. + m_plan_complete = true; + return true; } -Vote -ThreadPlan::ShouldReportStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if (m_stop_vote == eVoteNoOpinion) - { - ThreadPlan *prev_plan = GetPreviousPlan (); - if (prev_plan) - { - Vote prev_vote = prev_plan->ShouldReportStop (event_ptr); - if (log) - log->Printf ("ThreadPlan::ShouldReportStop() returning previous thread plan vote: %s", - GetVoteAsCString (prev_vote)); - return prev_vote; - } +Vote ThreadPlan::ShouldReportStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (m_stop_vote == eVoteNoOpinion) { + ThreadPlan *prev_plan = GetPreviousPlan(); + if (prev_plan) { + Vote prev_vote = prev_plan->ShouldReportStop(event_ptr); + if (log) + log->Printf("ThreadPlan::ShouldReportStop() returning previous thread " + "plan vote: %s", + GetVoteAsCString(prev_vote)); + return prev_vote; } - if (log) - log->Printf ("ThreadPlan::ShouldReportStop() returning vote: %s", GetVoteAsCString (m_stop_vote)); - return m_stop_vote; + } + if (log) + log->Printf("ThreadPlan::ShouldReportStop() returning vote: %s", + GetVoteAsCString(m_stop_vote)); + return m_stop_vote; } -Vote -ThreadPlan::ShouldReportRun (Event *event_ptr) -{ - if (m_run_vote == eVoteNoOpinion) - { - ThreadPlan *prev_plan = GetPreviousPlan (); - if (prev_plan) - return prev_plan->ShouldReportRun (event_ptr); - } - return m_run_vote; +Vote ThreadPlan::ShouldReportRun(Event *event_ptr) { + if (m_run_vote == eVoteNoOpinion) { + ThreadPlan *prev_plan = GetPreviousPlan(); + if (prev_plan) + return prev_plan->ShouldReportRun(event_ptr); + } + return m_run_vote; } -bool -ThreadPlan::StopOthers () -{ - ThreadPlan *prev_plan; - prev_plan = GetPreviousPlan (); - return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); +bool ThreadPlan::StopOthers() { + ThreadPlan *prev_plan; + prev_plan = GetPreviousPlan(); + return (prev_plan == nullptr) ? false : prev_plan->StopOthers(); } -void -ThreadPlan::SetStopOthers (bool new_value) -{ - // SetStopOthers doesn't work up the hierarchy. You have to set the - // explicit ThreadPlan you want to affect. +void ThreadPlan::SetStopOthers(bool new_value) { + // SetStopOthers doesn't work up the hierarchy. You have to set the + // explicit ThreadPlan you want to affect. } -bool -ThreadPlan::WillResume (StateType resume_state, bool current_plan) -{ - m_cached_plan_explains_stop = eLazyBoolCalculate; - - if (current_plan) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if (log) - { - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); - assert (reg_ctx); - addr_t pc = reg_ctx->GetPC(); - addr_t sp = reg_ctx->GetSP(); - addr_t fp = reg_ctx->GetFP(); - log->Printf("%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " - "plan = '%s', state = %s, stop others = %d", - __FUNCTION__, m_thread.GetIndexID(), - static_cast<void*>(&m_thread), m_thread.GetID(), - static_cast<uint64_t>(pc), static_cast<uint64_t>(sp), - static_cast<uint64_t>(fp), m_name.c_str(), - StateAsCString(resume_state), StopOthers()); - } +bool ThreadPlan::WillResume(StateType resume_state, bool current_plan) { + m_cached_plan_explains_stop = eLazyBoolCalculate; + + if (current_plan) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (log) { + RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + assert(reg_ctx); + addr_t pc = reg_ctx->GetPC(); + addr_t sp = reg_ctx->GetSP(); + addr_t fp = reg_ctx->GetFP(); + log->Printf( + "%s Thread #%u (0x%p): tid = 0x%4.4" PRIx64 ", pc = 0x%8.8" PRIx64 + ", sp = 0x%8.8" PRIx64 ", fp = 0x%8.8" PRIx64 ", " + "plan = '%s', state = %s, stop others = %d", + __FUNCTION__, m_thread.GetIndexID(), static_cast<void *>(&m_thread), + m_thread.GetID(), static_cast<uint64_t>(pc), + static_cast<uint64_t>(sp), static_cast<uint64_t>(fp), m_name.c_str(), + StateAsCString(resume_state), StopOthers()); } - return DoWillResume (resume_state, current_plan); + } + return DoWillResume(resume_state, current_plan); } -lldb::user_id_t -ThreadPlan::GetNextID() -{ - static uint32_t g_nextPlanID = 0; - return ++g_nextPlanID; +lldb::user_id_t ThreadPlan::GetNextID() { + static uint32_t g_nextPlanID = 0; + return ++g_nextPlanID; } -void -ThreadPlan::DidPush() -{ -} +void ThreadPlan::DidPush() {} -void -ThreadPlan::WillPop() -{ -} +void ThreadPlan::WillPop() {} -bool -ThreadPlan::OkayToDiscard() -{ - return IsMasterPlan() ? m_okay_to_discard : true; +bool ThreadPlan::OkayToDiscard() { + return IsMasterPlan() ? m_okay_to_discard : true; } -lldb::StateType -ThreadPlan::RunState () -{ - if (m_tracer_sp && m_tracer_sp->TracingEnabled() && m_tracer_sp->SingleStepEnabled()) - return eStateStepping; - else - return GetPlanRunState(); +lldb::StateType ThreadPlan::RunState() { + if (m_tracer_sp && m_tracer_sp->TracingEnabled() && + m_tracer_sp->SingleStepEnabled()) + return eStateStepping; + else + return GetPlanRunState(); } -bool -ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) -{ - switch (reason) - { - case eStopReasonWatchpoint: - case eStopReasonSignal: - case eStopReasonException: - case eStopReasonExec: - case eStopReasonThreadExiting: - case eStopReasonInstrumentation: - return true; - default: - return false; - } +bool ThreadPlan::IsUsuallyUnexplainedStopReason(lldb::StopReason reason) { + switch (reason) { + case eStopReasonWatchpoint: + case eStopReasonSignal: + case eStopReasonException: + case eStopReasonExec: + case eStopReasonThreadExiting: + case eStopReasonInstrumentation: + return true; + default: + return false; + } } //---------------------------------------------------------------------- // ThreadPlanNull //---------------------------------------------------------------------- -ThreadPlanNull::ThreadPlanNull (Thread &thread) : - ThreadPlan (ThreadPlan::eKindNull, - "Null Thread Plan", - thread, - eVoteNoOpinion, - eVoteNoOpinion) -{ -} +ThreadPlanNull::ThreadPlanNull(Thread &thread) + : ThreadPlan(ThreadPlan::eKindNull, "Null Thread Plan", thread, + eVoteNoOpinion, eVoteNoOpinion) {} ThreadPlanNull::~ThreadPlanNull() = default; -void -ThreadPlanNull::GetDescription (Stream *s, - lldb::DescriptionLevel level) -{ - s->PutCString("Null thread plan - thread has been destroyed."); +void ThreadPlanNull::GetDescription(Stream *s, lldb::DescriptionLevel level) { + s->PutCString("Null thread plan - thread has been destroyed."); } -bool -ThreadPlanNull::ValidatePlan (Stream *error) -{ +bool ThreadPlanNull::ValidatePlan(Stream *error) { #ifdef LLDB_CONFIGURATION_DEBUG - fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + fprintf(stderr, + "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), + m_thread.GetProtocolID()); #endif - return true; + return true; } -bool -ThreadPlanNull::ShouldStop (Event *event_ptr) -{ +bool ThreadPlanNull::ShouldStop(Event *event_ptr) { #ifdef LLDB_CONFIGURATION_DEBUG - fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + fprintf(stderr, + "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), + m_thread.GetProtocolID()); #endif - return true; + return true; } -bool -ThreadPlanNull::WillStop () -{ +bool ThreadPlanNull::WillStop() { #ifdef LLDB_CONFIGURATION_DEBUG - fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + fprintf(stderr, + "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), + m_thread.GetProtocolID()); #endif - return true; + return true; } -bool -ThreadPlanNull::DoPlanExplainsStop (Event *event_ptr) -{ +bool ThreadPlanNull::DoPlanExplainsStop(Event *event_ptr) { #ifdef LLDB_CONFIGURATION_DEBUG - fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + fprintf(stderr, + "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), + m_thread.GetProtocolID()); #endif - return true; + return true; } // The null plan is never done. -bool -ThreadPlanNull::MischiefManaged () -{ - // The null plan is never done. +bool ThreadPlanNull::MischiefManaged() { +// The null plan is never done. #ifdef LLDB_CONFIGURATION_DEBUG - fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + fprintf(stderr, + "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), + m_thread.GetProtocolID()); #endif - return false; + return false; } -lldb::StateType -ThreadPlanNull::GetPlanRunState () -{ - // Not sure what to return here. This is a dead thread. +lldb::StateType ThreadPlanNull::GetPlanRunState() { +// Not sure what to return here. This is a dead thread. #ifdef LLDB_CONFIGURATION_DEBUG - fprintf(stderr, "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + fprintf(stderr, + "error: %s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), m_thread.GetProtocolID()); #else - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 ", ptid = 0x%" PRIx64 ")", - LLVM_PRETTY_FUNCTION, - m_thread.GetID(), - m_thread.GetProtocolID()); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Error("%s called on thread that has been destroyed (tid = 0x%" PRIx64 + ", ptid = 0x%" PRIx64 ")", + LLVM_PRETTY_FUNCTION, m_thread.GetID(), + m_thread.GetProtocolID()); #endif - return eStateRunning; + return eStateRunning; } diff --git a/lldb/source/Target/ThreadPlanBase.cpp b/lldb/source/Target/ThreadPlanBase.cpp index d70afae5557..f290483e904 100644 --- a/lldb/source/Target/ThreadPlanBase.cpp +++ b/lldb/source/Target/ThreadPlanBase.cpp @@ -14,10 +14,10 @@ // Other libraries and framework includes // Project includes // -#include "lldb/Breakpoint/StoppointCallbackContext.h" -#include "lldb/Breakpoint/BreakpointSite.h" -#include "lldb/Breakpoint/BreakpointLocation.h" #include "lldb/Breakpoint/Breakpoint.h" +#include "lldb/Breakpoint/BreakpointLocation.h" +#include "lldb/Breakpoint/BreakpointSite.h" +#include "lldb/Breakpoint/StoppointCallbackContext.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" #include "lldb/Target/Process.h" @@ -33,205 +33,180 @@ using namespace lldb_private; // FIXME: The "signal handling" policies should probably go here. //---------------------------------------------------------------------- -ThreadPlanBase::ThreadPlanBase (Thread &thread) : - ThreadPlan(ThreadPlan::eKindBase, "base plan", thread, eVoteYes, eVoteNoOpinion) -{ - // Set the tracer to a default tracer. - // FIXME: need to add a thread settings variable to pix various tracers... +ThreadPlanBase::ThreadPlanBase(Thread &thread) + : ThreadPlan(ThreadPlan::eKindBase, "base plan", thread, eVoteYes, + eVoteNoOpinion) { +// Set the tracer to a default tracer. +// FIXME: need to add a thread settings variable to pix various tracers... #define THREAD_PLAN_USE_ASSEMBLY_TRACER 1 #ifdef THREAD_PLAN_USE_ASSEMBLY_TRACER - ThreadPlanTracerSP new_tracer_sp (new ThreadPlanAssemblyTracer (m_thread)); + ThreadPlanTracerSP new_tracer_sp(new ThreadPlanAssemblyTracer(m_thread)); #else - ThreadPlanTracerSP new_tracer_sp (new ThreadPlanTracer (m_thread)); + ThreadPlanTracerSP new_tracer_sp(new ThreadPlanTracer(m_thread)); #endif - new_tracer_sp->EnableTracing (m_thread.GetTraceEnabledState()); - SetThreadPlanTracer(new_tracer_sp); - SetIsMasterPlan (true); + new_tracer_sp->EnableTracing(m_thread.GetTraceEnabledState()); + SetThreadPlanTracer(new_tracer_sp); + SetIsMasterPlan(true); } -ThreadPlanBase::~ThreadPlanBase () -{ +ThreadPlanBase::~ThreadPlanBase() {} +void ThreadPlanBase::GetDescription(Stream *s, lldb::DescriptionLevel level) { + s->Printf("Base thread plan."); } -void -ThreadPlanBase::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - s->Printf ("Base thread plan."); -} +bool ThreadPlanBase::ValidatePlan(Stream *error) { return true; } -bool -ThreadPlanBase::ValidatePlan (Stream *error) -{ +bool ThreadPlanBase::DoPlanExplainsStop(Event *event_ptr) { + // The base plan should defer to its tracer, since by default it + // always handles the stop. + if (TracerExplainsStop()) + return false; + else return true; } -bool -ThreadPlanBase::DoPlanExplainsStop (Event *event_ptr) -{ - // The base plan should defer to its tracer, since by default it - // always handles the stop. - if (TracerExplainsStop()) - return false; +Vote ThreadPlanBase::ShouldReportStop(Event *event_ptr) { + StopInfoSP stop_info_sp = m_thread.GetStopInfo(); + if (stop_info_sp) { + bool should_notify = stop_info_sp->ShouldNotify(event_ptr); + if (should_notify) + return eVoteYes; else - return true; + return eVoteNoOpinion; + } else + return eVoteNoOpinion; } -Vote -ThreadPlanBase::ShouldReportStop(Event *event_ptr) -{ - StopInfoSP stop_info_sp = m_thread.GetStopInfo (); - if (stop_info_sp) - { - bool should_notify = stop_info_sp->ShouldNotify(event_ptr); - if (should_notify) - return eVoteYes; +bool ThreadPlanBase::ShouldStop(Event *event_ptr) { + m_stop_vote = eVoteYes; + m_run_vote = eVoteYes; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + switch (reason) { + case eStopReasonInvalid: + case eStopReasonNone: + // This + m_run_vote = eVoteNoOpinion; + m_stop_vote = eVoteNo; + return false; + + case eStopReasonBreakpoint: + case eStopReasonWatchpoint: + if (stop_info_sp->ShouldStopSynchronous(event_ptr)) { + // If we are going to stop for a breakpoint, then unship the other plans + // at this point. Don't force the discard, however, so Master plans can + // stay + // in place if they want to. + if (log) + log->Printf( + "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 + " (breakpoint hit.)", + m_thread.GetID()); + m_thread.DiscardThreadPlans(false); + return true; + } + // If we aren't going to stop at this breakpoint, and it is internal, + // don't report this stop or the subsequent running event. + // Otherwise we will post the stopped & running, but the stopped event + // will get marked + // with "restarted" so the UI will know to wait and expect the consequent + // "running". + if (stop_info_sp->ShouldNotify(event_ptr)) { + m_stop_vote = eVoteYes; + m_run_vote = eVoteYes; + } else { + m_stop_vote = eVoteNo; + m_run_vote = eVoteNo; + } + return false; + + // TODO: the break below was missing, was this intentional??? If so + // please mention it + break; + + case eStopReasonException: + // If we crashed, discard thread plans and stop. Don't force the discard, + // however, + // since on rerun the target may clean up this exception and continue + // normally from there. + if (log) + log->Printf( + "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 + " (exception: %s)", + m_thread.GetID(), stop_info_sp->GetDescription()); + m_thread.DiscardThreadPlans(false); + return true; + + case eStopReasonExec: + // If we crashed, discard thread plans and stop. Don't force the discard, + // however, + // since on rerun the target may clean up this exception and continue + // normally from there. + if (log) + log->Printf( + "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 + " (exec.)", + m_thread.GetID()); + m_thread.DiscardThreadPlans(false); + return true; + + case eStopReasonThreadExiting: + case eStopReasonSignal: + if (stop_info_sp->ShouldStop(event_ptr)) { + if (log) + log->Printf( + "Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 + " (signal: %s)", + m_thread.GetID(), stop_info_sp->GetDescription()); + m_thread.DiscardThreadPlans(false); + return true; + } else { + // We're not going to stop, but while we are here, let's figure out + // whether to report this. + if (stop_info_sp->ShouldNotify(event_ptr)) + m_stop_vote = eVoteYes; else - return eVoteNoOpinion; - } - else - return eVoteNoOpinion; -} + m_stop_vote = eVoteNo; + } + return false; -bool -ThreadPlanBase::ShouldStop (Event *event_ptr) -{ - m_stop_vote = eVoteYes; - m_run_vote = eVoteYes; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason (); - switch (reason) - { - case eStopReasonInvalid: - case eStopReasonNone: - // This - m_run_vote = eVoteNoOpinion; - m_stop_vote = eVoteNo; - return false; - - case eStopReasonBreakpoint: - case eStopReasonWatchpoint: - if (stop_info_sp->ShouldStopSynchronous(event_ptr)) - { - // If we are going to stop for a breakpoint, then unship the other plans - // at this point. Don't force the discard, however, so Master plans can stay - // in place if they want to. - if (log) - log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (breakpoint hit.)", m_thread.GetID()); - m_thread.DiscardThreadPlans(false); - return true; - } - // If we aren't going to stop at this breakpoint, and it is internal, - // don't report this stop or the subsequent running event. - // Otherwise we will post the stopped & running, but the stopped event will get marked - // with "restarted" so the UI will know to wait and expect the consequent "running". - if (stop_info_sp->ShouldNotify (event_ptr)) - { - m_stop_vote = eVoteYes; - m_run_vote = eVoteYes; - } - else - { - m_stop_vote = eVoteNo; - m_run_vote = eVoteNo; - } - return false; - - // TODO: the break below was missing, was this intentional??? If so - // please mention it - break; - - case eStopReasonException: - // If we crashed, discard thread plans and stop. Don't force the discard, however, - // since on rerun the target may clean up this exception and continue normally from there. - if (log) - log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exception: %s)", m_thread.GetID(), stop_info_sp->GetDescription()); - m_thread.DiscardThreadPlans(false); - return true; - - case eStopReasonExec: - // If we crashed, discard thread plans and stop. Don't force the discard, however, - // since on rerun the target may clean up this exception and continue normally from there. - if (log) - log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (exec.)", m_thread.GetID()); - m_thread.DiscardThreadPlans(false); - return true; - - case eStopReasonThreadExiting: - case eStopReasonSignal: - if (stop_info_sp->ShouldStop(event_ptr)) - { - if (log) - log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal: %s)", m_thread.GetID(), stop_info_sp->GetDescription()); - m_thread.DiscardThreadPlans(false); - return true; - } - else - { - // We're not going to stop, but while we are here, let's figure out - // whether to report this. - if (stop_info_sp->ShouldNotify(event_ptr)) - m_stop_vote = eVoteYes; - else - m_stop_vote = eVoteNo; - } - return false; - - default: - return true; - } - - } - else - { - m_run_vote = eVoteNoOpinion; - m_stop_vote = eVoteNo; + default: + return true; } - // If there's no explicit reason to stop, then we will continue. - return false; -} + } else { + m_run_vote = eVoteNoOpinion; + m_stop_vote = eVoteNo; + } -bool -ThreadPlanBase::StopOthers () -{ - return false; + // If there's no explicit reason to stop, then we will continue. + return false; } -StateType -ThreadPlanBase::GetPlanRunState () -{ - return eStateRunning; -} +bool ThreadPlanBase::StopOthers() { return false; } -bool -ThreadPlanBase::WillStop () -{ - return true; -} +StateType ThreadPlanBase::GetPlanRunState() { return eStateRunning; } -bool -ThreadPlanBase::DoWillResume (lldb::StateType resume_state, bool current_plan) -{ - // Reset these to the default values so we don't set them wrong, then not get asked - // for a while, then return the wrong answer. - m_run_vote = eVoteNoOpinion; - m_stop_vote = eVoteNo; - return true; -} +bool ThreadPlanBase::WillStop() { return true; } +bool ThreadPlanBase::DoWillResume(lldb::StateType resume_state, + bool current_plan) { + // Reset these to the default values so we don't set them wrong, then not get + // asked + // for a while, then return the wrong answer. + m_run_vote = eVoteNoOpinion; + m_stop_vote = eVoteNo; + return true; +} // The base plan is never done. -bool -ThreadPlanBase::MischiefManaged () -{ - // The base plan is never done. - return false; +bool ThreadPlanBase::MischiefManaged() { + // The base plan is never done. + return false; } - diff --git a/lldb/source/Target/ThreadPlanCallFunction.cpp b/lldb/source/Target/ThreadPlanCallFunction.cpp index 01ca1267dd9..f9efb272fe0 100644 --- a/lldb/source/Target/ThreadPlanCallFunction.cpp +++ b/lldb/source/Target/ThreadPlanCallFunction.cpp @@ -34,555 +34,482 @@ using namespace lldb_private; //---------------------------------------------------------------------- // ThreadPlanCallFunction: Plan to call a single function //---------------------------------------------------------------------- -bool -ThreadPlanCallFunction::ConstructorSetup (Thread &thread, - ABI *& abi, - lldb::addr_t &start_load_addr, - lldb::addr_t &function_load_addr) -{ - SetIsMasterPlan (true); - SetOkayToDiscard (false); - SetPrivate (true); - - ProcessSP process_sp (thread.GetProcess()); - if (!process_sp) - return false; +bool ThreadPlanCallFunction::ConstructorSetup( + Thread &thread, ABI *&abi, lldb::addr_t &start_load_addr, + lldb::addr_t &function_load_addr) { + SetIsMasterPlan(true); + SetOkayToDiscard(false); + SetPrivate(true); + + ProcessSP process_sp(thread.GetProcess()); + if (!process_sp) + return false; - abi = process_sp->GetABI().get(); + abi = process_sp->GetABI().get(); - if (!abi) - return false; + if (!abi) + return false; - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP)); - SetBreakpoints(); + SetBreakpoints(); - m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize(); - // If we can't read memory at the point of the process where we are planning to put our function, we're - // not going to get any further... - Error error; - process_sp->ReadUnsignedIntegerFromMemory(m_function_sp, 4, 0, error); - if (!error.Success()) - { - m_constructor_errors.Printf ("Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".", m_function_sp); - if (log) - log->Printf ("ThreadPlanCallFunction(%p): %s.", - static_cast<void*>(this), - m_constructor_errors.GetData()); - return false; - } + m_function_sp = thread.GetRegisterContext()->GetSP() - abi->GetRedZoneSize(); + // If we can't read memory at the point of the process where we are planning + // to put our function, we're + // not going to get any further... + Error error; + process_sp->ReadUnsignedIntegerFromMemory(m_function_sp, 4, 0, error); + if (!error.Success()) { + m_constructor_errors.Printf( + "Trying to put the stack in unreadable memory at: 0x%" PRIx64 ".", + m_function_sp); + if (log) + log->Printf("ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this), + m_constructor_errors.GetData()); + return false; + } - Module *exe_module = GetTarget().GetExecutableModulePointer(); + Module *exe_module = GetTarget().GetExecutableModulePointer(); - if (exe_module == nullptr) - { - m_constructor_errors.Printf ("Can't execute code without an executable module."); - if (log) - log->Printf ("ThreadPlanCallFunction(%p): %s.", - static_cast<void*>(this), - m_constructor_errors.GetData()); - return false; + if (exe_module == nullptr) { + m_constructor_errors.Printf( + "Can't execute code without an executable module."); + if (log) + log->Printf("ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this), + m_constructor_errors.GetData()); + return false; + } else { + ObjectFile *objectFile = exe_module->GetObjectFile(); + if (!objectFile) { + m_constructor_errors.Printf( + "Could not find object file for module \"%s\".", + exe_module->GetFileSpec().GetFilename().AsCString()); + + if (log) + log->Printf("ThreadPlanCallFunction(%p): %s.", + static_cast<void *>(this), m_constructor_errors.GetData()); + return false; } - else - { - ObjectFile *objectFile = exe_module->GetObjectFile(); - if (!objectFile) - { - m_constructor_errors.Printf ("Could not find object file for module \"%s\".", - exe_module->GetFileSpec().GetFilename().AsCString()); - - if (log) - log->Printf ("ThreadPlanCallFunction(%p): %s.", - static_cast<void*>(this), - m_constructor_errors.GetData()); - return false; - } - m_start_addr = objectFile->GetEntryPointAddress(); - if (!m_start_addr.IsValid()) - { - m_constructor_errors.Printf ("Could not find entry point address for executable module \"%s\".", - exe_module->GetFileSpec().GetFilename().AsCString()); - if (log) - log->Printf ("ThreadPlanCallFunction(%p): %s.", - static_cast<void*>(this), - m_constructor_errors.GetData()); - return false; - } + m_start_addr = objectFile->GetEntryPointAddress(); + if (!m_start_addr.IsValid()) { + m_constructor_errors.Printf( + "Could not find entry point address for executable module \"%s\".", + exe_module->GetFileSpec().GetFilename().AsCString()); + if (log) + log->Printf("ThreadPlanCallFunction(%p): %s.", + static_cast<void *>(this), m_constructor_errors.GetData()); + return false; } + } - start_load_addr = m_start_addr.GetLoadAddress (&GetTarget()); + start_load_addr = m_start_addr.GetLoadAddress(&GetTarget()); - // Checkpoint the thread state so we can restore it later. - if (log && log->GetVerbose()) - ReportRegisterState ("About to checkpoint thread before function call. Original register state was:"); + // Checkpoint the thread state so we can restore it later. + if (log && log->GetVerbose()) + ReportRegisterState("About to checkpoint thread before function call. " + "Original register state was:"); - if (!thread.CheckpointThreadState (m_stored_thread_state)) - { - m_constructor_errors.Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state."); - if (log) - log->Printf ("ThreadPlanCallFunction(%p): %s.", - static_cast<void*>(this), - m_constructor_errors.GetData()); - return false; - } - function_load_addr = m_function_addr.GetLoadAddress (&GetTarget()); + if (!thread.CheckpointThreadState(m_stored_thread_state)) { + m_constructor_errors.Printf("Setting up ThreadPlanCallFunction, failed to " + "checkpoint thread state."); + if (log) + log->Printf("ThreadPlanCallFunction(%p): %s.", static_cast<void *>(this), + m_constructor_errors.GetData()); + return false; + } + function_load_addr = m_function_addr.GetLoadAddress(&GetTarget()); - return true; + return true; } -ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread, - const Address &function, - const CompilerType &return_type, - llvm::ArrayRef<addr_t> args, - const EvaluateExpressionOptions &options) : - ThreadPlan (ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_valid (false), - m_stop_other_threads (options.GetStopOthers()), - m_unwind_on_error (options.DoesUnwindOnError()), - m_ignore_breakpoints (options.DoesIgnoreBreakpoints()), - m_debug_execution (options.GetDebug()), - m_trap_exceptions (options.GetTrapExceptions()), - m_function_addr (function), - m_function_sp (0), - m_takedown_done (false), - m_should_clear_objc_exception_bp(false), - m_should_clear_cxx_exception_bp (false), - m_stop_address (LLDB_INVALID_ADDRESS), - m_return_type (return_type) -{ - lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; - lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; - ABI *abi = nullptr; - - if (!ConstructorSetup (thread, abi, start_load_addr, function_load_addr)) - return; - - if (!abi->PrepareTrivialCall(thread, - m_function_sp, - function_load_addr, - start_load_addr, - args)) - return; - - ReportRegisterState ("Function call was set up. Register state was:"); - - m_valid = true; +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, const CompilerType &return_type, + llvm::ArrayRef<addr_t> args, const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; + + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; + + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + start_load_addr, args)) + return; + + ReportRegisterState("Function call was set up. Register state was:"); + + m_valid = true; } -ThreadPlanCallFunction::ThreadPlanCallFunction(Thread &thread, - const Address &function, - const EvaluateExpressionOptions &options) : - ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_valid(false), - m_stop_other_threads(options.GetStopOthers()), - m_unwind_on_error(options.DoesUnwindOnError()), - m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), - m_debug_execution(options.GetDebug()), - m_trap_exceptions(options.GetTrapExceptions()), - m_function_addr(function), - m_function_sp(0), - m_takedown_done(false), - m_should_clear_objc_exception_bp(false), - m_should_clear_cxx_exception_bp(false), - m_stop_address(LLDB_INVALID_ADDRESS), - m_return_type(CompilerType()) -{ +ThreadPlanCallFunction::ThreadPlanCallFunction( + Thread &thread, const Address &function, + const EvaluateExpressionOptions &options) + : ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_valid(false), m_stop_other_threads(options.GetStopOthers()), + m_unwind_on_error(options.DoesUnwindOnError()), + m_ignore_breakpoints(options.DoesIgnoreBreakpoints()), + m_debug_execution(options.GetDebug()), + m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function), + m_function_sp(0), m_takedown_done(false), + m_should_clear_objc_exception_bp(false), + m_should_clear_cxx_exception_bp(false), + m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(CompilerType()) {} + +ThreadPlanCallFunction::~ThreadPlanCallFunction() { + DoTakedown(PlanSucceeded()); } -ThreadPlanCallFunction::~ThreadPlanCallFunction () -{ - DoTakedown(PlanSucceeded()); -} +void ThreadPlanCallFunction::ReportRegisterState(const char *message) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP | + LIBLLDB_LOG_VERBOSE)); + if (log) { + StreamString strm; + RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); -void -ThreadPlanCallFunction::ReportRegisterState (const char *message) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_VERBOSE)); - if (log) - { - StreamString strm; - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); - - log->PutCString(message); - - RegisterValue reg_value; - - for (uint32_t reg_idx = 0, num_registers = reg_ctx->GetRegisterCount(); - reg_idx < num_registers; - ++reg_idx) - { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex (reg_idx); - if (reg_ctx->ReadRegister(reg_info, reg_value)) - { - reg_value.Dump(&strm, reg_info, true, false, eFormatDefault); - strm.EOL(); - } - } - log->PutCString(strm.GetData()); - } -} + log->PutCString(message); -void -ThreadPlanCallFunction::DoTakedown (bool success) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); + RegisterValue reg_value; - if (!m_valid) - { - //Don't call DoTakedown if we were never valid to begin with. - if (log) - log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.", - static_cast<void*>(this)); - return; + for (uint32_t reg_idx = 0, num_registers = reg_ctx->GetRegisterCount(); + reg_idx < num_registers; ++reg_idx) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_idx); + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + reg_value.Dump(&strm, reg_info, true, false, eFormatDefault); + strm.EOL(); + } } + log->PutCString(strm.GetData()); + } +} - if (!m_takedown_done) - { - if (success) - { - SetReturnValue(); - } - if (log) - log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", - static_cast<void*>(this), m_thread.GetID(), m_valid, - IsPlanComplete()); - m_takedown_done = true; - m_stop_address = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); - m_real_stop_info_sp = GetPrivateStopInfo (); - if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) - { - if (log) - log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state", - static_cast<void*>(this)); - } - SetPlanComplete(success); - ClearBreakpoints(); - if (log && log->GetVerbose()) - ReportRegisterState ("Restoring thread state after function call. Restored register state:"); +void ThreadPlanCallFunction::DoTakedown(bool success) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP)); + + if (!m_valid) { + // Don't call DoTakedown if we were never valid to begin with. + if (log) + log->Printf("ThreadPlanCallFunction(%p): Log called on " + "ThreadPlanCallFunction that was never valid.", + static_cast<void *>(this)); + return; + } + + if (!m_takedown_done) { + if (success) { + SetReturnValue(); } - else - { - if (log) - log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", - static_cast<void*>(this), m_thread.GetID(), m_valid, - IsPlanComplete()); + if (log) + log->Printf("ThreadPlanCallFunction(%p): DoTakedown called for thread " + "0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", + static_cast<void *>(this), m_thread.GetID(), m_valid, + IsPlanComplete()); + m_takedown_done = true; + m_stop_address = + m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); + m_real_stop_info_sp = GetPrivateStopInfo(); + if (!m_thread.RestoreRegisterStateFromCheckpoint(m_stored_thread_state)) { + if (log) + log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore " + "register state", + static_cast<void *>(this)); } + SetPlanComplete(success); + ClearBreakpoints(); + if (log && log->GetVerbose()) + ReportRegisterState("Restoring thread state after function call. " + "Restored register state:"); + } else { + if (log) + log->Printf("ThreadPlanCallFunction(%p): DoTakedown called as no-op for " + "thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", + static_cast<void *>(this), m_thread.GetID(), m_valid, + IsPlanComplete()); + } } -void -ThreadPlanCallFunction::WillPop () -{ - DoTakedown(PlanSucceeded()); -} +void ThreadPlanCallFunction::WillPop() { DoTakedown(PlanSucceeded()); } -void -ThreadPlanCallFunction::GetDescription (Stream *s, DescriptionLevel level) -{ - if (level == eDescriptionLevelBrief) - { - s->Printf("Function call thread plan"); - } - else - { - TargetSP target_sp (m_thread.CalculateTarget()); - s->Printf("Thread plan to call 0x%" PRIx64, m_function_addr.GetLoadAddress(target_sp.get())); - } +void ThreadPlanCallFunction::GetDescription(Stream *s, DescriptionLevel level) { + if (level == eDescriptionLevelBrief) { + s->Printf("Function call thread plan"); + } else { + TargetSP target_sp(m_thread.CalculateTarget()); + s->Printf("Thread plan to call 0x%" PRIx64, + m_function_addr.GetLoadAddress(target_sp.get())); + } } -bool -ThreadPlanCallFunction::ValidatePlan (Stream *error) -{ - if (!m_valid) - { - if (error) - { - if (m_constructor_errors.GetSize() > 0) - error->PutCString (m_constructor_errors.GetData()); - else - error->PutCString ("Unknown error"); - } - return false; +bool ThreadPlanCallFunction::ValidatePlan(Stream *error) { + if (!m_valid) { + if (error) { + if (m_constructor_errors.GetSize() > 0) + error->PutCString(m_constructor_errors.GetData()); + else + error->PutCString("Unknown error"); } + return false; + } - return true; + return true; } -Vote -ThreadPlanCallFunction::ShouldReportStop(Event *event_ptr) -{ - if (m_takedown_done || IsPlanComplete()) - return eVoteYes; - else - return ThreadPlan::ShouldReportStop(event_ptr); +Vote ThreadPlanCallFunction::ShouldReportStop(Event *event_ptr) { + if (m_takedown_done || IsPlanComplete()) + return eVoteYes; + else + return ThreadPlan::ShouldReportStop(event_ptr); } -bool -ThreadPlanCallFunction::DoPlanExplainsStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP|LIBLLDB_LOG_PROCESS)); - m_real_stop_info_sp = GetPrivateStopInfo (); - - // If our subplan knows why we stopped, even if it's done (which would forward the question to us) - // we answer yes. - if (m_subplan_sp && m_subplan_sp->PlanExplainsStop(event_ptr)) - { - SetPlanComplete(); - return true; - } - - // Check if the breakpoint is one of ours. - - StopReason stop_reason; - if (!m_real_stop_info_sp) - stop_reason = eStopReasonNone; - else - stop_reason = m_real_stop_info_sp->GetStopReason(); +bool ThreadPlanCallFunction::DoPlanExplainsStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP | + LIBLLDB_LOG_PROCESS)); + m_real_stop_info_sp = GetPrivateStopInfo(); + + // If our subplan knows why we stopped, even if it's done (which would forward + // the question to us) + // we answer yes. + if (m_subplan_sp && m_subplan_sp->PlanExplainsStop(event_ptr)) { + SetPlanComplete(); + return true; + } + + // Check if the breakpoint is one of ours. + + StopReason stop_reason; + if (!m_real_stop_info_sp) + stop_reason = eStopReasonNone; + else + stop_reason = m_real_stop_info_sp->GetStopReason(); + if (log) + log->Printf( + "ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - %s.", + Thread::StopReasonAsCString(stop_reason)); + + if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop()) + return true; + + // One more quirk here. If this event was from Halt interrupting the target, + // then we should not consider + // ourselves complete. Return true to acknowledge the stop. + if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) { if (log) - log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: Got stop reason - %s.", Thread::StopReasonAsCString(stop_reason)); - - if (stop_reason == eStopReasonBreakpoint && BreakpointsExplainStop()) - return true; - - // One more quirk here. If this event was from Halt interrupting the target, then we should not consider - // ourselves complete. Return true to acknowledge the stop. - if (Process::ProcessEventData::GetInterruptedFromEvent(event_ptr)) - { + log->Printf("ThreadPlanCallFunction::PlanExplainsStop: The event is an " + "Interrupt, returning true."); + return true; + } + // We control breakpoints separately from other "stop reasons." So first, + // check the case where we stopped for an internal breakpoint, in that case, + // continue on. + // If it is not an internal breakpoint, consult m_ignore_breakpoints. + + if (stop_reason == eStopReasonBreakpoint) { + ProcessSP process_sp(m_thread.CalculateProcess()); + uint64_t break_site_id = m_real_stop_info_sp->GetValue(); + BreakpointSiteSP bp_site_sp; + if (process_sp) + bp_site_sp = process_sp->GetBreakpointSiteList().FindByID(break_site_id); + if (bp_site_sp) { + uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); + bool is_internal = true; + for (uint32_t i = 0; i < num_owners; i++) { + Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); if (log) - log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: The event is an Interrupt, returning true."); - return true; - } - // We control breakpoints separately from other "stop reasons." So first, - // check the case where we stopped for an internal breakpoint, in that case, continue on. - // If it is not an internal breakpoint, consult m_ignore_breakpoints. - - if (stop_reason == eStopReasonBreakpoint) - { - ProcessSP process_sp (m_thread.CalculateProcess()); - uint64_t break_site_id = m_real_stop_info_sp->GetValue(); - BreakpointSiteSP bp_site_sp; - if (process_sp) - bp_site_sp = process_sp->GetBreakpointSiteList().FindByID(break_site_id); - if (bp_site_sp) - { - uint32_t num_owners = bp_site_sp->GetNumberOfOwners(); - bool is_internal = true; - for (uint32_t i = 0; i < num_owners; i++) - { - Breakpoint &bp = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint(); - if (log) - log->Printf ("ThreadPlanCallFunction::PlanExplainsStop: hit breakpoint %d while calling function", bp.GetID()); - - if (!bp.IsInternal()) - { - is_internal = false; - break; - } - } - if (is_internal) - { - if (log) - log->Printf ("ThreadPlanCallFunction::PlanExplainsStop hit an internal breakpoint, not stopping."); - return false; - } - } + log->Printf("ThreadPlanCallFunction::PlanExplainsStop: hit " + "breakpoint %d while calling function", + bp.GetID()); - if (m_ignore_breakpoints) - { - if (log) - log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are ignoring breakpoints, overriding breakpoint stop info ShouldStop, returning true"); - m_real_stop_info_sp->OverrideShouldStop(false); - return true; - } - else - { - if (log) - log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are not ignoring breakpoints, overriding breakpoint stop info ShouldStop, returning true"); - m_real_stop_info_sp->OverrideShouldStop(true); - return false; + if (!bp.IsInternal()) { + is_internal = false; + break; } - } - else if (!m_unwind_on_error) - { - // If we don't want to discard this plan, than any stop we don't understand should be propagated up the stack. + } + if (is_internal) { + if (log) + log->Printf("ThreadPlanCallFunction::PlanExplainsStop hit an " + "internal breakpoint, not stopping."); return false; + } } - else - { - // If the subplan is running, any crashes are attributable to us. - // If we want to discard the plan, then we say we explain the stop - // but if we are going to be discarded, let whoever is above us - // explain the stop. - // But don't discard the plan if the stop would restart itself (for instance if it is a - // signal that is set not to stop. Check that here first. We just say we explain the stop - // but aren't done and everything will continue on from there. - - if (m_real_stop_info_sp && m_real_stop_info_sp->ShouldStopSynchronous(event_ptr)) - { - SetPlanComplete(false); - return m_subplan_sp ? m_unwind_on_error : false; - } - else - return true; - } -} -bool -ThreadPlanCallFunction::ShouldStop (Event *event_ptr) -{ - // We do some computation in DoPlanExplainsStop that may or may not set the plan as complete. - // We need to do that here to make sure our state is correct. - DoPlanExplainsStop(event_ptr); - - if (IsPlanComplete()) - { - ReportRegisterState ("Function completed. Register state was:"); - return true; - } - else - { - return false; + if (m_ignore_breakpoints) { + if (log) + log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are ignoring " + "breakpoints, overriding breakpoint stop info ShouldStop, " + "returning true"); + m_real_stop_info_sp->OverrideShouldStop(false); + return true; + } else { + if (log) + log->Printf("ThreadPlanCallFunction::PlanExplainsStop: we are not " + "ignoring breakpoints, overriding breakpoint stop info " + "ShouldStop, returning true"); + m_real_stop_info_sp->OverrideShouldStop(true); + return false; } + } else if (!m_unwind_on_error) { + // If we don't want to discard this plan, than any stop we don't understand + // should be propagated up the stack. + return false; + } else { + // If the subplan is running, any crashes are attributable to us. + // If we want to discard the plan, then we say we explain the stop + // but if we are going to be discarded, let whoever is above us + // explain the stop. + // But don't discard the plan if the stop would restart itself (for instance + // if it is a + // signal that is set not to stop. Check that here first. We just say we + // explain the stop + // but aren't done and everything will continue on from there. + + if (m_real_stop_info_sp && + m_real_stop_info_sp->ShouldStopSynchronous(event_ptr)) { + SetPlanComplete(false); + return m_subplan_sp ? m_unwind_on_error : false; + } else + return true; + } } -bool -ThreadPlanCallFunction::StopOthers () -{ - return m_stop_other_threads; -} +bool ThreadPlanCallFunction::ShouldStop(Event *event_ptr) { + // We do some computation in DoPlanExplainsStop that may or may not set the + // plan as complete. + // We need to do that here to make sure our state is correct. + DoPlanExplainsStop(event_ptr); -StateType -ThreadPlanCallFunction::GetPlanRunState () -{ - return eStateRunning; + if (IsPlanComplete()) { + ReportRegisterState("Function completed. Register state was:"); + return true; + } else { + return false; + } } -void -ThreadPlanCallFunction::DidPush () -{ -//#define SINGLE_STEP_EXPRESSIONS - - // Now set the thread state to "no reason" so we don't run with whatever signal was outstanding... - // Wait till the plan is pushed so we aren't changing the stop info till we're about to run. - - GetThread().SetStopInfoToNothing(); - +bool ThreadPlanCallFunction::StopOthers() { return m_stop_other_threads; } + +StateType ThreadPlanCallFunction::GetPlanRunState() { return eStateRunning; } + +void ThreadPlanCallFunction::DidPush() { + //#define SINGLE_STEP_EXPRESSIONS + + // Now set the thread state to "no reason" so we don't run with whatever + // signal was outstanding... + // Wait till the plan is pushed so we aren't changing the stop info till we're + // about to run. + + GetThread().SetStopInfoToNothing(); + #ifndef SINGLE_STEP_EXPRESSIONS - m_subplan_sp.reset(new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads)); - - m_thread.QueueThreadPlan(m_subplan_sp, false); - m_subplan_sp->SetPrivate (true); + m_subplan_sp.reset( + new ThreadPlanRunToAddress(m_thread, m_start_addr, m_stop_other_threads)); + + m_thread.QueueThreadPlan(m_subplan_sp, false); + m_subplan_sp->SetPrivate(true); #endif } -bool -ThreadPlanCallFunction::WillStop () -{ - return true; -} +bool ThreadPlanCallFunction::WillStop() { return true; } -bool -ThreadPlanCallFunction::MischiefManaged () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +bool ThreadPlanCallFunction::MischiefManaged() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (IsPlanComplete()) - { - if (log) - log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", - static_cast<void*>(this)); + if (IsPlanComplete()) { + if (log) + log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", + static_cast<void *>(this)); - ThreadPlan::MischiefManaged (); - return true; - } - else - { - return false; - } + ThreadPlan::MischiefManaged(); + return true; + } else { + return false; + } } -void -ThreadPlanCallFunction::SetBreakpoints () -{ - ProcessSP process_sp (m_thread.CalculateProcess()); - if (m_trap_exceptions && process_sp) - { - m_cxx_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus); - m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC); - - if (m_cxx_language_runtime) - { - m_should_clear_cxx_exception_bp = !m_cxx_language_runtime->ExceptionBreakpointsAreSet(); - m_cxx_language_runtime->SetExceptionBreakpoints(); - } - if (m_objc_language_runtime) - { - m_should_clear_objc_exception_bp = !m_objc_language_runtime->ExceptionBreakpointsAreSet(); - m_objc_language_runtime->SetExceptionBreakpoints(); - } +void ThreadPlanCallFunction::SetBreakpoints() { + ProcessSP process_sp(m_thread.CalculateProcess()); + if (m_trap_exceptions && process_sp) { + m_cxx_language_runtime = + process_sp->GetLanguageRuntime(eLanguageTypeC_plus_plus); + m_objc_language_runtime = process_sp->GetLanguageRuntime(eLanguageTypeObjC); + + if (m_cxx_language_runtime) { + m_should_clear_cxx_exception_bp = + !m_cxx_language_runtime->ExceptionBreakpointsAreSet(); + m_cxx_language_runtime->SetExceptionBreakpoints(); + } + if (m_objc_language_runtime) { + m_should_clear_objc_exception_bp = + !m_objc_language_runtime->ExceptionBreakpointsAreSet(); + m_objc_language_runtime->SetExceptionBreakpoints(); } + } } -void -ThreadPlanCallFunction::ClearBreakpoints () -{ - if (m_trap_exceptions) - { - if (m_cxx_language_runtime && m_should_clear_cxx_exception_bp) - m_cxx_language_runtime->ClearExceptionBreakpoints(); - if (m_objc_language_runtime && m_should_clear_objc_exception_bp) - m_objc_language_runtime->ClearExceptionBreakpoints(); - } +void ThreadPlanCallFunction::ClearBreakpoints() { + if (m_trap_exceptions) { + if (m_cxx_language_runtime && m_should_clear_cxx_exception_bp) + m_cxx_language_runtime->ClearExceptionBreakpoints(); + if (m_objc_language_runtime && m_should_clear_objc_exception_bp) + m_objc_language_runtime->ClearExceptionBreakpoints(); + } } -bool -ThreadPlanCallFunction::BreakpointsExplainStop() -{ - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - - if (m_trap_exceptions) - { - if ((m_cxx_language_runtime && - m_cxx_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp)) - ||(m_objc_language_runtime && - m_objc_language_runtime->ExceptionBreakpointsExplainStop(stop_info_sp))) - { - Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an exception breakpoint, setting plan complete."); - - SetPlanComplete(false); - - // If the user has set the ObjC language breakpoint, it would normally get priority over our internal - // catcher breakpoint, but in this case we can't let that happen, so force the ShouldStop here. - stop_info_sp->OverrideShouldStop (true); - return true; - } +bool ThreadPlanCallFunction::BreakpointsExplainStop() { + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + + if (m_trap_exceptions) { + if ((m_cxx_language_runtime && + m_cxx_language_runtime->ExceptionBreakpointsExplainStop( + stop_info_sp)) || + (m_objc_language_runtime && + m_objc_language_runtime->ExceptionBreakpointsExplainStop( + stop_info_sp))) { + Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("ThreadPlanCallFunction::BreakpointsExplainStop - Hit an " + "exception breakpoint, setting plan complete."); + + SetPlanComplete(false); + + // If the user has set the ObjC language breakpoint, it would normally get + // priority over our internal + // catcher breakpoint, but in this case we can't let that happen, so force + // the ShouldStop here. + stop_info_sp->OverrideShouldStop(true); + return true; } - - return false; + } + + return false; } -void -ThreadPlanCallFunction::SetStopOthers (bool new_value) -{ - m_subplan_sp->SetStopOthers(new_value); +void ThreadPlanCallFunction::SetStopOthers(bool new_value) { + m_subplan_sp->SetStopOthers(new_value); } -bool -ThreadPlanCallFunction::RestoreThreadState() -{ - return GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state); +bool ThreadPlanCallFunction::RestoreThreadState() { + return GetThread().RestoreThreadStateFromCheckpoint(m_stored_thread_state); } -void -ThreadPlanCallFunction::SetReturnValue() -{ - ProcessSP process_sp(m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - if (abi && m_return_type.IsValid()) - { - const bool persistent = false; - m_return_valobj_sp = abi->GetReturnValueObject(m_thread, m_return_type, persistent); - } +void ThreadPlanCallFunction::SetReturnValue() { + ProcessSP process_sp(m_thread.GetProcess()); + const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; + if (abi && m_return_type.IsValid()) { + const bool persistent = false; + m_return_valobj_sp = + abi->GetReturnValueObject(m_thread, m_return_type, persistent); + } } diff --git a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp index df23edc0fd1..6c5969577a9 100644 --- a/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp +++ b/lldb/source/Target/ThreadPlanCallFunctionUsingABI.cpp @@ -24,63 +24,52 @@ using namespace lldb; using namespace lldb_private; //-------------------------------------------------------------------------------------------- -// ThreadPlanCallFunctionUsingABI: Plan to call a single function using the ABI instead of JIT +// ThreadPlanCallFunctionUsingABI: Plan to call a single function using the ABI +// instead of JIT //------------------------------------------------------------------------------------------- -ThreadPlanCallFunctionUsingABI::ThreadPlanCallFunctionUsingABI (Thread &thread, - const Address &function, - llvm::Type &prototype, - llvm::Type &return_type, - llvm::ArrayRef<ABI::CallArgument> args, - const EvaluateExpressionOptions &options) : - ThreadPlanCallFunction(thread,function,options), - m_return_type(return_type) -{ - lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; - lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; - ABI *abi = nullptr; +ThreadPlanCallFunctionUsingABI::ThreadPlanCallFunctionUsingABI( + Thread &thread, const Address &function, llvm::Type &prototype, + llvm::Type &return_type, llvm::ArrayRef<ABI::CallArgument> args, + const EvaluateExpressionOptions &options) + : ThreadPlanCallFunction(thread, function, options), + m_return_type(return_type) { + lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS; + lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS; + ABI *abi = nullptr; - if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) - return; + if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr)) + return; - if (!abi->PrepareTrivialCall(thread, - m_function_sp, - function_load_addr, - start_load_addr, - prototype, - args)) - return; + if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr, + start_load_addr, prototype, args)) + return; - ReportRegisterState("ABI Function call was set up. Register state was:"); + ReportRegisterState("ABI Function call was set up. Register state was:"); - m_valid = true; + m_valid = true; } ThreadPlanCallFunctionUsingABI::~ThreadPlanCallFunctionUsingABI() = default; -void -ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s, DescriptionLevel level) -{ - if (level == eDescriptionLevelBrief) - { - s->Printf("Function call thread plan using ABI instead of JIT"); - } - else - { - TargetSP target_sp(m_thread.CalculateTarget()); - s->Printf("Thread plan to call 0x%" PRIx64" using ABI instead of JIT", m_function_addr.GetLoadAddress(target_sp.get())); - } +void ThreadPlanCallFunctionUsingABI::GetDescription(Stream *s, + DescriptionLevel level) { + if (level == eDescriptionLevelBrief) { + s->Printf("Function call thread plan using ABI instead of JIT"); + } else { + TargetSP target_sp(m_thread.CalculateTarget()); + s->Printf("Thread plan to call 0x%" PRIx64 " using ABI instead of JIT", + m_function_addr.GetLoadAddress(target_sp.get())); + } } -void -ThreadPlanCallFunctionUsingABI::SetReturnValue() -{ - ProcessSP process_sp(m_thread.GetProcess()); - const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; +void ThreadPlanCallFunctionUsingABI::SetReturnValue() { + ProcessSP process_sp(m_thread.GetProcess()); + const ABI *abi = process_sp ? process_sp->GetABI().get() : nullptr; - // Ask the abi for the return value - if (abi) - { - const bool persistent = false; - m_return_valobj_sp = abi->GetReturnValueObject(m_thread, m_return_type, persistent); - } + // Ask the abi for the return value + if (abi) { + const bool persistent = false; + m_return_valobj_sp = + abi->GetReturnValueObject(m_thread, m_return_type, persistent); + } } diff --git a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp index b2383e4f122..0dae98f03ef 100644 --- a/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp +++ b/lldb/source/Target/ThreadPlanCallOnFunctionExit.cpp @@ -12,108 +12,89 @@ using namespace lldb; using namespace lldb_private; -ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit(Thread &thread, - const Callback - &callback) : - ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit", - thread, - eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these - ), - m_callback(callback) -{ - // We are not a user-generated plan. - SetIsMasterPlan(false); +ThreadPlanCallOnFunctionExit::ThreadPlanCallOnFunctionExit( + Thread &thread, const Callback &callback) + : ThreadPlan(ThreadPlanKind::eKindGeneric, "CallOnFunctionExit", thread, + eVoteNoOpinion, eVoteNoOpinion // TODO check with Jim on these + ), + m_callback(callback) { + // We are not a user-generated plan. + SetIsMasterPlan(false); } -void -ThreadPlanCallOnFunctionExit::DidPush() -{ - // We now want to queue the "step out" thread plan so it executes - // and completes. - - // Set stop vote to eVoteNo. - m_step_out_threadplan_sp = GetThread() - .QueueThreadPlanForStepOut(false, // abort other plans - nullptr, // addr_context - true, // first instruction - true, // stop other threads - eVoteNo, // do not say "we're stopping" - eVoteNoOpinion, // don't care about - // run state broadcasting - 0, // frame_idx - eLazyBoolCalculate // avoid code w/o debinfo - ); +void ThreadPlanCallOnFunctionExit::DidPush() { + // We now want to queue the "step out" thread plan so it executes + // and completes. + + // Set stop vote to eVoteNo. + m_step_out_threadplan_sp = GetThread().QueueThreadPlanForStepOut( + false, // abort other plans + nullptr, // addr_context + true, // first instruction + true, // stop other threads + eVoteNo, // do not say "we're stopping" + eVoteNoOpinion, // don't care about + // run state broadcasting + 0, // frame_idx + eLazyBoolCalculate // avoid code w/o debinfo + ); } // ------------------------------------------------------------------------- // ThreadPlan API // ------------------------------------------------------------------------- -void -ThreadPlanCallOnFunctionExit::GetDescription(Stream *s, lldb::DescriptionLevel - level) -{ - if (!s) - return; - s->Printf("Running until completion of current function, then making " - "callback."); +void ThreadPlanCallOnFunctionExit::GetDescription( + Stream *s, lldb::DescriptionLevel level) { + if (!s) + return; + s->Printf("Running until completion of current function, then making " + "callback."); } -bool -ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) -{ - // We'll say we're always good since I don't know what would make this - // invalid. - return true; +bool ThreadPlanCallOnFunctionExit::ValidatePlan(Stream *error) { + // We'll say we're always good since I don't know what would make this + // invalid. + return true; } -bool -ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) -{ - // If this is where we find out that an internal stop came in, then: - // Check if the step-out plan completed. If it did, then we want to - // run the callback here (our reason for living...) - if (m_step_out_threadplan_sp && - m_step_out_threadplan_sp->IsPlanComplete()) - { - m_callback(); +bool ThreadPlanCallOnFunctionExit::ShouldStop(Event *event_ptr) { + // If this is where we find out that an internal stop came in, then: + // Check if the step-out plan completed. If it did, then we want to + // run the callback here (our reason for living...) + if (m_step_out_threadplan_sp && m_step_out_threadplan_sp->IsPlanComplete()) { + m_callback(); - // We no longer need the pointer to the step-out thread plan. - m_step_out_threadplan_sp.reset(); + // We no longer need the pointer to the step-out thread plan. + m_step_out_threadplan_sp.reset(); - // Indicate that this plan is done and can be discarded. - SetPlanComplete(); + // Indicate that this plan is done and can be discarded. + SetPlanComplete(); - // We're done now, but we want to return false so that we - // don't cause the thread to really stop. - } + // We're done now, but we want to return false so that we + // don't cause the thread to really stop. + } - return false; + return false; } -bool -ThreadPlanCallOnFunctionExit::WillStop() -{ - // The code looks like the return value is ignored via ThreadList:: - // ShouldStop(). - // This is called when we really are going to stop. We don't care - // and don't need to do anything here. - return false; +bool ThreadPlanCallOnFunctionExit::WillStop() { + // The code looks like the return value is ignored via ThreadList:: + // ShouldStop(). + // This is called when we really are going to stop. We don't care + // and don't need to do anything here. + return false; } -bool -ThreadPlanCallOnFunctionExit::DoPlanExplainsStop (Event *event_ptr) -{ - // We don't ever explain a stop. The only stop that is relevant - // to us directly is the step_out plan we added to do the heavy lifting - // of getting us past the current method. - return false; +bool ThreadPlanCallOnFunctionExit::DoPlanExplainsStop(Event *event_ptr) { + // We don't ever explain a stop. The only stop that is relevant + // to us directly is the step_out plan we added to do the heavy lifting + // of getting us past the current method. + return false; } -lldb::StateType -ThreadPlanCallOnFunctionExit::GetPlanRunState() -{ - // This value doesn't matter - we'll never be the top thread plan, so - // nobody will ask us this question. - return eStateRunning; +lldb::StateType ThreadPlanCallOnFunctionExit::GetPlanRunState() { + // This value doesn't matter - we'll never be the top thread plan, so + // nobody will ask us this question. + return eStateRunning; } diff --git a/lldb/source/Target/ThreadPlanCallUserExpression.cpp b/lldb/source/Target/ThreadPlanCallUserExpression.cpp index d4259ed18d3..dcd5c8c6eb8 100644 --- a/lldb/source/Target/ThreadPlanCallUserExpression.cpp +++ b/lldb/source/Target/ThreadPlanCallUserExpression.cpp @@ -1,4 +1,5 @@ -//===-- ThreadPlanCallUserExpression.cpp ------------------------------*- C++ -*-===// +//===-- ThreadPlanCallUserExpression.cpp ------------------------------*- C++ +//-*-===// // // The LLVM Compiler Infrastructure // @@ -38,91 +39,78 @@ using namespace lldb_private; // ThreadPlanCallUserExpression: Plan to call a single function //---------------------------------------------------------------------- -ThreadPlanCallUserExpression::ThreadPlanCallUserExpression (Thread &thread, - Address &function, - llvm::ArrayRef<lldb::addr_t> args, - const EvaluateExpressionOptions &options, - lldb::UserExpressionSP &user_expression_sp) : - ThreadPlanCallFunction (thread, function, CompilerType(), args, options), - m_user_expression_sp (user_expression_sp) -{ - // User expressions are generally "User generated" so we should set them up to stop when done. - SetIsMasterPlan (true); - SetOkayToDiscard(false); +ThreadPlanCallUserExpression::ThreadPlanCallUserExpression( + Thread &thread, Address &function, llvm::ArrayRef<lldb::addr_t> args, + const EvaluateExpressionOptions &options, + lldb::UserExpressionSP &user_expression_sp) + : ThreadPlanCallFunction(thread, function, CompilerType(), args, options), + m_user_expression_sp(user_expression_sp) { + // User expressions are generally "User generated" so we should set them up to + // stop when done. + SetIsMasterPlan(true); + SetOkayToDiscard(false); } -ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression () -{ -} +ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression() {} -void -ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == eDescriptionLevelBrief) - s->Printf("User Expression thread plan"); - else - ThreadPlanCallFunction::GetDescription (s, level); +void ThreadPlanCallUserExpression::GetDescription( + Stream *s, lldb::DescriptionLevel level) { + if (level == eDescriptionLevelBrief) + s->Printf("User Expression thread plan"); + else + ThreadPlanCallFunction::GetDescription(s, level); } -void -ThreadPlanCallUserExpression::WillPop () -{ - ThreadPlanCallFunction::WillPop(); - if (m_user_expression_sp) - m_user_expression_sp.reset(); +void ThreadPlanCallUserExpression::WillPop() { + ThreadPlanCallFunction::WillPop(); + if (m_user_expression_sp) + m_user_expression_sp.reset(); } -bool -ThreadPlanCallUserExpression::MischiefManaged () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if (IsPlanComplete()) - { - if (log) - log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", - static_cast<void*>(this)); +bool ThreadPlanCallUserExpression::MischiefManaged() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (m_manage_materialization && PlanSucceeded() && m_user_expression_sp) - { - lldb::addr_t function_stack_top; - lldb::addr_t function_stack_bottom; - lldb::addr_t function_stack_pointer = GetFunctionStackPointer(); + if (IsPlanComplete()) { + if (log) + log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", + static_cast<void *>(this)); - function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); - function_stack_top = function_stack_pointer; + if (m_manage_materialization && PlanSucceeded() && m_user_expression_sp) { + lldb::addr_t function_stack_top; + lldb::addr_t function_stack_bottom; + lldb::addr_t function_stack_pointer = GetFunctionStackPointer(); - DiagnosticManager diagnostics; + function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize(); + function_stack_top = function_stack_pointer; - ExecutionContext exe_ctx(GetThread()); + DiagnosticManager diagnostics; - m_user_expression_sp->FinalizeJITExecution(diagnostics, exe_ctx, m_result_var_sp, function_stack_bottom, - function_stack_top); - } + ExecutionContext exe_ctx(GetThread()); - ThreadPlan::MischiefManaged(); - return true; - } - else - { - return false; + m_user_expression_sp->FinalizeJITExecution( + diagnostics, exe_ctx, m_result_var_sp, function_stack_bottom, + function_stack_top); } + + ThreadPlan::MischiefManaged(); + return true; + } else { + return false; + } } -StopInfoSP -ThreadPlanCallUserExpression::GetRealStopInfo() -{ - StopInfoSP stop_info_sp = ThreadPlanCallFunction::GetRealStopInfo(); - - if (stop_info_sp) - { - lldb::addr_t addr = GetStopAddress(); - DynamicCheckerFunctions *checkers = m_thread.GetProcess()->GetDynamicCheckers(); - StreamString s; - - if (checkers && checkers->DoCheckersExplainStop(addr, s)) - stop_info_sp->SetDescription(s.GetData()); - } +StopInfoSP ThreadPlanCallUserExpression::GetRealStopInfo() { + StopInfoSP stop_info_sp = ThreadPlanCallFunction::GetRealStopInfo(); + + if (stop_info_sp) { + lldb::addr_t addr = GetStopAddress(); + DynamicCheckerFunctions *checkers = + m_thread.GetProcess()->GetDynamicCheckers(); + StreamString s; + + if (checkers && checkers->DoCheckersExplainStop(addr, s)) + stop_info_sp->SetDescription(s.GetData()); + } - return stop_info_sp; + return stop_info_sp; } diff --git a/lldb/source/Target/ThreadPlanPython.cpp b/lldb/source/Target/ThreadPlanPython.cpp index 39a8d77d43a..33dadbf2a2e 100644 --- a/lldb/source/Target/ThreadPlanPython.cpp +++ b/lldb/source/Target/ThreadPlanPython.cpp @@ -18,12 +18,12 @@ #include "lldb/Core/State.h" #include "lldb/Interpreter/CommandInterpreter.h" #include "lldb/Interpreter/ScriptInterpreter.h" +#include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlan.h" #include "lldb/Target/ThreadPlanPython.h" -#include "lldb/Target/Process.h" -#include "lldb/Target/Target.h" using namespace lldb; using namespace lldb_private; @@ -32,181 +32,175 @@ using namespace lldb_private; // ThreadPlanPython //---------------------------------------------------------------------- -ThreadPlanPython::ThreadPlanPython (Thread &thread, const char *class_name) : - ThreadPlan (ThreadPlan::eKindPython, - "Python based Thread Plan", - thread, - eVoteNoOpinion, - eVoteNoOpinion), - m_class_name (class_name) -{ - SetIsMasterPlan (true); - SetOkayToDiscard (true); - SetPrivate (false); +ThreadPlanPython::ThreadPlanPython(Thread &thread, const char *class_name) + : ThreadPlan(ThreadPlan::eKindPython, "Python based Thread Plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_class_name(class_name) { + SetIsMasterPlan(true); + SetOkayToDiscard(true); + SetPrivate(false); } -ThreadPlanPython::~ThreadPlanPython () -{ - // FIXME, do I need to decrement the ref count on this implementation object to make it go away? +ThreadPlanPython::~ThreadPlanPython() { + // FIXME, do I need to decrement the ref count on this implementation object + // to make it go away? } -bool -ThreadPlanPython::ValidatePlan (Stream *error) -{ - // I have to postpone setting up the implementation till after the constructor because I need to call - // shared_from_this, which you can't do in the constructor. So I'll do it here. - if (m_implementation_sp) - return true; - else - return false; +bool ThreadPlanPython::ValidatePlan(Stream *error) { + // I have to postpone setting up the implementation till after the constructor + // because I need to call + // shared_from_this, which you can't do in the constructor. So I'll do it + // here. + if (m_implementation_sp) + return true; + else + return false; } -void -ThreadPlanPython::DidPush() -{ - // We set up the script side in DidPush, so that it can push other plans in the constructor, - // and doesn't have to care about the details of DidPush. - - if (!m_class_name.empty()) - { - ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (script_interp) - { - m_implementation_sp = script_interp->CreateScriptedThreadPlan (m_class_name.c_str(), this->shared_from_this()); - } +void ThreadPlanPython::DidPush() { + // We set up the script side in DidPush, so that it can push other plans in + // the constructor, + // and doesn't have to care about the details of DidPush. + + if (!m_class_name.empty()) { + ScriptInterpreter *script_interp = m_thread.GetProcess() + ->GetTarget() + .GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter(); + if (script_interp) { + m_implementation_sp = script_interp->CreateScriptedThreadPlan( + m_class_name.c_str(), this->shared_from_this()); } + } } -bool -ThreadPlanPython::ShouldStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("%s called on Python Thread Plan: %s )", - LLVM_PRETTY_FUNCTION, m_class_name.c_str()); - - bool should_stop = true; - if (m_implementation_sp) - { - ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (script_interp) - { - bool script_error; - should_stop = script_interp->ScriptedThreadPlanShouldStop (m_implementation_sp, event_ptr, script_error); - if (script_error) - SetPlanComplete(false); - } +bool ThreadPlanPython::ShouldStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + + bool should_stop = true; + if (m_implementation_sp) { + ScriptInterpreter *script_interp = m_thread.GetProcess() + ->GetTarget() + .GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter(); + if (script_interp) { + bool script_error; + should_stop = script_interp->ScriptedThreadPlanShouldStop( + m_implementation_sp, event_ptr, script_error); + if (script_error) + SetPlanComplete(false); } - return should_stop; + } + return should_stop; } -bool -ThreadPlanPython::IsPlanStale() -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("%s called on Python Thread Plan: %s )", - LLVM_PRETTY_FUNCTION, m_class_name.c_str()); - - bool is_stale = true; - if (m_implementation_sp) - { - ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (script_interp) - { - bool script_error; - is_stale = script_interp->ScriptedThreadPlanIsStale (m_implementation_sp, script_error); - if (script_error) - SetPlanComplete(false); - } +bool ThreadPlanPython::IsPlanStale() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + + bool is_stale = true; + if (m_implementation_sp) { + ScriptInterpreter *script_interp = m_thread.GetProcess() + ->GetTarget() + .GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter(); + if (script_interp) { + bool script_error; + is_stale = script_interp->ScriptedThreadPlanIsStale(m_implementation_sp, + script_error); + if (script_error) + SetPlanComplete(false); } - return is_stale; + } + return is_stale; } -bool -ThreadPlanPython::DoPlanExplainsStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("%s called on Python Thread Plan: %s )", - LLVM_PRETTY_FUNCTION, m_class_name.c_str()); - - bool explains_stop = true; - if (m_implementation_sp) - { - ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (script_interp) - { - bool script_error; - explains_stop = script_interp->ScriptedThreadPlanExplainsStop (m_implementation_sp, event_ptr, script_error); - if (script_error) - SetPlanComplete(false); - } +bool ThreadPlanPython::DoPlanExplainsStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + + bool explains_stop = true; + if (m_implementation_sp) { + ScriptInterpreter *script_interp = m_thread.GetProcess() + ->GetTarget() + .GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter(); + if (script_interp) { + bool script_error; + explains_stop = script_interp->ScriptedThreadPlanExplainsStop( + m_implementation_sp, event_ptr, script_error); + if (script_error) + SetPlanComplete(false); } - return explains_stop; + } + return explains_stop; } -bool -ThreadPlanPython::MischiefManaged () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("%s called on Python Thread Plan: %s )", - LLVM_PRETTY_FUNCTION, m_class_name.c_str()); - bool mischief_managed = true; - if (m_implementation_sp) - { - // I don't really need mischief_managed, since it's simpler to just call SetPlanComplete in should_stop. - mischief_managed = IsPlanComplete(); - if (mischief_managed) - m_implementation_sp.reset(); - } - return mischief_managed; +bool ThreadPlanPython::MischiefManaged() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + bool mischief_managed = true; + if (m_implementation_sp) { + // I don't really need mischief_managed, since it's simpler to just call + // SetPlanComplete in should_stop. + mischief_managed = IsPlanComplete(); + if (mischief_managed) + m_implementation_sp.reset(); + } + return mischief_managed; } -lldb::StateType -ThreadPlanPython::GetPlanRunState () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("%s called on Python Thread Plan: %s )", - LLVM_PRETTY_FUNCTION, - m_class_name.c_str()); - lldb::StateType run_state = eStateRunning; - if (m_implementation_sp) - { - ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter(); - if (script_interp) - { - bool script_error; - run_state = script_interp->ScriptedThreadPlanGetRunState (m_implementation_sp, script_error); - } +lldb::StateType ThreadPlanPython::GetPlanRunState() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + lldb::StateType run_state = eStateRunning; + if (m_implementation_sp) { + ScriptInterpreter *script_interp = m_thread.GetProcess() + ->GetTarget() + .GetDebugger() + .GetCommandInterpreter() + .GetScriptInterpreter(); + if (script_interp) { + bool script_error; + run_state = script_interp->ScriptedThreadPlanGetRunState( + m_implementation_sp, script_error); } - return run_state; + } + return run_state; } // The ones below are not currently exported to Python. -bool -ThreadPlanPython::StopOthers () -{ - // For now Python plans run all threads, but we should add some controls for this. - return false; +bool ThreadPlanPython::StopOthers() { + // For now Python plans run all threads, but we should add some controls for + // this. + return false; } -void -ThreadPlanPython::GetDescription (Stream *s, - lldb::DescriptionLevel level) -{ - s->Printf ("Python thread plan implemented by class %s.", m_class_name.c_str()); +void ThreadPlanPython::GetDescription(Stream *s, lldb::DescriptionLevel level) { + s->Printf("Python thread plan implemented by class %s.", + m_class_name.c_str()); } -bool -ThreadPlanPython::WillStop () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD)); - if (log) - log->Printf ("%s called on Python Thread Plan: %s )", - LLVM_PRETTY_FUNCTION, m_class_name.c_str()); - return true; +bool ThreadPlanPython::WillStop() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_THREAD)); + if (log) + log->Printf("%s called on Python Thread Plan: %s )", LLVM_PRETTY_FUNCTION, + m_class_name.c_str()); + return true; } diff --git a/lldb/source/Target/ThreadPlanRunToAddress.cpp b/lldb/source/Target/ThreadPlanRunToAddress.cpp index 18c43dafd7b..6f31db0d93a 100644 --- a/lldb/source/Target/ThreadPlanRunToAddress.cpp +++ b/lldb/source/Target/ThreadPlanRunToAddress.cpp @@ -14,10 +14,10 @@ #include "lldb/Target/ThreadPlanRunToAddress.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" -#include "lldb/Target/Target.h" #include "lldb/Target/Process.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" using namespace lldb; using namespace lldb_private; @@ -26,241 +26,179 @@ using namespace lldb_private; // ThreadPlanRunToAddress: Continue plan //---------------------------------------------------------------------- -ThreadPlanRunToAddress::ThreadPlanRunToAddress -( - Thread &thread, - Address &address, - bool stop_others -) : - ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_stop_others (stop_others), - m_addresses (), - m_break_ids () -{ - m_addresses.push_back (address.GetOpcodeLoadAddress (m_thread.CalculateTarget().get())); - SetInitialBreakpoints(); +ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, Address &address, + bool stop_others) + : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_stop_others(stop_others), m_addresses(), m_break_ids() { + m_addresses.push_back( + address.GetOpcodeLoadAddress(m_thread.CalculateTarget().get())); + SetInitialBreakpoints(); } -ThreadPlanRunToAddress::ThreadPlanRunToAddress -( - Thread &thread, - lldb::addr_t address, - bool stop_others -) : - ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_stop_others (stop_others), - m_addresses (), - m_break_ids () -{ - m_addresses.push_back(m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); - SetInitialBreakpoints(); +ThreadPlanRunToAddress::ThreadPlanRunToAddress(Thread &thread, + lldb::addr_t address, + bool stop_others) + : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_stop_others(stop_others), m_addresses(), m_break_ids() { + m_addresses.push_back( + m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); + SetInitialBreakpoints(); } -ThreadPlanRunToAddress::ThreadPlanRunToAddress -( - Thread &thread, - const std::vector<lldb::addr_t> &addresses, - bool stop_others -) : - ThreadPlan (ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion), - m_stop_others (stop_others), - m_addresses (addresses), - m_break_ids () -{ - // Convert all addresses into opcode addresses to make sure we set - // breakpoints at the correct address. - Target &target = thread.GetProcess()->GetTarget(); - std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end(); - for (pos = m_addresses.begin(); pos != end; ++pos) - *pos = target.GetOpcodeLoadAddress (*pos); - - SetInitialBreakpoints(); +ThreadPlanRunToAddress::ThreadPlanRunToAddress( + Thread &thread, const std::vector<lldb::addr_t> &addresses, + bool stop_others) + : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_stop_others(stop_others), m_addresses(addresses), m_break_ids() { + // Convert all addresses into opcode addresses to make sure we set + // breakpoints at the correct address. + Target &target = thread.GetProcess()->GetTarget(); + std::vector<lldb::addr_t>::iterator pos, end = m_addresses.end(); + for (pos = m_addresses.begin(); pos != end; ++pos) + *pos = target.GetOpcodeLoadAddress(*pos); + + SetInitialBreakpoints(); } -void -ThreadPlanRunToAddress::SetInitialBreakpoints () -{ - size_t num_addresses = m_addresses.size(); - m_break_ids.resize(num_addresses); - - for (size_t i = 0; i < num_addresses; i++) - { - Breakpoint *breakpoint; - breakpoint = m_thread.CalculateTarget()->CreateBreakpoint (m_addresses[i], true, false).get(); - if (breakpoint != nullptr) - { - m_break_ids[i] = breakpoint->GetID(); - breakpoint->SetThreadID(m_thread.GetID()); - breakpoint->SetBreakpointKind("run-to-address"); - } +void ThreadPlanRunToAddress::SetInitialBreakpoints() { + size_t num_addresses = m_addresses.size(); + m_break_ids.resize(num_addresses); + + for (size_t i = 0; i < num_addresses; i++) { + Breakpoint *breakpoint; + breakpoint = m_thread.CalculateTarget() + ->CreateBreakpoint(m_addresses[i], true, false) + .get(); + if (breakpoint != nullptr) { + m_break_ids[i] = breakpoint->GetID(); + breakpoint->SetThreadID(m_thread.GetID()); + breakpoint->SetBreakpointKind("run-to-address"); } + } } -ThreadPlanRunToAddress::~ThreadPlanRunToAddress () -{ - size_t num_break_ids = m_break_ids.size(); - for (size_t i = 0; i < num_break_ids; i++) - { - m_thread.CalculateTarget()->RemoveBreakpointByID (m_break_ids[i]); - } +ThreadPlanRunToAddress::~ThreadPlanRunToAddress() { + size_t num_break_ids = m_break_ids.size(); + for (size_t i = 0; i < num_break_ids; i++) { + m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); + } } -void -ThreadPlanRunToAddress::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - size_t num_addresses = m_addresses.size(); - - if (level == lldb::eDescriptionLevelBrief) - { - if (num_addresses == 0) - { - s->Printf ("run to address with no addresses given."); - return; - } - else if (num_addresses == 1) - s->Printf ("run to address: "); - else - s->Printf ("run to addresses: "); - - for (size_t i = 0; i < num_addresses; i++) - { - s->Address (m_addresses[i], sizeof (addr_t)); - s->Printf(" "); - } - } +void ThreadPlanRunToAddress::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + size_t num_addresses = m_addresses.size(); + + if (level == lldb::eDescriptionLevelBrief) { + if (num_addresses == 0) { + s->Printf("run to address with no addresses given."); + return; + } else if (num_addresses == 1) + s->Printf("run to address: "); else - { - if (num_addresses == 0) - { - s->Printf ("run to address with no addresses given."); - return; - } - else if (num_addresses == 1) - s->Printf ("Run to address: "); - else - { - s->Printf ("Run to addresses: "); - } - - for (size_t i = 0; i < num_addresses; i++) - { - if (num_addresses > 1) - { - s->Printf("\n"); - s->Indent(); - } - - s->Address(m_addresses[i], sizeof (addr_t)); - s->Printf (" using breakpoint: %d - ", m_break_ids[i]); - Breakpoint *breakpoint = m_thread.CalculateTarget()->GetBreakpointByID (m_break_ids[i]).get(); - if (breakpoint) - breakpoint->Dump (s); - else - s->Printf ("but the breakpoint has been deleted."); - } + s->Printf("run to addresses: "); + + for (size_t i = 0; i < num_addresses; i++) { + s->Address(m_addresses[i], sizeof(addr_t)); + s->Printf(" "); + } + } else { + if (num_addresses == 0) { + s->Printf("run to address with no addresses given."); + return; + } else if (num_addresses == 1) + s->Printf("Run to address: "); + else { + s->Printf("Run to addresses: "); } -} -bool -ThreadPlanRunToAddress::ValidatePlan (Stream *error) -{ - // If we couldn't set the breakpoint for some reason, then this won't - // work. - bool all_bps_good = true; - size_t num_break_ids = m_break_ids.size(); - - for (size_t i = 0; i < num_break_ids; i++) - { - if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) - { - all_bps_good = false; - if (error) - { - error->Printf ("Could not set breakpoint for address: "); - error->Address (m_addresses[i], sizeof (addr_t)); - error->Printf ("\n"); - } - } + for (size_t i = 0; i < num_addresses; i++) { + if (num_addresses > 1) { + s->Printf("\n"); + s->Indent(); + } + + s->Address(m_addresses[i], sizeof(addr_t)); + s->Printf(" using breakpoint: %d - ", m_break_ids[i]); + Breakpoint *breakpoint = + m_thread.CalculateTarget()->GetBreakpointByID(m_break_ids[i]).get(); + if (breakpoint) + breakpoint->Dump(s); + else + s->Printf("but the breakpoint has been deleted."); } - return all_bps_good; + } } -bool -ThreadPlanRunToAddress::DoPlanExplainsStop (Event *event_ptr) -{ - return AtOurAddress(); +bool ThreadPlanRunToAddress::ValidatePlan(Stream *error) { + // If we couldn't set the breakpoint for some reason, then this won't + // work. + bool all_bps_good = true; + size_t num_break_ids = m_break_ids.size(); + + for (size_t i = 0; i < num_break_ids; i++) { + if (m_break_ids[i] == LLDB_INVALID_BREAK_ID) { + all_bps_good = false; + if (error) { + error->Printf("Could not set breakpoint for address: "); + error->Address(m_addresses[i], sizeof(addr_t)); + error->Printf("\n"); + } + } + } + return all_bps_good; } -bool -ThreadPlanRunToAddress::ShouldStop (Event *event_ptr) -{ - return AtOurAddress(); +bool ThreadPlanRunToAddress::DoPlanExplainsStop(Event *event_ptr) { + return AtOurAddress(); } -bool -ThreadPlanRunToAddress::StopOthers () -{ - return m_stop_others; +bool ThreadPlanRunToAddress::ShouldStop(Event *event_ptr) { + return AtOurAddress(); } -void -ThreadPlanRunToAddress::SetStopOthers (bool new_value) -{ - m_stop_others = new_value; -} +bool ThreadPlanRunToAddress::StopOthers() { return m_stop_others; } -StateType -ThreadPlanRunToAddress::GetPlanRunState () -{ - return eStateRunning; +void ThreadPlanRunToAddress::SetStopOthers(bool new_value) { + m_stop_others = new_value; } -bool -ThreadPlanRunToAddress::WillStop () -{ - return true; -} +StateType ThreadPlanRunToAddress::GetPlanRunState() { return eStateRunning; } -bool -ThreadPlanRunToAddress::MischiefManaged () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +bool ThreadPlanRunToAddress::WillStop() { return true; } - if (AtOurAddress()) - { - // Remove the breakpoint - size_t num_break_ids = m_break_ids.size(); - - for (size_t i = 0; i < num_break_ids; i++) - { - if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) - { - m_thread.CalculateTarget()->RemoveBreakpointByID (m_break_ids[i]); - m_break_ids[i] = LLDB_INVALID_BREAK_ID; - } - } - if (log) - log->Printf("Completed run to address plan."); - ThreadPlan::MischiefManaged (); - return true; +bool ThreadPlanRunToAddress::MischiefManaged() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (AtOurAddress()) { + // Remove the breakpoint + size_t num_break_ids = m_break_ids.size(); + + for (size_t i = 0; i < num_break_ids; i++) { + if (m_break_ids[i] != LLDB_INVALID_BREAK_ID) { + m_thread.CalculateTarget()->RemoveBreakpointByID(m_break_ids[i]); + m_break_ids[i] = LLDB_INVALID_BREAK_ID; + } } - else - return false; + if (log) + log->Printf("Completed run to address plan."); + ThreadPlan::MischiefManaged(); + return true; + } else + return false; } -bool -ThreadPlanRunToAddress::AtOurAddress () -{ - lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); - bool found_it = false; - size_t num_addresses = m_addresses.size(); - for (size_t i = 0; i < num_addresses; i++) - { - if (m_addresses[i] == current_address) - { - found_it = true; - break; - } +bool ThreadPlanRunToAddress::AtOurAddress() { + lldb::addr_t current_address = m_thread.GetRegisterContext()->GetPC(); + bool found_it = false; + size_t num_addresses = m_addresses.size(); + for (size_t i = 0; i < num_addresses; i++) { + if (m_addresses[i] == current_address) { + found_it = true; + break; } - return found_it; + } + return found_it; } diff --git a/lldb/source/Target/ThreadPlanShouldStopHere.cpp b/lldb/source/Target/ThreadPlanShouldStopHere.cpp index fcbc7f01c90..408650d75f0 100644 --- a/lldb/source/Target/ThreadPlanShouldStopHere.cpp +++ b/lldb/source/Target/ThreadPlanShouldStopHere.cpp @@ -11,10 +11,10 @@ // C++ Includes // Other libraries and framework includes // Project includes +#include "lldb/Target/Thread.h" #include "lldb/Core/Log.h" #include "lldb/Symbol/Symbol.h" #include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanShouldStopHere.h" using namespace lldb; @@ -23,166 +23,149 @@ using namespace lldb_private; //---------------------------------------------------------------------- // ThreadPlanShouldStopHere constructor //---------------------------------------------------------------------- -ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) : - m_callbacks(), - m_baton(nullptr), - m_owner(owner), - m_flags(ThreadPlanShouldStopHere::eNone) -{ - m_callbacks.should_stop_here_callback = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback; - m_callbacks.step_from_here_callback = ThreadPlanShouldStopHere::DefaultStepFromHereCallback; +ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) + : m_callbacks(), m_baton(nullptr), m_owner(owner), + m_flags(ThreadPlanShouldStopHere::eNone) { + m_callbacks.should_stop_here_callback = + ThreadPlanShouldStopHere::DefaultShouldStopHereCallback; + m_callbacks.step_from_here_callback = + ThreadPlanShouldStopHere::DefaultStepFromHereCallback; } -ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, void *baton) : - m_callbacks (), - m_baton (), - m_owner (owner), - m_flags (ThreadPlanShouldStopHere::eNone) -{ - SetShouldStopHereCallbacks(callbacks, baton); +ThreadPlanShouldStopHere::ThreadPlanShouldStopHere( + ThreadPlan *owner, const ThreadPlanShouldStopHereCallbacks *callbacks, + void *baton) + : m_callbacks(), m_baton(), m_owner(owner), + m_flags(ThreadPlanShouldStopHere::eNone) { + SetShouldStopHereCallbacks(callbacks, baton); } ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere() = default; -bool -ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation) -{ - bool should_stop_here = true; - if (m_callbacks.should_stop_here_callback) - { - should_stop_here = m_callbacks.should_stop_here_callback (m_owner, m_flags, operation, m_baton); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - { - lldb::addr_t current_addr = m_owner->GetThread().GetRegisterContext()->GetPC(0); - - log->Printf ("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", should_stop_here, current_addr); - } +bool ThreadPlanShouldStopHere::InvokeShouldStopHereCallback( + FrameComparison operation) { + bool should_stop_here = true; + if (m_callbacks.should_stop_here_callback) { + should_stop_here = m_callbacks.should_stop_here_callback( + m_owner, m_flags, operation, m_baton); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + lldb::addr_t current_addr = + m_owner->GetThread().GetRegisterContext()->GetPC(0); + + log->Printf("ShouldStopHere callback returned %u from 0x%" PRIx64 ".", + should_stop_here, current_addr); } - - return should_stop_here; -} + } -bool -ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (ThreadPlan *current_plan, - Flags &flags, - FrameComparison operation, - void *baton) -{ - bool should_stop_here = true; - StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); - if (!frame) - return true; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) - || (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) - || (operation == eFrameCompareSameParent && flags.Test(eStepInAvoidNoDebug))) - { - if (!frame->HasDebugInformation()) - { - if (log) - log->Printf ("Stepping out of frame with no debug info"); - - should_stop_here = false; - } - } - - // Always avoid code with line number 0. - // FIXME: At present the ShouldStop and the StepFromHere calculate this independently. If this ever - // becomes expensive (this one isn't) we can try to have this set a state that the StepFromHere can use. - if (frame) - { - SymbolContext sc; - sc = frame->GetSymbolContext (eSymbolContextLineEntry); - if (sc.line_entry.line == 0) - should_stop_here = false; - } - - return should_stop_here; + return should_stop_here; } -ThreadPlanSP -ThreadPlanShouldStopHere::DefaultStepFromHereCallback (ThreadPlan *current_plan, - Flags &flags, - FrameComparison operation, - void *baton) -{ - const bool stop_others = false; - const size_t frame_index = 0; - ThreadPlanSP return_plan_sp; - // If we are stepping through code at line number 0, then we need to step over this range. Otherwise - // we will step out. - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); - if (!frame) - return return_plan_sp; +bool ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( + ThreadPlan *current_plan, Flags &flags, FrameComparison operation, + void *baton) { + bool should_stop_here = true; + StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); + if (!frame) + return true; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if ((operation == eFrameCompareOlder && flags.Test(eStepOutAvoidNoDebug)) || + (operation == eFrameCompareYounger && flags.Test(eStepInAvoidNoDebug)) || + (operation == eFrameCompareSameParent && + flags.Test(eStepInAvoidNoDebug))) { + if (!frame->HasDebugInformation()) { + if (log) + log->Printf("Stepping out of frame with no debug info"); + + should_stop_here = false; + } + } + + // Always avoid code with line number 0. + // FIXME: At present the ShouldStop and the StepFromHere calculate this + // independently. If this ever + // becomes expensive (this one isn't) we can try to have this set a state that + // the StepFromHere can use. + if (frame) { SymbolContext sc; - sc = frame->GetSymbolContext (eSymbolContextLineEntry|eSymbolContextSymbol); - + sc = frame->GetSymbolContext(eSymbolContextLineEntry); if (sc.line_entry.line == 0) - { - AddressRange range = sc.line_entry.range; - - // If the whole function is marked line 0 just step out, that's easier & faster than continuing - // to step through it. - bool just_step_out = false; - if (sc.symbol && sc.symbol->ValueIsAddress()) - { - Address symbol_end = sc.symbol->GetAddress(); - symbol_end.Slide(sc.symbol->GetByteSize() - 1); - if (range.ContainsFileAddress(sc.symbol->GetAddress()) && range.ContainsFileAddress(symbol_end)) - { - if (log) - log->Printf("Stopped in a function with only line 0 lines, just stepping out."); - just_step_out = true; - } - } - if (!just_step_out) - { - if (log) - log->Printf ("ThreadPlanShouldStopHere::DefaultStepFromHereCallback Queueing StepInRange plan to step through line 0 code."); - - return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange(false, - range, - sc, - NULL, - eOnlyDuringStepping, - eLazyBoolCalculate, - eLazyBoolNo); - } - } - - if (!return_plan_sp) - return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop(false, - nullptr, - true, - stop_others, - eVoteNo, - eVoteNoOpinion, - frame_index, - true); - return return_plan_sp; + should_stop_here = false; + } + + return should_stop_here; } -ThreadPlanSP -ThreadPlanShouldStopHere::QueueStepOutFromHerePlan(lldb_private::Flags &flags, lldb::FrameComparison operation) -{ - ThreadPlanSP return_plan_sp; - if (m_callbacks.step_from_here_callback) - { - return_plan_sp = m_callbacks.step_from_here_callback (m_owner, flags, operation, m_baton); - } +ThreadPlanSP ThreadPlanShouldStopHere::DefaultStepFromHereCallback( + ThreadPlan *current_plan, Flags &flags, FrameComparison operation, + void *baton) { + const bool stop_others = false; + const size_t frame_index = 0; + ThreadPlanSP return_plan_sp; + // If we are stepping through code at line number 0, then we need to step over + // this range. Otherwise + // we will step out. + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); + if (!frame) return return_plan_sp; + SymbolContext sc; + sc = frame->GetSymbolContext(eSymbolContextLineEntry | eSymbolContextSymbol); + + if (sc.line_entry.line == 0) { + AddressRange range = sc.line_entry.range; + + // If the whole function is marked line 0 just step out, that's easier & + // faster than continuing + // to step through it. + bool just_step_out = false; + if (sc.symbol && sc.symbol->ValueIsAddress()) { + Address symbol_end = sc.symbol->GetAddress(); + symbol_end.Slide(sc.symbol->GetByteSize() - 1); + if (range.ContainsFileAddress(sc.symbol->GetAddress()) && + range.ContainsFileAddress(symbol_end)) { + if (log) + log->Printf("Stopped in a function with only line 0 lines, just " + "stepping out."); + just_step_out = true; + } + } + if (!just_step_out) { + if (log) + log->Printf("ThreadPlanShouldStopHere::DefaultStepFromHereCallback " + "Queueing StepInRange plan to step through line 0 code."); + + return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepInRange( + false, range, sc, NULL, eOnlyDuringStepping, eLazyBoolCalculate, + eLazyBoolNo); + } + } + + if (!return_plan_sp) + return_plan_sp = + current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop( + false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, + frame_index, true); + return return_plan_sp; +} + +ThreadPlanSP ThreadPlanShouldStopHere::QueueStepOutFromHerePlan( + lldb_private::Flags &flags, lldb::FrameComparison operation) { + ThreadPlanSP return_plan_sp; + if (m_callbacks.step_from_here_callback) { + return_plan_sp = + m_callbacks.step_from_here_callback(m_owner, flags, operation, m_baton); + } + return return_plan_sp; } -lldb::ThreadPlanSP -ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut (lldb::FrameComparison operation) -{ - if (!InvokeShouldStopHereCallback(operation)) - return QueueStepOutFromHerePlan(m_flags, operation); - else - return ThreadPlanSP(); +lldb::ThreadPlanSP ThreadPlanShouldStopHere::CheckShouldStopHereAndQueueStepOut( + lldb::FrameComparison operation) { + if (!InvokeShouldStopHereCallback(operation)) + return QueueStepOutFromHerePlan(m_flags, operation); + else + return ThreadPlanSP(); } diff --git a/lldb/source/Target/ThreadPlanStepInRange.cpp b/lldb/source/Target/ThreadPlanStepInRange.cpp index 3771e210c1a..3eece2fc41b 100644 --- a/lldb/source/Target/ThreadPlanStepInRange.cpp +++ b/lldb/source/Target/ThreadPlanStepInRange.cpp @@ -14,526 +14,493 @@ #include "lldb/Target/ThreadPlanStepInRange.h" #include "lldb/Core/Log.h" #include "lldb/Core/Module.h" +#include "lldb/Core/RegularExpression.h" #include "lldb/Core/Stream.h" -#include "lldb/Symbol/Symbol.h" #include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" #include "lldb/Target/Thread.h" #include "lldb/Target/ThreadPlanStepOut.h" #include "lldb/Target/ThreadPlanStepThrough.h" -#include "lldb/Core/RegularExpression.h" using namespace lldb; using namespace lldb_private; -uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eStepInAvoidNoDebug; +uint32_t ThreadPlanStepInRange::s_default_flag_values = + ThreadPlanShouldStopHere::eStepInAvoidNoDebug; //---------------------------------------------------------------------- -// ThreadPlanStepInRange: Step through a stack range, either stepping over or into +// ThreadPlanStepInRange: Step through a stack range, either stepping over or +// into // based on the value of \a type. //---------------------------------------------------------------------- -ThreadPlanStepInRange::ThreadPlanStepInRange -( - Thread &thread, - const AddressRange &range, - const SymbolContext &addr_context, - lldb::RunMode stop_others, +ThreadPlanStepInRange::ThreadPlanStepInRange( + Thread &thread, const AddressRange &range, + const SymbolContext &addr_context, lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info -) : - ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), - ThreadPlanShouldStopHere (this), - m_step_past_prologue (true), - m_virtual_step (false) -{ - SetCallbacks(); - SetFlagsToDefault (); - SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info); + LazyBool step_out_avoids_code_without_debug_info) + : ThreadPlanStepRange(ThreadPlan::eKindStepInRange, + "Step Range stepping in", thread, range, addr_context, + stop_others), + ThreadPlanShouldStopHere(this), m_step_past_prologue(true), + m_virtual_step(false) { + SetCallbacks(); + SetFlagsToDefault(); + SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, + step_out_avoids_code_without_debug_info); } -ThreadPlanStepInRange::ThreadPlanStepInRange -( - Thread &thread, - const AddressRange &range, - const SymbolContext &addr_context, - const char *step_into_target, - lldb::RunMode stop_others, - LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info -) : - ThreadPlanStepRange (ThreadPlan::eKindStepInRange, "Step Range stepping in", thread, range, addr_context, stop_others), - ThreadPlanShouldStopHere (this), - m_step_past_prologue (true), - m_virtual_step (false), - m_step_into_target (step_into_target) -{ - SetCallbacks(); - SetFlagsToDefault (); - SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, step_out_avoids_code_without_debug_info); +ThreadPlanStepInRange::ThreadPlanStepInRange( + Thread &thread, const AddressRange &range, + const SymbolContext &addr_context, const char *step_into_target, + lldb::RunMode stop_others, LazyBool step_in_avoids_code_without_debug_info, + LazyBool step_out_avoids_code_without_debug_info) + : ThreadPlanStepRange(ThreadPlan::eKindStepInRange, + "Step Range stepping in", thread, range, addr_context, + stop_others), + ThreadPlanShouldStopHere(this), m_step_past_prologue(true), + m_virtual_step(false), m_step_into_target(step_into_target) { + SetCallbacks(); + SetFlagsToDefault(); + SetupAvoidNoDebug(step_in_avoids_code_without_debug_info, + step_out_avoids_code_without_debug_info); } ThreadPlanStepInRange::~ThreadPlanStepInRange() = default; -void -ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_debug_info, - LazyBool step_out_avoids_code_without_debug_info) -{ - bool avoid_nodebug = true; - - switch (step_in_avoids_code_without_debug_info) - { - case eLazyBoolYes: - avoid_nodebug = true; - break; - case eLazyBoolNo: - avoid_nodebug = false; - break; - case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepInAvoidsNoDebug(); - break; - } - if (avoid_nodebug) - GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); - else - GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); - - switch (step_out_avoids_code_without_debug_info) - { - case eLazyBoolYes: - avoid_nodebug = true; - break; - case eLazyBoolNo: - avoid_nodebug = false; - break; - case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); - break; - } - if (avoid_nodebug) - GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); - else - GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); +void ThreadPlanStepInRange::SetupAvoidNoDebug( + LazyBool step_in_avoids_code_without_debug_info, + LazyBool step_out_avoids_code_without_debug_info) { + bool avoid_nodebug = true; + + switch (step_in_avoids_code_without_debug_info) { + case eLazyBoolYes: + avoid_nodebug = true; + break; + case eLazyBoolNo: + avoid_nodebug = false; + break; + case eLazyBoolCalculate: + avoid_nodebug = m_thread.GetStepInAvoidsNoDebug(); + break; + } + if (avoid_nodebug) + GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); + else + GetFlags().Clear(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); + + switch (step_out_avoids_code_without_debug_info) { + case eLazyBoolYes: + avoid_nodebug = true; + break; + case eLazyBoolNo: + avoid_nodebug = false; + break; + case eLazyBoolCalculate: + avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + break; + } + if (avoid_nodebug) + GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + else + GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); } -void -ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - { - s->Printf("step in"); - return; - } +void ThreadPlanStepInRange::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) { + s->Printf("step in"); + return; + } - s->Printf ("Stepping in"); - bool printed_line_info = false; - if (m_addr_context.line_entry.IsValid()) - { - s->Printf (" through line "); - m_addr_context.line_entry.DumpStopContext (s, false); - printed_line_info = true; - } + s->Printf("Stepping in"); + bool printed_line_info = false; + if (m_addr_context.line_entry.IsValid()) { + s->Printf(" through line "); + m_addr_context.line_entry.DumpStopContext(s, false); + printed_line_info = true; + } - const char *step_into_target = m_step_into_target.AsCString(); - if (step_into_target && step_into_target[0] != '\0') - s->Printf (" targeting %s", m_step_into_target.AsCString()); + const char *step_into_target = m_step_into_target.AsCString(); + if (step_into_target && step_into_target[0] != '\0') + s->Printf(" targeting %s", m_step_into_target.AsCString()); - if (!printed_line_info || level == eDescriptionLevelVerbose) - { - s->Printf (" using ranges:"); - DumpRanges(s); - } + if (!printed_line_info || level == eDescriptionLevelVerbose) { + s->Printf(" using ranges:"); + DumpRanges(s); + } - s->PutChar('.'); + s->PutChar('.'); } -bool -ThreadPlanStepInRange::ShouldStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if (log) - { - StreamString s; - s.Address (m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); - log->Printf("ThreadPlanStepInRange reached %s.", s.GetData()); - } +bool ThreadPlanStepInRange::ShouldStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (IsPlanComplete()) - return true; - - m_no_more_plans = false; - if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) - { - if (!m_sub_plan_sp->PlanSucceeded()) - { - SetPlanComplete(); - m_no_more_plans = true; - return true; - } - else - m_sub_plan_sp.reset(); + if (log) { + StreamString s; + s.Address( + m_thread.GetRegisterContext()->GetPC(), + m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + log->Printf("ThreadPlanStepInRange reached %s.", s.GetData()); + } + + if (IsPlanComplete()) + return true; + + m_no_more_plans = false; + if (m_sub_plan_sp && m_sub_plan_sp->IsPlanComplete()) { + if (!m_sub_plan_sp->PlanSucceeded()) { + SetPlanComplete(); + m_no_more_plans = true; + return true; + } else + m_sub_plan_sp.reset(); + } + + if (m_virtual_step) { + // If we've just completed a virtual step, all we need to do is check for a + // ShouldStopHere plan, and otherwise + // we're done. + // FIXME - This can be both a step in and a step out. Probably should + // record which in the m_virtual_step. + m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger); + } else { + // Stepping through should be done running other threads in general, since + // we're setting a breakpoint and + // continuing. So only stop others if we are explicitly told to do so. + + bool stop_others = (m_stop_others == lldb::eOnlyThisThread); + + FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + + if (frame_order == eFrameCompareOlder || + frame_order == eFrameCompareSameParent) { + // If we're in an older frame then we should stop. + // + // A caveat to this is if we think the frame is older but we're actually + // in a trampoline. + // I'm going to make the assumption that you wouldn't RETURN to a + // trampoline. So if we are + // in a trampoline we think the frame is older because the trampoline + // confused the backtracer. + m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others); + if (!m_sub_plan_sp) { + // Otherwise check the ShouldStopHere for step out: + m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + if (log) + log->Printf("ShouldStopHere says we should step out of this frame."); + } else if (log) { + log->Printf( + "Thought I stepped out, but in fact arrived at a trampoline."); + } + } else if (frame_order == eFrameCompareEqual && InSymbol()) { + // If we are not in a place we should step through, we're done. + // One tricky bit here is that some stubs don't push a frame, so we have + // to check + // both the case of a frame that is younger, or the same as this frame. + // However, if the frame is the same, and we are still in the symbol we + // started + // in, the we don't need to do this. This first check isn't strictly + // necessary, + // but it is more efficient. + + // If we're still in the range, keep going, either by running to the next + // branch breakpoint, or by + // stepping. + if (InRange()) { + SetNextBranchBreakpoint(); + return false; + } + + SetPlanComplete(); + m_no_more_plans = true; + return true; } - - if (m_virtual_step) - { - // If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise - // we're done. - // FIXME - This can be both a step in and a step out. Probably should record which in the m_virtual_step. - m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(eFrameCompareYounger); + + // If we get to this point, we're not going to use a previously set "next + // branch" breakpoint, so delete it: + ClearNextBranchBreakpoint(); + + // We may have set the plan up above in the FrameIsOlder section: + + if (!m_sub_plan_sp) + m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others); + + if (log) { + if (m_sub_plan_sp) + log->Printf("Found a step through plan: %s", m_sub_plan_sp->GetName()); + else + log->Printf("No step through plan found."); } - else - { - // Stepping through should be done running other threads in general, since we're setting a breakpoint and - // continuing. So only stop others if we are explicitly told to do so. - - bool stop_others = (m_stop_others == lldb::eOnlyThisThread); - - FrameComparison frame_order = CompareCurrentFrameToStartFrame(); - - if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent) - { - // If we're in an older frame then we should stop. - // - // A caveat to this is if we think the frame is older but we're actually in a trampoline. - // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are - // in a trampoline we think the frame is older because the trampoline confused the backtracer. - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - if (!m_sub_plan_sp) - { - // Otherwise check the ShouldStopHere for step out: - m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); - if (log) - log->Printf ("ShouldStopHere says we should step out of this frame."); - } - else if (log) - { - log->Printf("Thought I stepped out, but in fact arrived at a trampoline."); - } - } - else if (frame_order == eFrameCompareEqual && InSymbol()) - { - // If we are not in a place we should step through, we're done. - // One tricky bit here is that some stubs don't push a frame, so we have to check - // both the case of a frame that is younger, or the same as this frame. - // However, if the frame is the same, and we are still in the symbol we started - // in, the we don't need to do this. This first check isn't strictly necessary, - // but it is more efficient. - - // If we're still in the range, keep going, either by running to the next branch breakpoint, or by - // stepping. - if (InRange()) - { - SetNextBranchBreakpoint(); - return false; - } - - SetPlanComplete(); - m_no_more_plans = true; - return true; - } - - // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it: - ClearNextBranchBreakpoint(); - - // We may have set the plan up above in the FrameIsOlder section: - - if (!m_sub_plan_sp) - m_sub_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - - if (log) - { - if (m_sub_plan_sp) - log->Printf ("Found a step through plan: %s", m_sub_plan_sp->GetName()); - else - log->Printf ("No step through plan found."); + + // If not, give the "should_stop" callback a chance to push a plan to get us + // out of here. + // But only do that if we actually have stepped in. + if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) + m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + + // If we've stepped in and we are going to stop here, check to see if we + // were asked to + // run past the prologue, and if so do that. + + if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && + m_step_past_prologue) { + lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); + if (curr_frame) { + size_t bytes_to_skip = 0; + lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); + Address func_start_address; + + SymbolContext sc = curr_frame->GetSymbolContext(eSymbolContextFunction | + eSymbolContextSymbol); + + if (sc.function) { + func_start_address = sc.function->GetAddressRange().GetBaseAddress(); + if (curr_addr == + func_start_address.GetLoadAddress( + m_thread.CalculateTarget().get())) + bytes_to_skip = sc.function->GetPrologueByteSize(); + } else if (sc.symbol) { + func_start_address = sc.symbol->GetAddress(); + if (curr_addr == + func_start_address.GetLoadAddress( + m_thread.CalculateTarget().get())) + bytes_to_skip = sc.symbol->GetPrologueByteSize(); } - - // If not, give the "should_stop" callback a chance to push a plan to get us out of here. - // But only do that if we actually have stepped in. - if (!m_sub_plan_sp && frame_order == eFrameCompareYounger) - m_sub_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); - - // If we've stepped in and we are going to stop here, check to see if we were asked to - // run past the prologue, and if so do that. - - if (!m_sub_plan_sp && frame_order == eFrameCompareYounger && m_step_past_prologue) - { - lldb::StackFrameSP curr_frame = m_thread.GetStackFrameAtIndex(0); - if (curr_frame) - { - size_t bytes_to_skip = 0; - lldb::addr_t curr_addr = m_thread.GetRegisterContext()->GetPC(); - Address func_start_address; - - SymbolContext sc = curr_frame->GetSymbolContext (eSymbolContextFunction | eSymbolContextSymbol); - - if (sc.function) - { - func_start_address = sc.function->GetAddressRange().GetBaseAddress(); - if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get())) - bytes_to_skip = sc.function->GetPrologueByteSize(); - } - else if (sc.symbol) - { - func_start_address = sc.symbol->GetAddress(); - if (curr_addr == func_start_address.GetLoadAddress(m_thread.CalculateTarget().get())) - bytes_to_skip = sc.symbol->GetPrologueByteSize(); - } - - if (bytes_to_skip != 0) - { - func_start_address.Slide (bytes_to_skip); - log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP); - if (log) - log->Printf ("Pushing past prologue "); - - m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress(false, func_start_address,true); - } - } + + if (bytes_to_skip != 0) { + func_start_address.Slide(bytes_to_skip); + log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP); + if (log) + log->Printf("Pushing past prologue "); + + m_sub_plan_sp = m_thread.QueueThreadPlanForRunToAddress( + false, func_start_address, true); } - } - - if (!m_sub_plan_sp) - { - m_no_more_plans = true; - SetPlanComplete(); - return true; - } - else - { - m_no_more_plans = false; - m_sub_plan_sp->SetPrivate(true); - return false; + } } + } + + if (!m_sub_plan_sp) { + m_no_more_plans = true; + SetPlanComplete(); + return true; + } else { + m_no_more_plans = false; + m_sub_plan_sp->SetPrivate(true); + return false; + } } -void -ThreadPlanStepInRange::SetAvoidRegexp(const char *name) -{ - if (!m_avoid_regexp_ap) - m_avoid_regexp_ap.reset (new RegularExpression(name)); +void ThreadPlanStepInRange::SetAvoidRegexp(const char *name) { + if (!m_avoid_regexp_ap) + m_avoid_regexp_ap.reset(new RegularExpression(name)); - m_avoid_regexp_ap->Compile (name); + m_avoid_regexp_ap->Compile(name); } -void -ThreadPlanStepInRange::SetDefaultFlagValue (uint32_t new_value) -{ - // TODO: Should we test this for sanity? - ThreadPlanStepInRange::s_default_flag_values = new_value; +void ThreadPlanStepInRange::SetDefaultFlagValue(uint32_t new_value) { + // TODO: Should we test this for sanity? + ThreadPlanStepInRange::s_default_flag_values = new_value; } -bool -ThreadPlanStepInRange::FrameMatchesAvoidCriteria () -{ - StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); - - // Check the library list first, as that's cheapest: - bool libraries_say_avoid = false; - - FileSpecList libraries_to_avoid (GetThread().GetLibrariesToAvoid()); - size_t num_libraries = libraries_to_avoid.GetSize(); - if (num_libraries > 0) - { - SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule)); - FileSpec frame_library(sc.module_sp->GetFileSpec()); - - if (frame_library) - { - for (size_t i = 0; i < num_libraries; i++) - { - const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i)); - if (FileSpec::Equal (file_spec, frame_library, false)) - { - libraries_say_avoid = true; - break; - } - } +bool ThreadPlanStepInRange::FrameMatchesAvoidCriteria() { + StackFrame *frame = GetThread().GetStackFrameAtIndex(0).get(); + + // Check the library list first, as that's cheapest: + bool libraries_say_avoid = false; + + FileSpecList libraries_to_avoid(GetThread().GetLibrariesToAvoid()); + size_t num_libraries = libraries_to_avoid.GetSize(); + if (num_libraries > 0) { + SymbolContext sc(frame->GetSymbolContext(eSymbolContextModule)); + FileSpec frame_library(sc.module_sp->GetFileSpec()); + + if (frame_library) { + for (size_t i = 0; i < num_libraries; i++) { + const FileSpec &file_spec(libraries_to_avoid.GetFileSpecAtIndex(i)); + if (FileSpec::Equal(file_spec, frame_library, false)) { + libraries_say_avoid = true; + break; } + } } - if (libraries_say_avoid) - return true; - - const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get(); - if (avoid_regexp_to_use == nullptr) - avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); - - if (avoid_regexp_to_use != nullptr) - { - SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); - if (sc.symbol != nullptr) - { - const char *frame_function_name = sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments).GetCString(); - if (frame_function_name) - { - size_t num_matches = 0; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - num_matches = 1; - - RegularExpression::Match regex_match(num_matches); - - bool return_value = avoid_regexp_to_use->Execute(frame_function_name, ®ex_match); - if (return_value) - { - if (log) - { - std::string match; - regex_match.GetMatchAtIndex(frame_function_name,0, match); - log->Printf ("Stepping out of function \"%s\" because it matches the avoid regexp \"%s\" - match substring: \"%s\".", - frame_function_name, - avoid_regexp_to_use->GetText(), - match.c_str()); - } - - } - return return_value; - } + } + if (libraries_say_avoid) + return true; + + const RegularExpression *avoid_regexp_to_use = m_avoid_regexp_ap.get(); + if (avoid_regexp_to_use == nullptr) + avoid_regexp_to_use = GetThread().GetSymbolsToAvoidRegexp(); + + if (avoid_regexp_to_use != nullptr) { + SymbolContext sc = frame->GetSymbolContext( + eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol); + if (sc.symbol != nullptr) { + const char *frame_function_name = + sc.GetFunctionName(Mangled::ePreferDemangledWithoutArguments) + .GetCString(); + if (frame_function_name) { + size_t num_matches = 0; + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + num_matches = 1; + + RegularExpression::Match regex_match(num_matches); + + bool return_value = + avoid_regexp_to_use->Execute(frame_function_name, ®ex_match); + if (return_value) { + if (log) { + std::string match; + regex_match.GetMatchAtIndex(frame_function_name, 0, match); + log->Printf("Stepping out of function \"%s\" because it matches " + "the avoid regexp \"%s\" - match substring: \"%s\".", + frame_function_name, avoid_regexp_to_use->GetText(), + match.c_str()); + } } + return return_value; + } } - return false; + } + return false; } -bool -ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, FrameComparison operation, void *baton) -{ - bool should_stop_here = true; - StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - // First see if the ThreadPlanShouldStopHere default implementation thinks we should get out of here: - should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback (current_plan, flags, operation, baton); - if (!should_stop_here) - return should_stop_here; - - if (should_stop_here && current_plan->GetKind() == eKindStepInRange && operation == eFrameCompareYounger) - { - ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); - if (step_in_range_plan->m_step_into_target) - { - SymbolContext sc = frame->GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock|eSymbolContextSymbol); - if (sc.symbol != nullptr) - { - // First try an exact match, since that's cheap with ConstStrings. Then do a strstr compare. - if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) - { - should_stop_here = true; - } - else - { - const char *target_name = step_in_range_plan->m_step_into_target.AsCString(); - const char *function_name = sc.GetFunctionName().AsCString(); - - if (function_name == nullptr) - should_stop_here = false; - else if (strstr(function_name, target_name) == nullptr) - should_stop_here = false; - } - if (log && !should_stop_here) - log->Printf("Stepping out of frame %s which did not match step into target %s.", - sc.GetFunctionName().AsCString(), - step_in_range_plan->m_step_into_target.AsCString()); - } - } - - if (should_stop_here) - { - ThreadPlanStepInRange *step_in_range_plan = static_cast<ThreadPlanStepInRange *> (current_plan); - // Don't log the should_step_out here, it's easier to do it in FrameMatchesAvoidCriteria. - should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria (); - } - } - +bool ThreadPlanStepInRange::DefaultShouldStopHereCallback( + ThreadPlan *current_plan, Flags &flags, FrameComparison operation, + void *baton) { + bool should_stop_here = true; + StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get(); + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + // First see if the ThreadPlanShouldStopHere default implementation thinks we + // should get out of here: + should_stop_here = ThreadPlanShouldStopHere::DefaultShouldStopHereCallback( + current_plan, flags, operation, baton); + if (!should_stop_here) return should_stop_here; -} -bool -ThreadPlanStepInRange::DoPlanExplainsStop (Event *event_ptr) -{ - // We always explain a stop. Either we've just done a single step, in which - // case we'll do our ordinary processing, or we stopped for some - // reason that isn't handled by our sub-plans, in which case we want to just stop right - // away. - // In general, we don't want to mark the plan as complete for unexplained stops. - // For instance, if you step in to some code with no debug info, so you step out - // and in the course of that hit a breakpoint, then you want to stop & show the user - // the breakpoint, but not unship the step in plan, since you still may want to complete that - // plan when you continue. This is particularly true when doing "step in to target function." - // stepping. - // - // The only variation is that if we are doing "step by running to next branch" in which case - // if we hit our branch breakpoint we don't set the plan to complete. - - bool return_value = false; - - if (m_virtual_step) - { - return_value = true; - } - else - { - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - - if (reason == eStopReasonBreakpoint) - { - if (NextRangeBreakpointExplainsStop(stop_info_sp)) - { - return_value = true; - } - } - else if (IsUsuallyUnexplainedStopReason(reason)) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); - return_value = false; - } - else - { - return_value = true; - } + if (should_stop_here && current_plan->GetKind() == eKindStepInRange && + operation == eFrameCompareYounger) { + ThreadPlanStepInRange *step_in_range_plan = + static_cast<ThreadPlanStepInRange *>(current_plan); + if (step_in_range_plan->m_step_into_target) { + SymbolContext sc = frame->GetSymbolContext( + eSymbolContextFunction | eSymbolContextBlock | eSymbolContextSymbol); + if (sc.symbol != nullptr) { + // First try an exact match, since that's cheap with ConstStrings. Then + // do a strstr compare. + if (step_in_range_plan->m_step_into_target == sc.GetFunctionName()) { + should_stop_here = true; + } else { + const char *target_name = + step_in_range_plan->m_step_into_target.AsCString(); + const char *function_name = sc.GetFunctionName().AsCString(); + + if (function_name == nullptr) + should_stop_here = false; + else if (strstr(function_name, target_name) == nullptr) + should_stop_here = false; } - else - return_value = true; + if (log && !should_stop_here) + log->Printf("Stepping out of frame %s which did not match step into " + "target %s.", + sc.GetFunctionName().AsCString(), + step_in_range_plan->m_step_into_target.AsCString()); + } } - - return return_value; + + if (should_stop_here) { + ThreadPlanStepInRange *step_in_range_plan = + static_cast<ThreadPlanStepInRange *>(current_plan); + // Don't log the should_step_out here, it's easier to do it in + // FrameMatchesAvoidCriteria. + should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria(); + } + } + + return should_stop_here; } -bool -ThreadPlanStepInRange::DoWillResume (lldb::StateType resume_state, bool current_plan) -{ - m_virtual_step = false; - if (resume_state == eStateStepping && current_plan) - { - // See if we are about to step over a virtual inlined call. - bool step_without_resume = m_thread.DecrementCurrentInlinedDepth(); - if (step_without_resume) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("ThreadPlanStepInRange::DoWillResume: returning false, inline_depth: %d", - m_thread.GetCurrentInlinedDepth()); - SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread)); - - // FIXME: Maybe it would be better to create a InlineStep stop reason, but then - // the whole rest of the world would have to handle that stop reason. - m_virtual_step = true; +bool ThreadPlanStepInRange::DoPlanExplainsStop(Event *event_ptr) { + // We always explain a stop. Either we've just done a single step, in which + // case we'll do our ordinary processing, or we stopped for some + // reason that isn't handled by our sub-plans, in which case we want to just + // stop right + // away. + // In general, we don't want to mark the plan as complete for unexplained + // stops. + // For instance, if you step in to some code with no debug info, so you step + // out + // and in the course of that hit a breakpoint, then you want to stop & show + // the user + // the breakpoint, but not unship the step in plan, since you still may want + // to complete that + // plan when you continue. This is particularly true when doing "step in to + // target function." + // stepping. + // + // The only variation is that if we are doing "step by running to next branch" + // in which case + // if we hit our branch breakpoint we don't set the plan to complete. + + bool return_value = false; + + if (m_virtual_step) { + return_value = true; + } else { + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + + if (reason == eStopReasonBreakpoint) { + if (NextRangeBreakpointExplainsStop(stop_info_sp)) { + return_value = true; } - return !step_without_resume; - } - return true; + } else if (IsUsuallyUnexplainedStopReason(reason)) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->PutCString("ThreadPlanStepInRange got asked if it explains the " + "stop for some reason other than step."); + return_value = false; + } else { + return_value = true; + } + } else + return_value = true; + } + + return return_value; } -bool -ThreadPlanStepInRange::IsVirtualStep() -{ - return m_virtual_step; +bool ThreadPlanStepInRange::DoWillResume(lldb::StateType resume_state, + bool current_plan) { + m_virtual_step = false; + if (resume_state == eStateStepping && current_plan) { + // See if we are about to step over a virtual inlined call. + bool step_without_resume = m_thread.DecrementCurrentInlinedDepth(); + if (step_without_resume) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("ThreadPlanStepInRange::DoWillResume: returning false, " + "inline_depth: %d", + m_thread.GetCurrentInlinedDepth()); + SetStopInfo(StopInfo::CreateStopReasonToTrace(m_thread)); + + // FIXME: Maybe it would be better to create a InlineStep stop reason, but + // then + // the whole rest of the world would have to handle that stop reason. + m_virtual_step = true; + } + return !step_without_resume; + } + return true; } + +bool ThreadPlanStepInRange::IsVirtualStep() { return m_virtual_step; } diff --git a/lldb/source/Target/ThreadPlanStepInstruction.cpp b/lldb/source/Target/ThreadPlanStepInstruction.cpp index ccfd52e00e1..6ad6a2343a5 100644 --- a/lldb/source/Target/ThreadPlanStepInstruction.cpp +++ b/lldb/source/Target/ThreadPlanStepInstruction.cpp @@ -27,270 +27,218 @@ using namespace lldb_private; // ThreadPlanStepInstruction: Step over the current instruction //---------------------------------------------------------------------- -ThreadPlanStepInstruction::ThreadPlanStepInstruction -( - Thread &thread, - bool step_over, - bool stop_other_threads, - Vote stop_vote, - Vote run_vote -) : - ThreadPlan (ThreadPlan::eKindStepInstruction, "Step over single instruction", thread, stop_vote, run_vote), - m_instruction_addr (0), - m_stop_other_threads (stop_other_threads), - m_step_over (step_over) -{ - m_takes_iteration_count = true; - SetUpState(); +ThreadPlanStepInstruction::ThreadPlanStepInstruction(Thread &thread, + bool step_over, + bool stop_other_threads, + Vote stop_vote, + Vote run_vote) + : ThreadPlan(ThreadPlan::eKindStepInstruction, + "Step over single instruction", thread, stop_vote, run_vote), + m_instruction_addr(0), m_stop_other_threads(stop_other_threads), + m_step_over(step_over) { + m_takes_iteration_count = true; + SetUpState(); } ThreadPlanStepInstruction::~ThreadPlanStepInstruction() = default; -void -ThreadPlanStepInstruction::SetUpState() -{ - m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); - StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); - m_stack_id = start_frame_sp->GetStackID(); - - m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr; - - StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1); - if (parent_frame_sp) - m_parent_frame_id = parent_frame_sp->GetStackID(); +void ThreadPlanStepInstruction::SetUpState() { + m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0); + StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0)); + m_stack_id = start_frame_sp->GetStackID(); + + m_start_has_symbol = + start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != nullptr; + + StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1); + if (parent_frame_sp) + m_parent_frame_id = parent_frame_sp->GetStackID(); } -void -ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - { - if (m_step_over) - s->Printf ("instruction step over"); - else - s->Printf ("instruction step into"); - } +void ThreadPlanStepInstruction::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) { + if (m_step_over) + s->Printf("instruction step over"); else - { - s->Printf ("Stepping one instruction past "); - s->Address(m_instruction_addr, sizeof (addr_t)); - if (!m_start_has_symbol) - s->Printf(" which has no symbol"); - - if (m_step_over) - s->Printf(" stepping over calls"); - else - s->Printf(" stepping into calls"); - } + s->Printf("instruction step into"); + } else { + s->Printf("Stepping one instruction past "); + s->Address(m_instruction_addr, sizeof(addr_t)); + if (!m_start_has_symbol) + s->Printf(" which has no symbol"); + + if (m_step_over) + s->Printf(" stepping over calls"); + else + s->Printf(" stepping into calls"); + } } -bool -ThreadPlanStepInstruction::ValidatePlan (Stream *error) -{ - // Since we read the instruction we're stepping over from the thread, - // this plan will always work. - return true; +bool ThreadPlanStepInstruction::ValidatePlan(Stream *error) { + // Since we read the instruction we're stepping over from the thread, + // this plan will always work. + return true; } -bool -ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr) -{ - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - return (reason == eStopReasonTrace || reason == eStopReasonNone); - } - return false; +bool ThreadPlanStepInstruction::DoPlanExplainsStop(Event *event_ptr) { + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + return (reason == eStopReasonTrace || reason == eStopReasonNone); + } + return false; } -bool -ThreadPlanStepInstruction::IsPlanStale () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - if (cur_frame_id == m_stack_id) - { - return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); - } - else if (cur_frame_id < m_stack_id) - { - // If the current frame is younger than the start frame and we are stepping over, then we need to continue, - // but if we are doing just one step, we're done. - return !m_step_over; - } - else - { - if (log) - { - log->Printf ("ThreadPlanStepInstruction::IsPlanStale - Current frame is older than start frame, plan is stale."); - } - return true; +bool ThreadPlanStepInstruction::IsPlanStale() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + if (cur_frame_id == m_stack_id) { + return (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr); + } else if (cur_frame_id < m_stack_id) { + // If the current frame is younger than the start frame and we are stepping + // over, then we need to continue, + // but if we are doing just one step, we're done. + return !m_step_over; + } else { + if (log) { + log->Printf("ThreadPlanStepInstruction::IsPlanStale - Current frame is " + "older than start frame, plan is stale."); } + return true; + } } -bool -ThreadPlanStepInstruction::ShouldStop (Event *event_ptr) -{ - if (m_step_over) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); - if (!cur_frame_sp) - { - if (log) - log->Printf ("ThreadPlanStepInstruction couldn't get the 0th frame, stopping."); - SetPlanComplete(); - return true; - } - - StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); - - if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) - { - if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) - { - if (--m_iteration_count <= 0) - { - SetPlanComplete(); - return true; - } - else - { - // We are still stepping, reset the start pc, and in case we've stepped out, - // reset the current stack id. - SetUpState(); - return false; - } - } - else - return false; - } - else - { - // We've stepped in, step back out again: - StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); - if (return_frame) - { - if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol) - { - // next-instruction shouldn't step out of inlined functions. But we may have stepped into a - // real function that starts with an inlined function, and we do want to step out of that... - - if (cur_frame_sp->IsInlined()) - { - StackFrameSP parent_frame_sp = m_thread.GetFrameWithStackID(m_stack_id); - - if(parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == cur_frame_sp->GetConcreteFrameIndex()) - { - SetPlanComplete(); - if (log) - { - log->Printf("Frame we stepped into is inlined into the frame we were stepping from, stopping."); - } - return true; - } - } +bool ThreadPlanStepInstruction::ShouldStop(Event *event_ptr) { + if (m_step_over) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0); + if (!cur_frame_sp) { + if (log) + log->Printf( + "ThreadPlanStepInstruction couldn't get the 0th frame, stopping."); + SetPlanComplete(); + return true; + } - if (log) - { - StreamString s; - s.PutCString ("Stepped in to: "); - addr_t stop_addr = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); - s.Address (stop_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); - s.PutCString (" stepping out to: "); - addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); - s.Address (return_addr, m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); - log->Printf("%s.", s.GetData()); - } - - // StepInstruction should probably have the tri-state RunMode, but for now it is safer to - // run others. - const bool stop_others = false; - m_thread.QueueThreadPlanForStepOutNoShouldStop(false, - nullptr, - true, - stop_others, - eVoteNo, - eVoteNoOpinion, - 0); - return false; - } - else - { - if (log) - { - log->PutCString("The stack id we are stepping in changed, but our parent frame did not when stepping from code with no symbols. " - "We are probably just confused about where we are, stopping."); - } - SetPlanComplete(); - return true; - } - } - else - { - if (log) - log->Printf("Could not find previous frame, stopping."); - SetPlanComplete(); - return true; - } + StackID cur_frame_zero_id = cur_frame_sp->GetStackID(); + + if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id) { + if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr) { + if (--m_iteration_count <= 0) { + SetPlanComplete(); + return true; + } else { + // We are still stepping, reset the start pc, and in case we've + // stepped out, + // reset the current stack id. + SetUpState(); + return false; } - } - else - { - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0); - if (pc_addr != m_instruction_addr) - { - if (--m_iteration_count <= 0) - { - SetPlanComplete(); - return true; - } - else - { - // We are still stepping, reset the start pc, and in case we've stepped in or out, - // reset the current stack id. - SetUpState(); - return false; + } else + return false; + } else { + // We've stepped in, step back out again: + StackFrame *return_frame = m_thread.GetStackFrameAtIndex(1).get(); + if (return_frame) { + if (return_frame->GetStackID() != m_parent_frame_id || + m_start_has_symbol) { + // next-instruction shouldn't step out of inlined functions. But we + // may have stepped into a + // real function that starts with an inlined function, and we do want + // to step out of that... + + if (cur_frame_sp->IsInlined()) { + StackFrameSP parent_frame_sp = + m_thread.GetFrameWithStackID(m_stack_id); + + if (parent_frame_sp && + parent_frame_sp->GetConcreteFrameIndex() == + cur_frame_sp->GetConcreteFrameIndex()) { + SetPlanComplete(); + if (log) { + log->Printf("Frame we stepped into is inlined into the frame " + "we were stepping from, stopping."); + } + return true; } + } + + if (log) { + StreamString s; + s.PutCString("Stepped in to: "); + addr_t stop_addr = + m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); + s.Address(stop_addr, m_thread.CalculateTarget() + ->GetArchitecture() + .GetAddressByteSize()); + s.PutCString(" stepping out to: "); + addr_t return_addr = return_frame->GetRegisterContext()->GetPC(); + s.Address(return_addr, m_thread.CalculateTarget() + ->GetArchitecture() + .GetAddressByteSize()); + log->Printf("%s.", s.GetData()); + } + + // StepInstruction should probably have the tri-state RunMode, but for + // now it is safer to + // run others. + const bool stop_others = false; + m_thread.QueueThreadPlanForStepOutNoShouldStop( + false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0); + return false; + } else { + if (log) { + log->PutCString( + "The stack id we are stepping in changed, but our parent frame " + "did not when stepping from code with no symbols. " + "We are probably just confused about where we are, stopping."); + } + SetPlanComplete(); + return true; } - else - return false; + } else { + if (log) + log->Printf("Could not find previous frame, stopping."); + SetPlanComplete(); + return true; + } } + } else { + lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(0); + if (pc_addr != m_instruction_addr) { + if (--m_iteration_count <= 0) { + SetPlanComplete(); + return true; + } else { + // We are still stepping, reset the start pc, and in case we've stepped + // in or out, + // reset the current stack id. + SetUpState(); + return false; + } + } else + return false; + } } -bool -ThreadPlanStepInstruction::StopOthers () -{ - return m_stop_other_threads; -} +bool ThreadPlanStepInstruction::StopOthers() { return m_stop_other_threads; } -StateType -ThreadPlanStepInstruction::GetPlanRunState () -{ - return eStateStepping; +StateType ThreadPlanStepInstruction::GetPlanRunState() { + return eStateStepping; } -bool -ThreadPlanStepInstruction::WillStop () -{ - return true; -} +bool ThreadPlanStepInstruction::WillStop() { return true; } -bool -ThreadPlanStepInstruction::MischiefManaged () -{ - if (IsPlanComplete()) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Completed single instruction step plan."); - ThreadPlan::MischiefManaged (); - return true; - } - else - { - return false; - } +bool ThreadPlanStepInstruction::MischiefManaged() { + if (IsPlanComplete()) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Completed single instruction step plan."); + ThreadPlan::MischiefManaged(); + return true; + } else { + return false; + } } diff --git a/lldb/source/Target/ThreadPlanStepOut.cpp b/lldb/source/Target/ThreadPlanStepOut.cpp index 55f8818d689..b8d6e6dcba9 100644 --- a/lldb/source/Target/ThreadPlanStepOut.cpp +++ b/lldb/source/Target/ThreadPlanStepOut.cpp @@ -36,529 +36,450 @@ uint32_t ThreadPlanStepOut::s_default_flag_values = 0; //---------------------------------------------------------------------- // ThreadPlanStepOut: Step out of the current frame //---------------------------------------------------------------------- -ThreadPlanStepOut::ThreadPlanStepOut -( - Thread &thread, - SymbolContext *context, - bool first_insn, - bool stop_others, - Vote stop_vote, - Vote run_vote, - uint32_t frame_idx, +ThreadPlanStepOut::ThreadPlanStepOut( + Thread &thread, SymbolContext *context, bool first_insn, bool stop_others, + Vote stop_vote, Vote run_vote, uint32_t frame_idx, LazyBool step_out_avoids_code_without_debug_info, - bool continue_to_next_branch, - bool gather_return_value -) : - ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote), - ThreadPlanShouldStopHere (this), - m_step_from_insn (LLDB_INVALID_ADDRESS), - m_return_bp_id (LLDB_INVALID_BREAK_ID), - m_return_addr (LLDB_INVALID_ADDRESS), - m_stop_others (stop_others), - m_immediate_step_from_function(nullptr), - m_calculate_return_value(gather_return_value) -{ - SetFlagsToDefault(); - SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); - - m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); - - StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); - StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (frame_idx)); - - if (!return_frame_sp || !immediate_return_from_sp) - return; // we can't do anything here. ValidatePlan() will return false. - - m_step_out_to_id = return_frame_sp->GetStackID(); - m_immediate_step_from_id = immediate_return_from_sp->GetStackID(); - - // If the frame directly below the one we are returning to is inlined, we have to be - // a little more careful. It is non-trivial to determine the real "return code address" for - // an inlined frame, so we have to work our way to that frame and then step out. - if (immediate_return_from_sp && immediate_return_from_sp->IsInlined()) - { - if (frame_idx > 0) - { - // First queue a plan that gets us to this inlined frame, and when we get there we'll queue a second - // plan that walks us out of this frame. - m_step_out_to_inline_plan_sp.reset(new ThreadPlanStepOut(m_thread, - nullptr, - false, - stop_others, - eVoteNoOpinion, - eVoteNoOpinion, - frame_idx - 1, - eLazyBoolNo, - continue_to_next_branch)); - static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr); - m_step_out_to_inline_plan_sp->SetPrivate(true); - } - else - { - // If we're already at the inlined frame we're stepping through, then just do that now. - QueueInlinedStepPlan(false); - } + bool continue_to_next_branch, bool gather_return_value) + : ThreadPlan(ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, + run_vote), + ThreadPlanShouldStopHere(this), m_step_from_insn(LLDB_INVALID_ADDRESS), + m_return_bp_id(LLDB_INVALID_BREAK_ID), + m_return_addr(LLDB_INVALID_ADDRESS), m_stop_others(stop_others), + m_immediate_step_from_function(nullptr), + m_calculate_return_value(gather_return_value) { + SetFlagsToDefault(); + SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); + + m_step_from_insn = m_thread.GetRegisterContext()->GetPC(0); + + StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1)); + StackFrameSP immediate_return_from_sp( + m_thread.GetStackFrameAtIndex(frame_idx)); + + if (!return_frame_sp || !immediate_return_from_sp) + return; // we can't do anything here. ValidatePlan() will return false. + + m_step_out_to_id = return_frame_sp->GetStackID(); + m_immediate_step_from_id = immediate_return_from_sp->GetStackID(); + + // If the frame directly below the one we are returning to is inlined, we have + // to be + // a little more careful. It is non-trivial to determine the real "return + // code address" for + // an inlined frame, so we have to work our way to that frame and then step + // out. + if (immediate_return_from_sp && immediate_return_from_sp->IsInlined()) { + if (frame_idx > 0) { + // First queue a plan that gets us to this inlined frame, and when we get + // there we'll queue a second + // plan that walks us out of this frame. + m_step_out_to_inline_plan_sp.reset(new ThreadPlanStepOut( + m_thread, nullptr, false, stop_others, eVoteNoOpinion, eVoteNoOpinion, + frame_idx - 1, eLazyBoolNo, continue_to_next_branch)); + static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get()) + ->SetShouldStopHereCallbacks(nullptr, nullptr); + m_step_out_to_inline_plan_sp->SetPrivate(true); + } else { + // If we're already at the inlined frame we're stepping through, then just + // do that now. + QueueInlinedStepPlan(false); } - else if (return_frame_sp) - { - // Find the return address and set a breakpoint there: - // FIXME - can we do this more securely if we know first_insn? - - Address return_address (return_frame_sp->GetFrameCodeAddress()); - if (continue_to_next_branch) - { - SymbolContext return_address_sc; - AddressRange range; - Address return_address_decr_pc = return_address; - if (return_address_decr_pc.GetOffset() > 0) - return_address_decr_pc.Slide (-1); - - return_address_decr_pc.CalculateSymbolContext (&return_address_sc, lldb::eSymbolContextLineEntry); - if (return_address_sc.line_entry.IsValid()) - { - range = return_address_sc.line_entry.GetSameLineContiguousAddressRange(); - if (range.GetByteSize() > 0) - { - return_address = m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction (return_address, - range); - } - } - } - m_return_addr = return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); - - if (m_return_addr == LLDB_INVALID_ADDRESS) - return; - - Breakpoint *return_bp = m_thread.CalculateTarget()->CreateBreakpoint (m_return_addr, true, false).get(); - if (return_bp != nullptr) - { - return_bp->SetThreadID(m_thread.GetID()); - m_return_bp_id = return_bp->GetID(); - return_bp->SetBreakpointKind ("step-out"); - } - - if (immediate_return_from_sp) - { - const SymbolContext &sc = immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction); - if (sc.function) - { - m_immediate_step_from_function = sc.function; - } + } else if (return_frame_sp) { + // Find the return address and set a breakpoint there: + // FIXME - can we do this more securely if we know first_insn? + + Address return_address(return_frame_sp->GetFrameCodeAddress()); + if (continue_to_next_branch) { + SymbolContext return_address_sc; + AddressRange range; + Address return_address_decr_pc = return_address; + if (return_address_decr_pc.GetOffset() > 0) + return_address_decr_pc.Slide(-1); + + return_address_decr_pc.CalculateSymbolContext( + &return_address_sc, lldb::eSymbolContextLineEntry); + if (return_address_sc.line_entry.IsValid()) { + range = + return_address_sc.line_entry.GetSameLineContiguousAddressRange(); + if (range.GetByteSize() > 0) { + return_address = + m_thread.GetProcess()->AdvanceAddressToNextBranchInstruction( + return_address, range); } + } + } + m_return_addr = + return_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget()); + + if (m_return_addr == LLDB_INVALID_ADDRESS) + return; + + Breakpoint *return_bp = m_thread.CalculateTarget() + ->CreateBreakpoint(m_return_addr, true, false) + .get(); + if (return_bp != nullptr) { + return_bp->SetThreadID(m_thread.GetID()); + m_return_bp_id = return_bp->GetID(); + return_bp->SetBreakpointKind("step-out"); } -} -void -ThreadPlanStepOut::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info) -{ - bool avoid_nodebug = true; - switch (step_out_avoids_code_without_debug_info) - { - case eLazyBoolYes: - avoid_nodebug = true; - break; - case eLazyBoolNo: - avoid_nodebug = false; - break; - case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); - break; + if (immediate_return_from_sp) { + const SymbolContext &sc = + immediate_return_from_sp->GetSymbolContext(eSymbolContextFunction); + if (sc.function) { + m_immediate_step_from_function = sc.function; + } } - if (avoid_nodebug) - GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); - else - GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + } } -void -ThreadPlanStepOut::DidPush() -{ - if (m_step_out_to_inline_plan_sp) - m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); - else if (m_step_through_inline_plan_sp) - m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); +void ThreadPlanStepOut::SetupAvoidNoDebug( + LazyBool step_out_avoids_code_without_debug_info) { + bool avoid_nodebug = true; + switch (step_out_avoids_code_without_debug_info) { + case eLazyBoolYes: + avoid_nodebug = true; + break; + case eLazyBoolNo: + avoid_nodebug = false; + break; + case eLazyBoolCalculate: + avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + break; + } + if (avoid_nodebug) + GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + else + GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); } -ThreadPlanStepOut::~ThreadPlanStepOut () -{ - if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); +void ThreadPlanStepOut::DidPush() { + if (m_step_out_to_inline_plan_sp) + m_thread.QueueThreadPlan(m_step_out_to_inline_plan_sp, false); + else if (m_step_through_inline_plan_sp) + m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); } -void -ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - s->Printf ("step out"); - else - { - if (m_step_out_to_inline_plan_sp) - s->Printf ("Stepping out to inlined frame so we can walk through it."); - else if (m_step_through_inline_plan_sp) - s->Printf ("Stepping out by stepping through inlined function."); - else - { - s->Printf ("Stepping out from "); - Address tmp_address; - if (tmp_address.SetLoadAddress (m_step_from_insn, &GetTarget())) - { - tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); - } - else - { - s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); - } - - // FIXME: find some useful way to present the m_return_id, since there may be multiple copies of the - // same function on the stack. - - s->Printf (" returning to frame at "); - if (tmp_address.SetLoadAddress (m_return_addr, &GetTarget())) - { - tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress); - } - else - { - s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_return_addr); - } - - if (level == eDescriptionLevelVerbose) - s->Printf(" using breakpoint site %d", m_return_bp_id); - } - } +ThreadPlanStepOut::~ThreadPlanStepOut() { + if (m_return_bp_id != LLDB_INVALID_BREAK_ID) + m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); } -bool -ThreadPlanStepOut::ValidatePlan (Stream *error) -{ +void ThreadPlanStepOut::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) + s->Printf("step out"); + else { if (m_step_out_to_inline_plan_sp) - return m_step_out_to_inline_plan_sp->ValidatePlan (error); + s->Printf("Stepping out to inlined frame so we can walk through it."); else if (m_step_through_inline_plan_sp) - return m_step_through_inline_plan_sp->ValidatePlan (error); - else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) - { - if (error) - error->PutCString("Could not create return address breakpoint."); - return false; + s->Printf("Stepping out by stepping through inlined function."); + else { + s->Printf("Stepping out from "); + Address tmp_address; + if (tmp_address.SetLoadAddress(m_step_from_insn, &GetTarget())) { + tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, + Address::DumpStyleLoadAddress); + } else { + s->Printf("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn); + } + + // FIXME: find some useful way to present the m_return_id, since there may + // be multiple copies of the + // same function on the stack. + + s->Printf(" returning to frame at "); + if (tmp_address.SetLoadAddress(m_return_addr, &GetTarget())) { + tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, + Address::DumpStyleLoadAddress); + } else { + s->Printf("address 0x%" PRIx64 "", (uint64_t)m_return_addr); + } + + if (level == eDescriptionLevelVerbose) + s->Printf(" using breakpoint site %d", m_return_bp_id); } - else - return true; + } } -bool -ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr) -{ - // If the step out plan is done, then we just need to step through the inlined frame. - if (m_step_out_to_inline_plan_sp) - { - return m_step_out_to_inline_plan_sp->MischiefManaged(); - } - else if (m_step_through_inline_plan_sp) - { - if (m_step_through_inline_plan_sp->MischiefManaged()) - { - CalculateReturnValue(); - SetPlanComplete(); - return true; - } - else - return false; - } - else if (m_step_out_further_plan_sp) - { - return m_step_out_further_plan_sp->MischiefManaged(); - } - - // We don't explain signals or breakpoints (breakpoints that handle stepping in or - // out will be handled by a child plan. - - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - if (reason == eStopReasonBreakpoint) - { - // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... - BreakpointSiteSP site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue())); - if (site_sp && site_sp->IsBreakpointAtThisSite (m_return_bp_id)) - { - bool done; - - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - - if (m_step_out_to_id == frame_zero_id) - done = true; - else if (m_step_out_to_id < frame_zero_id) - { - // Either we stepped past the breakpoint, or the stack ID calculation - // was incorrect and we should probably stop. - done = true; - } - else - { - done = (m_immediate_step_from_id < frame_zero_id); - } - - if (done) - { - if (InvokeShouldStopHereCallback (eFrameCompareOlder)) - { - CalculateReturnValue(); - SetPlanComplete(); - } - } - - // If there was only one owner, then we're done. But if we also hit some - // user breakpoint on our way out, we should mark ourselves as done, but - // also not claim to explain the stop, since it is more important to report - // the user breakpoint than the step out completion. - - if (site_sp->GetNumberOfOwners() == 1) - return true; - } - return false; - } - else if (IsUsuallyUnexplainedStopReason(reason)) - return false; - else - return true; - } +bool ThreadPlanStepOut::ValidatePlan(Stream *error) { + if (m_step_out_to_inline_plan_sp) + return m_step_out_to_inline_plan_sp->ValidatePlan(error); + else if (m_step_through_inline_plan_sp) + return m_step_through_inline_plan_sp->ValidatePlan(error); + else if (m_return_bp_id == LLDB_INVALID_BREAK_ID) { + if (error) + error->PutCString("Could not create return address breakpoint."); + return false; + } else return true; } -bool -ThreadPlanStepOut::ShouldStop (Event *event_ptr) -{ - if (IsPlanComplete()) - return true; - - bool done = false; - if (m_step_out_to_inline_plan_sp) - { - if (m_step_out_to_inline_plan_sp->MischiefManaged()) - { - // Now step through the inlined stack we are in: - if (QueueInlinedStepPlan(true)) - { - // If we can't queue a plan to do this, then just call ourselves done. - m_step_out_to_inline_plan_sp.reset(); - SetPlanComplete (false); - return true; - } - else - done = true; - } - else - return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr); - } - else if (m_step_through_inline_plan_sp) - { - if (m_step_through_inline_plan_sp->MischiefManaged()) - done = true; - else - return m_step_through_inline_plan_sp->ShouldStop(event_ptr); - } - else if (m_step_out_further_plan_sp) - { - if (m_step_out_further_plan_sp->MischiefManaged()) - m_step_out_further_plan_sp.reset(); - else - return m_step_out_further_plan_sp->ShouldStop(event_ptr); - } +bool ThreadPlanStepOut::DoPlanExplainsStop(Event *event_ptr) { + // If the step out plan is done, then we just need to step through the inlined + // frame. + if (m_step_out_to_inline_plan_sp) { + return m_step_out_to_inline_plan_sp->MischiefManaged(); + } else if (m_step_through_inline_plan_sp) { + if (m_step_through_inline_plan_sp->MischiefManaged()) { + CalculateReturnValue(); + SetPlanComplete(); + return true; + } else + return false; + } else if (m_step_out_further_plan_sp) { + return m_step_out_further_plan_sp->MischiefManaged(); + } + + // We don't explain signals or breakpoints (breakpoints that handle stepping + // in or + // out will be handled by a child plan. + + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + if (reason == eStopReasonBreakpoint) { + // If this is OUR breakpoint, we're fine, otherwise we don't know why this + // happened... + BreakpointSiteSP site_sp( + m_thread.GetProcess()->GetBreakpointSiteList().FindByID( + stop_info_sp->GetValue())); + if (site_sp && site_sp->IsBreakpointAtThisSite(m_return_bp_id)) { + bool done; - if (!done) - { StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - done = !(frame_zero_id < m_step_out_to_id); - } - // The normal step out computations think we are done, so all we need to do is consult the ShouldStopHere, - // and we are done. - - if (done) - { - if (InvokeShouldStopHereCallback(eFrameCompareOlder)) - { + if (m_step_out_to_id == frame_zero_id) + done = true; + else if (m_step_out_to_id < frame_zero_id) { + // Either we stepped past the breakpoint, or the stack ID calculation + // was incorrect and we should probably stop. + done = true; + } else { + done = (m_immediate_step_from_id < frame_zero_id); + } + + if (done) { + if (InvokeShouldStopHereCallback(eFrameCompareOlder)) { CalculateReturnValue(); SetPlanComplete(); + } } - else - { - m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder); - done = false; - } - } - - return done; -} -bool -ThreadPlanStepOut::StopOthers () -{ - return m_stop_others; + // If there was only one owner, then we're done. But if we also hit + // some + // user breakpoint on our way out, we should mark ourselves as done, but + // also not claim to explain the stop, since it is more important to + // report + // the user breakpoint than the step out completion. + + if (site_sp->GetNumberOfOwners() == 1) + return true; + } + return false; + } else if (IsUsuallyUnexplainedStopReason(reason)) + return false; + else + return true; + } + return true; } -StateType -ThreadPlanStepOut::GetPlanRunState () -{ - return eStateRunning; -} +bool ThreadPlanStepOut::ShouldStop(Event *event_ptr) { + if (IsPlanComplete()) + return true; -bool -ThreadPlanStepOut::DoWillResume (StateType resume_state, bool current_plan) -{ - if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp) + bool done = false; + if (m_step_out_to_inline_plan_sp) { + if (m_step_out_to_inline_plan_sp->MischiefManaged()) { + // Now step through the inlined stack we are in: + if (QueueInlinedStepPlan(true)) { + // If we can't queue a plan to do this, then just call ourselves done. + m_step_out_to_inline_plan_sp.reset(); + SetPlanComplete(false); return true; - - if (m_return_bp_id == LLDB_INVALID_BREAK_ID) - return false; - - if (current_plan) - { - Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled (true); + } else + done = true; + } else + return m_step_out_to_inline_plan_sp->ShouldStop(event_ptr); + } else if (m_step_through_inline_plan_sp) { + if (m_step_through_inline_plan_sp->MischiefManaged()) + done = true; + else + return m_step_through_inline_plan_sp->ShouldStop(event_ptr); + } else if (m_step_out_further_plan_sp) { + if (m_step_out_further_plan_sp->MischiefManaged()) + m_step_out_further_plan_sp.reset(); + else + return m_step_out_further_plan_sp->ShouldStop(event_ptr); + } + + if (!done) { + StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + done = !(frame_zero_id < m_step_out_to_id); + } + + // The normal step out computations think we are done, so all we need to do is + // consult the ShouldStopHere, + // and we are done. + + if (done) { + if (InvokeShouldStopHereCallback(eFrameCompareOlder)) { + CalculateReturnValue(); + SetPlanComplete(); + } else { + m_step_out_further_plan_sp = + QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder); + done = false; } - return true; + } + + return done; } -bool -ThreadPlanStepOut::WillStop () -{ - if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - { - Breakpoint *return_bp = m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled (false); - } - +bool ThreadPlanStepOut::StopOthers() { return m_stop_others; } + +StateType ThreadPlanStepOut::GetPlanRunState() { return eStateRunning; } + +bool ThreadPlanStepOut::DoWillResume(StateType resume_state, + bool current_plan) { + if (m_step_out_to_inline_plan_sp || m_step_through_inline_plan_sp) return true; + + if (m_return_bp_id == LLDB_INVALID_BREAK_ID) + return false; + + if (current_plan) { + Breakpoint *return_bp = + m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(true); + } + return true; } -bool -ThreadPlanStepOut::MischiefManaged () -{ - if (IsPlanComplete()) - { - // Did I reach my breakpoint? If so I'm done. - // - // I also check the stack depth, since if we've blown past the breakpoint for some - // reason and we're now stopping for some other reason altogether, then we're done - // with this step out operation. - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Completed step out plan."); - if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - { - m_thread.CalculateTarget()->RemoveBreakpointByID (m_return_bp_id); - m_return_bp_id = LLDB_INVALID_BREAK_ID; - } - - ThreadPlan::MischiefManaged (); - return true; - } - else - { - return false; - } +bool ThreadPlanStepOut::WillStop() { + if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { + Breakpoint *return_bp = + m_thread.CalculateTarget()->GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(false); + } + + return true; } -bool -ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now) -{ - // Now figure out the range of this inlined block, and set up a "step through range" - // plan for that. If we've been provided with a context, then use the block in that - // context. - StackFrameSP immediate_return_from_sp (m_thread.GetStackFrameAtIndex (0)); - if (!immediate_return_from_sp) - return false; - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +bool ThreadPlanStepOut::MischiefManaged() { + if (IsPlanComplete()) { + // Did I reach my breakpoint? If so I'm done. + // + // I also check the stack depth, since if we've blown past the breakpoint + // for some + // reason and we're now stopping for some other reason altogether, then + // we're done + // with this step out operation. + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); if (log) - { - StreamString s; - immediate_return_from_sp->Dump(&s, true, false); - log->Printf("Queuing inlined frame to step past: %s.", s.GetData()); - } - - Block *from_block = immediate_return_from_sp->GetFrameBlock(); - if (from_block) - { - Block *inlined_block = from_block->GetContainingInlinedBlock(); - if (inlined_block) - { - size_t num_ranges = inlined_block->GetNumRanges(); - AddressRange inline_range; - if (inlined_block->GetRangeAtIndex(0, inline_range)) - { - SymbolContext inlined_sc; - inlined_block->CalculateSymbolContext(&inlined_sc); - inlined_sc.target_sp = GetTarget().shared_from_this(); - RunMode run_mode = m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; - const LazyBool avoid_no_debug = eLazyBoolNo; - - m_step_through_inline_plan_sp.reset (new ThreadPlanStepOverRange(m_thread, - inline_range, - inlined_sc, - run_mode, - avoid_no_debug)); - ThreadPlanStepOverRange *step_through_inline_plan_ptr - = static_cast<ThreadPlanStepOverRange *>(m_step_through_inline_plan_sp.get()); - m_step_through_inline_plan_sp->SetPrivate(true); - - step_through_inline_plan_ptr->SetOkayToDiscard(true); - StreamString errors; - if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) - { - //FIXME: Log this failure. - delete step_through_inline_plan_ptr; - return false; - } - - for (size_t i = 1; i < num_ranges; i++) - { - if (inlined_block->GetRangeAtIndex (i, inline_range)) - step_through_inline_plan_ptr->AddRange (inline_range); - } - - if (queue_now) - m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false); - return true; - } - } + log->Printf("Completed step out plan."); + if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { + m_thread.CalculateTarget()->RemoveBreakpointByID(m_return_bp_id); + m_return_bp_id = LLDB_INVALID_BREAK_ID; } - + + ThreadPlan::MischiefManaged(); + return true; + } else { return false; + } } -void -ThreadPlanStepOut::CalculateReturnValue () -{ - if (m_return_valobj_sp) - return; - - if (!m_calculate_return_value) - return; - - if (m_immediate_step_from_function != nullptr) - { - CompilerType return_compiler_type = m_immediate_step_from_function->GetCompilerType().GetFunctionReturnType(); - if (return_compiler_type) - { - lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); - if (abi_sp) - m_return_valobj_sp = abi_sp->GetReturnValueObject(m_thread, return_compiler_type); +bool ThreadPlanStepOut::QueueInlinedStepPlan(bool queue_now) { + // Now figure out the range of this inlined block, and set up a "step through + // range" + // plan for that. If we've been provided with a context, then use the block + // in that + // context. + StackFrameSP immediate_return_from_sp(m_thread.GetStackFrameAtIndex(0)); + if (!immediate_return_from_sp) + return false; + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + StreamString s; + immediate_return_from_sp->Dump(&s, true, false); + log->Printf("Queuing inlined frame to step past: %s.", s.GetData()); + } + + Block *from_block = immediate_return_from_sp->GetFrameBlock(); + if (from_block) { + Block *inlined_block = from_block->GetContainingInlinedBlock(); + if (inlined_block) { + size_t num_ranges = inlined_block->GetNumRanges(); + AddressRange inline_range; + if (inlined_block->GetRangeAtIndex(0, inline_range)) { + SymbolContext inlined_sc; + inlined_block->CalculateSymbolContext(&inlined_sc); + inlined_sc.target_sp = GetTarget().shared_from_this(); + RunMode run_mode = + m_stop_others ? lldb::eOnlyThisThread : lldb::eAllThreads; + const LazyBool avoid_no_debug = eLazyBoolNo; + + m_step_through_inline_plan_sp.reset(new ThreadPlanStepOverRange( + m_thread, inline_range, inlined_sc, run_mode, avoid_no_debug)); + ThreadPlanStepOverRange *step_through_inline_plan_ptr = + static_cast<ThreadPlanStepOverRange *>( + m_step_through_inline_plan_sp.get()); + m_step_through_inline_plan_sp->SetPrivate(true); + + step_through_inline_plan_ptr->SetOkayToDiscard(true); + StreamString errors; + if (!step_through_inline_plan_ptr->ValidatePlan(&errors)) { + // FIXME: Log this failure. + delete step_through_inline_plan_ptr; + return false; } + + for (size_t i = 1; i < num_ranges; i++) { + if (inlined_block->GetRangeAtIndex(i, inline_range)) + step_through_inline_plan_ptr->AddRange(inline_range); + } + + if (queue_now) + m_thread.QueueThreadPlan(m_step_through_inline_plan_sp, false); + return true; + } } + } + + return false; } -bool -ThreadPlanStepOut::IsPlanStale() -{ - // If we are still lower on the stack than the frame we are returning to, then - // there's something for us to do. Otherwise, we're stale. - - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - return !(frame_zero_id < m_step_out_to_id); +void ThreadPlanStepOut::CalculateReturnValue() { + if (m_return_valobj_sp) + return; + + if (!m_calculate_return_value) + return; + + if (m_immediate_step_from_function != nullptr) { + CompilerType return_compiler_type = + m_immediate_step_from_function->GetCompilerType() + .GetFunctionReturnType(); + if (return_compiler_type) { + lldb::ABISP abi_sp = m_thread.GetProcess()->GetABI(); + if (abi_sp) + m_return_valobj_sp = + abi_sp->GetReturnValueObject(m_thread, return_compiler_type); + } + } +} + +bool ThreadPlanStepOut::IsPlanStale() { + // If we are still lower on the stack than the frame we are returning to, then + // there's something for us to do. Otherwise, we're stale. + + StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + return !(frame_zero_id < m_step_out_to_id); } diff --git a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp index da0326bfa91..39641a06548 100644 --- a/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp +++ b/lldb/source/Target/ThreadPlanStepOverBreakpoint.cpp @@ -22,172 +22,152 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// ThreadPlanStepOverBreakpoint: Single steps over a breakpoint bp_site_sp at the pc. +// ThreadPlanStepOverBreakpoint: Single steps over a breakpoint bp_site_sp at +// the pc. //---------------------------------------------------------------------- -ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint (Thread &thread) : - ThreadPlan (ThreadPlan::eKindStepOverBreakpoint, "Step over breakpoint trap", - thread, - eVoteNo, - eVoteNoOpinion), // We need to report the run since this happens - // first in the thread plan stack when stepping - // over a breakpoint - m_breakpoint_addr (LLDB_INVALID_ADDRESS), - m_auto_continue(false), - m_reenabled_breakpoint_site (false) - -{ - m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC(); - m_breakpoint_site_id = m_thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress (m_breakpoint_addr); -} - -ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint () -{ -} - -void -ThreadPlanStepOverBreakpoint::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - s->Printf("Single stepping past breakpoint site %" PRIu64 " at 0x%" PRIx64, m_breakpoint_site_id, (uint64_t)m_breakpoint_addr); -} - -bool -ThreadPlanStepOverBreakpoint::ValidatePlan (Stream *error) -{ - return true; -} - -bool -ThreadPlanStepOverBreakpoint::DoPlanExplainsStop (Event *event_ptr) -{ - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if (stop_info_sp) - { - // It's a little surprising that we stop here for a breakpoint hit. However, when you single step ONTO a breakpoint - // we still want to call that a breakpoint hit, and trigger the actions, etc. Otherwise you would see the - // PC at the breakpoint without having triggered the actions, then you'd continue, the PC wouldn't change, - // and you'd see the breakpoint hit, which would be odd. - // So the lower levels fake "step onto breakpoint address" and return that as a breakpoint. So our trace - // step COULD appear as a breakpoint hit if the next instruction also contained a breakpoint. - StopReason reason = stop_info_sp->GetStopReason(); - - switch (reason) - { - case eStopReasonTrace: - case eStopReasonNone: - return true; - case eStopReasonBreakpoint: - // It's a little surprising that we stop here for a breakpoint hit. However, when you single step ONTO a - // breakpoint we still want to call that a breakpoint hit, and trigger the actions, etc. Otherwise you - // would see the PC at the breakpoint without having triggered the actions, then you'd continue, the PC - // wouldn't change, and you'd see the breakpoint hit, which would be odd. - // So the lower levels fake "step onto breakpoint address" and return that as a breakpoint hit. So our trace - // step COULD appear as a breakpoint hit if the next instruction also contained a breakpoint. We don't want - // to handle that, since we really don't know what to do with breakpoint hits. But make sure we don't set - // ourselves to auto-continue or we'll wrench control away from the plans that can deal with this. - SetAutoContinue(false); - return false; - default: - return false; - } +ThreadPlanStepOverBreakpoint::ThreadPlanStepOverBreakpoint(Thread &thread) + : ThreadPlan( + ThreadPlan::eKindStepOverBreakpoint, "Step over breakpoint trap", + thread, eVoteNo, + eVoteNoOpinion), // We need to report the run since this happens + // first in the thread plan stack when stepping + // over a breakpoint + m_breakpoint_addr(LLDB_INVALID_ADDRESS), + m_auto_continue(false), m_reenabled_breakpoint_site(false) + +{ + m_breakpoint_addr = m_thread.GetRegisterContext()->GetPC(); + m_breakpoint_site_id = + m_thread.GetProcess()->GetBreakpointSiteList().FindIDByAddress( + m_breakpoint_addr); +} + +ThreadPlanStepOverBreakpoint::~ThreadPlanStepOverBreakpoint() {} + +void ThreadPlanStepOverBreakpoint::GetDescription( + Stream *s, lldb::DescriptionLevel level) { + s->Printf("Single stepping past breakpoint site %" PRIu64 " at 0x%" PRIx64, + m_breakpoint_site_id, (uint64_t)m_breakpoint_addr); +} + +bool ThreadPlanStepOverBreakpoint::ValidatePlan(Stream *error) { return true; } + +bool ThreadPlanStepOverBreakpoint::DoPlanExplainsStop(Event *event_ptr) { + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (stop_info_sp) { + // It's a little surprising that we stop here for a breakpoint hit. + // However, when you single step ONTO a breakpoint + // we still want to call that a breakpoint hit, and trigger the actions, + // etc. Otherwise you would see the + // PC at the breakpoint without having triggered the actions, then you'd + // continue, the PC wouldn't change, + // and you'd see the breakpoint hit, which would be odd. + // So the lower levels fake "step onto breakpoint address" and return that + // as a breakpoint. So our trace + // step COULD appear as a breakpoint hit if the next instruction also + // contained a breakpoint. + StopReason reason = stop_info_sp->GetStopReason(); + + switch (reason) { + case eStopReasonTrace: + case eStopReasonNone: + return true; + case eStopReasonBreakpoint: + // It's a little surprising that we stop here for a breakpoint hit. + // However, when you single step ONTO a + // breakpoint we still want to call that a breakpoint hit, and trigger the + // actions, etc. Otherwise you + // would see the PC at the breakpoint without having triggered the + // actions, then you'd continue, the PC + // wouldn't change, and you'd see the breakpoint hit, which would be odd. + // So the lower levels fake "step onto breakpoint address" and return that + // as a breakpoint hit. So our trace + // step COULD appear as a breakpoint hit if the next instruction also + // contained a breakpoint. We don't want + // to handle that, since we really don't know what to do with breakpoint + // hits. But make sure we don't set + // ourselves to auto-continue or we'll wrench control away from the plans + // that can deal with this. + SetAutoContinue(false); + return false; + default: + return false; } - return false; + } + return false; } -bool -ThreadPlanStepOverBreakpoint::ShouldStop (Event *event_ptr) -{ - return !ShouldAutoContinue(event_ptr); +bool ThreadPlanStepOverBreakpoint::ShouldStop(Event *event_ptr) { + return !ShouldAutoContinue(event_ptr); } -bool -ThreadPlanStepOverBreakpoint::StopOthers () -{ - return true; -} +bool ThreadPlanStepOverBreakpoint::StopOthers() { return true; } -StateType -ThreadPlanStepOverBreakpoint::GetPlanRunState () -{ - return eStateStepping; +StateType ThreadPlanStepOverBreakpoint::GetPlanRunState() { + return eStateStepping; } -bool -ThreadPlanStepOverBreakpoint::DoWillResume (StateType resume_state, bool current_plan) -{ - if (current_plan) - { - BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress (m_breakpoint_addr)); - if (bp_site_sp && bp_site_sp->IsEnabled()) - m_thread.GetProcess()->DisableBreakpointSite (bp_site_sp.get()); - } - return true; +bool ThreadPlanStepOverBreakpoint::DoWillResume(StateType resume_state, + bool current_plan) { + if (current_plan) { + BreakpointSiteSP bp_site_sp( + m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress( + m_breakpoint_addr)); + if (bp_site_sp && bp_site_sp->IsEnabled()) + m_thread.GetProcess()->DisableBreakpointSite(bp_site_sp.get()); + } + return true; } -bool -ThreadPlanStepOverBreakpoint::WillStop () -{ - ReenableBreakpointSite (); - return true; +bool ThreadPlanStepOverBreakpoint::WillStop() { + ReenableBreakpointSite(); + return true; } -bool -ThreadPlanStepOverBreakpoint::MischiefManaged () -{ - lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(); +bool ThreadPlanStepOverBreakpoint::MischiefManaged() { + lldb::addr_t pc_addr = m_thread.GetRegisterContext()->GetPC(); - if (pc_addr == m_breakpoint_addr) - { - // If we are still at the PC of our breakpoint, then for some reason we didn't - // get a chance to run. - return false; - } - else - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Completed step over breakpoint plan."); - // Otherwise, re-enable the breakpoint we were stepping over, and we're done. - ReenableBreakpointSite (); - ThreadPlan::MischiefManaged (); - return true; - } + if (pc_addr == m_breakpoint_addr) { + // If we are still at the PC of our breakpoint, then for some reason we + // didn't + // get a chance to run. + return false; + } else { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Completed step over breakpoint plan."); + // Otherwise, re-enable the breakpoint we were stepping over, and we're + // done. + ReenableBreakpointSite(); + ThreadPlan::MischiefManaged(); + return true; + } } -void -ThreadPlanStepOverBreakpoint::ReenableBreakpointSite () -{ - if (!m_reenabled_breakpoint_site) - { - m_reenabled_breakpoint_site = true; - BreakpointSiteSP bp_site_sp (m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress (m_breakpoint_addr)); - if (bp_site_sp) - { - m_thread.GetProcess()->EnableBreakpointSite (bp_site_sp.get()); - } +void ThreadPlanStepOverBreakpoint::ReenableBreakpointSite() { + if (!m_reenabled_breakpoint_site) { + m_reenabled_breakpoint_site = true; + BreakpointSiteSP bp_site_sp( + m_thread.GetProcess()->GetBreakpointSiteList().FindByAddress( + m_breakpoint_addr)); + if (bp_site_sp) { + m_thread.GetProcess()->EnableBreakpointSite(bp_site_sp.get()); } + } } -void -ThreadPlanStepOverBreakpoint::ThreadDestroyed () -{ - ReenableBreakpointSite (); +void ThreadPlanStepOverBreakpoint::ThreadDestroyed() { + ReenableBreakpointSite(); } -void -ThreadPlanStepOverBreakpoint::SetAutoContinue (bool do_it) -{ - m_auto_continue = do_it; +void ThreadPlanStepOverBreakpoint::SetAutoContinue(bool do_it) { + m_auto_continue = do_it; } -bool -ThreadPlanStepOverBreakpoint::ShouldAutoContinue (Event *event_ptr) -{ - return m_auto_continue; +bool ThreadPlanStepOverBreakpoint::ShouldAutoContinue(Event *event_ptr) { + return m_auto_continue; } -bool -ThreadPlanStepOverBreakpoint::IsPlanStale() -{ - return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr; +bool ThreadPlanStepOverBreakpoint::IsPlanStale() { + return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr; } - diff --git a/lldb/source/Target/ThreadPlanStepOverRange.cpp b/lldb/source/Target/ThreadPlanStepOverRange.cpp index 0d02531efe8..2ded5953989 100644 --- a/lldb/source/Target/ThreadPlanStepOverRange.cpp +++ b/lldb/source/Target/ThreadPlanStepOverRange.cpp @@ -31,410 +31,404 @@ using namespace lldb; uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0; //---------------------------------------------------------------------- -// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into +// ThreadPlanStepOverRange: Step through a stack range, either stepping over or +// into // based on the value of \a type. //---------------------------------------------------------------------- -ThreadPlanStepOverRange::ThreadPlanStepOverRange -( - Thread &thread, - const AddressRange &range, - const SymbolContext &addr_context, - lldb::RunMode stop_others, - LazyBool step_out_avoids_code_without_debug_info -) : - ThreadPlanStepRange (ThreadPlan::eKindStepOverRange, "Step range stepping over", thread, range, addr_context, stop_others), - ThreadPlanShouldStopHere (this), - m_first_resume(true) -{ - SetFlagsToDefault(); - SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); +ThreadPlanStepOverRange::ThreadPlanStepOverRange( + Thread &thread, const AddressRange &range, + const SymbolContext &addr_context, lldb::RunMode stop_others, + LazyBool step_out_avoids_code_without_debug_info) + : ThreadPlanStepRange(ThreadPlan::eKindStepOverRange, + "Step range stepping over", thread, range, + addr_context, stop_others), + ThreadPlanShouldStopHere(this), m_first_resume(true) { + SetFlagsToDefault(); + SetupAvoidNoDebug(step_out_avoids_code_without_debug_info); } ThreadPlanStepOverRange::~ThreadPlanStepOverRange() = default; -void -ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - { - s->Printf("step over"); - return; - } - s->Printf ("Stepping over"); - bool printed_line_info = false; - if (m_addr_context.line_entry.IsValid()) - { - s->Printf (" line "); - m_addr_context.line_entry.DumpStopContext (s, false); - printed_line_info = true; - } +void ThreadPlanStepOverRange::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) { + s->Printf("step over"); + return; + } + s->Printf("Stepping over"); + bool printed_line_info = false; + if (m_addr_context.line_entry.IsValid()) { + s->Printf(" line "); + m_addr_context.line_entry.DumpStopContext(s, false); + printed_line_info = true; + } - if (!printed_line_info || level == eDescriptionLevelVerbose) - { - s->Printf (" using ranges: "); - DumpRanges(s); - } + if (!printed_line_info || level == eDescriptionLevelVerbose) { + s->Printf(" using ranges: "); + DumpRanges(s); + } - s->PutChar('.'); + s->PutChar('.'); } -void -ThreadPlanStepOverRange::SetupAvoidNoDebug(LazyBool step_out_avoids_code_without_debug_info) -{ - bool avoid_nodebug = true; - switch (step_out_avoids_code_without_debug_info) - { - case eLazyBoolYes: - avoid_nodebug = true; - break; - case eLazyBoolNo: - avoid_nodebug = false; - break; - case eLazyBoolCalculate: - avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); - break; - } - if (avoid_nodebug) - GetFlags().Set (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); - else - GetFlags().Clear (ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); - // Step Over plans should always avoid no-debug on step in. Seems like you shouldn't - // have to say this, but a tail call looks more like a step in that a step out, so - // we want to catch this case. - GetFlags().Set (ThreadPlanShouldStopHere::eStepInAvoidNoDebug); +void ThreadPlanStepOverRange::SetupAvoidNoDebug( + LazyBool step_out_avoids_code_without_debug_info) { + bool avoid_nodebug = true; + switch (step_out_avoids_code_without_debug_info) { + case eLazyBoolYes: + avoid_nodebug = true; + break; + case eLazyBoolNo: + avoid_nodebug = false; + break; + case eLazyBoolCalculate: + avoid_nodebug = m_thread.GetStepOutAvoidsNoDebug(); + break; + } + if (avoid_nodebug) + GetFlags().Set(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + else + GetFlags().Clear(ThreadPlanShouldStopHere::eStepOutAvoidNoDebug); + // Step Over plans should always avoid no-debug on step in. Seems like you + // shouldn't + // have to say this, but a tail call looks more like a step in that a step + // out, so + // we want to catch this case. + GetFlags().Set(ThreadPlanShouldStopHere::eStepInAvoidNoDebug); } -bool -ThreadPlanStepOverRange::IsEquivalentContext(const SymbolContext &context) -{ - // Match as much as is specified in the m_addr_context: - // This is a fairly loose sanity check. Note, sometimes the target doesn't get filled - // in so I left out the target check. And sometimes the module comes in as the .o file from the - // inlined range, so I left that out too... - if (m_addr_context.comp_unit) - { - if (m_addr_context.comp_unit == context.comp_unit) - { - if (m_addr_context.function && m_addr_context.function == context.function) - { - // It is okay to return to a different block of a straight function, we only have to - // be more careful if returning from one inlined block to another. - if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr - && context.block->GetInlinedFunctionInfo() == nullptr) - return true; - - if (m_addr_context.block && m_addr_context.block == context.block) - return true; - } - } - } - else if (m_addr_context.symbol && m_addr_context.symbol == context.symbol) - { - return true; +bool ThreadPlanStepOverRange::IsEquivalentContext( + const SymbolContext &context) { + // Match as much as is specified in the m_addr_context: + // This is a fairly loose sanity check. Note, sometimes the target doesn't + // get filled + // in so I left out the target check. And sometimes the module comes in as + // the .o file from the + // inlined range, so I left that out too... + if (m_addr_context.comp_unit) { + if (m_addr_context.comp_unit == context.comp_unit) { + if (m_addr_context.function && + m_addr_context.function == context.function) { + // It is okay to return to a different block of a straight function, we + // only have to + // be more careful if returning from one inlined block to another. + if (m_addr_context.block->GetInlinedFunctionInfo() == nullptr && + context.block->GetInlinedFunctionInfo() == nullptr) + return true; + + if (m_addr_context.block && m_addr_context.block == context.block) + return true; + } } - return false; + } else if (m_addr_context.symbol && m_addr_context.symbol == context.symbol) { + return true; + } + return false; } -bool -ThreadPlanStepOverRange::ShouldStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - - if (log) - { - StreamString s; - s.Address (m_thread.GetRegisterContext()->GetPC(), - m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); - log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData()); +bool ThreadPlanStepOverRange::ShouldStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + + if (log) { + StreamString s; + s.Address( + m_thread.GetRegisterContext()->GetPC(), + m_thread.CalculateTarget()->GetArchitecture().GetAddressByteSize()); + log->Printf("ThreadPlanStepOverRange reached %s.", s.GetData()); + } + + // If we're out of the range but in the same frame or in our caller's frame + // then we should stop. + // When stepping out we only stop others if we are forcing running one thread. + bool stop_others = (m_stop_others == lldb::eOnlyThisThread); + ThreadPlanSP new_plan_sp; + FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + + if (frame_order == eFrameCompareOlder) { + // If we're in an older frame then we should stop. + // + // A caveat to this is if we think the frame is older but we're actually in + // a trampoline. + // I'm going to make the assumption that you wouldn't RETURN to a + // trampoline. So if we are + // in a trampoline we think the frame is older because the trampoline + // confused the backtracer. + // As below, we step through first, and then try to figure out how to get + // back out again. + + new_plan_sp = + m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, stop_others); + + if (new_plan_sp && log) + log->Printf( + "Thought I stepped out, but in fact arrived at a trampoline."); + } else if (frame_order == eFrameCompareYounger) { + // Make sure we really are in a new frame. Do that by unwinding and seeing + // if the + // start function really is our start function... + for (uint32_t i = 1;; ++i) { + StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); + if (!older_frame_sp) { + // We can't unwind the next frame we should just get out of here & + // stop... + break; + } + + const SymbolContext &older_context = + older_frame_sp->GetSymbolContext(eSymbolContextEverything); + if (IsEquivalentContext(older_context)) { + new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop( + false, nullptr, true, stop_others, eVoteNo, eVoteNoOpinion, 0, + true); + break; + } else { + new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others); + // If we found a way through, then we should stop recursing. + if (new_plan_sp) + break; + } } - - // If we're out of the range but in the same frame or in our caller's frame - // then we should stop. - // When stepping out we only stop others if we are forcing running one thread. - bool stop_others = (m_stop_others == lldb::eOnlyThisThread); - ThreadPlanSP new_plan_sp; - FrameComparison frame_order = CompareCurrentFrameToStartFrame(); - - if (frame_order == eFrameCompareOlder) - { - // If we're in an older frame then we should stop. - // - // A caveat to this is if we think the frame is older but we're actually in a trampoline. - // I'm going to make the assumption that you wouldn't RETURN to a trampoline. So if we are - // in a trampoline we think the frame is older because the trampoline confused the backtracer. - // As below, we step through first, and then try to figure out how to get back out again. - - new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - - if (new_plan_sp && log) - log->Printf("Thought I stepped out, but in fact arrived at a trampoline."); + } else { + // If we're still in the range, keep going. + if (InRange()) { + SetNextBranchBreakpoint(); + return false; } - else if (frame_order == eFrameCompareYounger) - { - // Make sure we really are in a new frame. Do that by unwinding and seeing if the - // start function really is our start function... - for(uint32_t i = 1;; ++i) - { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(i); - if (!older_frame_sp) { - // We can't unwind the next frame we should just get out of here & stop... - break; - } - const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything); - if (IsEquivalentContext(older_context)) - { - new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop(false, - nullptr, - true, - stop_others, - eVoteNo, - eVoteNoOpinion, - 0, - true); - break; - } - else - { - new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - // If we found a way through, then we should stop recursing. - if (new_plan_sp) - break; - } - } - } - else - { - // If we're still in the range, keep going. - if (InRange()) - { - SetNextBranchBreakpoint(); - return false; - } + if (!InSymbol()) { + // This one is a little tricky. Sometimes we may be in a stub or + // something similar, + // in which case we need to get out of there. But if we are in a stub + // then it's + // likely going to be hard to get out from here. It is probably easiest + // to step into the + // stub, and then it will be straight-forward to step out. + new_plan_sp = m_thread.QueueThreadPlanForStepThrough(m_stack_id, false, + stop_others); + } else { + // The current clang (at least through 424) doesn't always get the address + // range for the + // DW_TAG_inlined_subroutines right, so that when you leave the inlined + // range the line table says + // you are still in the source file of the inlining function. This is + // bad, because now you are missing + // the stack frame for the function containing the inlining, and if you + // sensibly do "finish" to get + // out of this function you will instead exit the containing function. + // To work around this, we check whether we are still in the source file + // we started in, and if not assume + // it is an error, and push a plan to get us out of this line and back to + // the containing file. - if (!InSymbol()) - { - // This one is a little tricky. Sometimes we may be in a stub or something similar, - // in which case we need to get out of there. But if we are in a stub then it's - // likely going to be hard to get out from here. It is probably easiest to step into the - // stub, and then it will be straight-forward to step out. - new_plan_sp = m_thread.QueueThreadPlanForStepThrough (m_stack_id, false, stop_others); - } - else - { - // The current clang (at least through 424) doesn't always get the address range for the - // DW_TAG_inlined_subroutines right, so that when you leave the inlined range the line table says - // you are still in the source file of the inlining function. This is bad, because now you are missing - // the stack frame for the function containing the inlining, and if you sensibly do "finish" to get - // out of this function you will instead exit the containing function. - // To work around this, we check whether we are still in the source file we started in, and if not assume - // it is an error, and push a plan to get us out of this line and back to the containing file. - - if (m_addr_context.line_entry.IsValid()) - { - SymbolContext sc; - StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); - sc = frame_sp->GetSymbolContext (eSymbolContextEverything); - if (sc.line_entry.IsValid()) - { - if (sc.line_entry.original_file != m_addr_context.line_entry.original_file - && sc.comp_unit == m_addr_context.comp_unit - && sc.function == m_addr_context.function) - { - // Okay, find the next occurrence of this file in the line table: - LineTable *line_table = m_addr_context.comp_unit->GetLineTable(); - if (line_table) - { - Address cur_address = frame_sp->GetFrameCodeAddress(); - uint32_t entry_idx; - LineEntry line_entry; - if (line_table->FindLineEntryByAddress (cur_address, line_entry, &entry_idx)) - { - LineEntry next_line_entry; - bool step_past_remaining_inline = false; - if (entry_idx > 0) - { - // We require the previous line entry and the current line entry come - // from the same file. - // The other requirement is that the previous line table entry be part of an - // inlined block, we don't want to step past cases where people have inlined - // some code fragment by using #include <source-fragment.c> directly. - LineEntry prev_line_entry; - if (line_table->GetLineEntryAtIndex(entry_idx - 1, prev_line_entry) - && prev_line_entry.original_file == line_entry.original_file) - { - SymbolContext prev_sc; - Address prev_address = prev_line_entry.range.GetBaseAddress(); - prev_address.CalculateSymbolContext(&prev_sc); - if (prev_sc.block) - { - Block *inlined_block = prev_sc.block->GetContainingInlinedBlock(); - if (inlined_block) - { - AddressRange inline_range; - inlined_block->GetRangeContainingAddress(prev_address, inline_range); - if (!inline_range.ContainsFileAddress(cur_address)) - { - - step_past_remaining_inline = true; - } - } - } - } - } - - if (step_past_remaining_inline) - { - uint32_t look_ahead_step = 1; - while (line_table->GetLineEntryAtIndex(entry_idx + look_ahead_step, next_line_entry)) - { - // Make sure we haven't wandered out of the function we started from... - Address next_line_address = next_line_entry.range.GetBaseAddress(); - Function *next_line_function = next_line_address.CalculateSymbolContextFunction(); - if (next_line_function != m_addr_context.function) - break; - - if (next_line_entry.original_file == m_addr_context.line_entry.original_file) - { - const bool abort_other_plans = false; - const RunMode stop_other_threads = RunMode::eAllThreads; - lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0)->GetRegisterContext()->GetPC(); - AddressRange step_range(cur_pc, next_line_address.GetLoadAddress(&GetTarget()) - cur_pc); - - new_plan_sp = m_thread.QueueThreadPlanForStepOverRange (abort_other_plans, - step_range, - sc, - stop_other_threads); - break; - } - look_ahead_step++; - } - } - } + if (m_addr_context.line_entry.IsValid()) { + SymbolContext sc; + StackFrameSP frame_sp = m_thread.GetStackFrameAtIndex(0); + sc = frame_sp->GetSymbolContext(eSymbolContextEverything); + if (sc.line_entry.IsValid()) { + if (sc.line_entry.original_file != + m_addr_context.line_entry.original_file && + sc.comp_unit == m_addr_context.comp_unit && + sc.function == m_addr_context.function) { + // Okay, find the next occurrence of this file in the line table: + LineTable *line_table = m_addr_context.comp_unit->GetLineTable(); + if (line_table) { + Address cur_address = frame_sp->GetFrameCodeAddress(); + uint32_t entry_idx; + LineEntry line_entry; + if (line_table->FindLineEntryByAddress(cur_address, line_entry, + &entry_idx)) { + LineEntry next_line_entry; + bool step_past_remaining_inline = false; + if (entry_idx > 0) { + // We require the previous line entry and the current line + // entry come + // from the same file. + // The other requirement is that the previous line table entry + // be part of an + // inlined block, we don't want to step past cases where + // people have inlined + // some code fragment by using #include <source-fragment.c> + // directly. + LineEntry prev_line_entry; + if (line_table->GetLineEntryAtIndex(entry_idx - 1, + prev_line_entry) && + prev_line_entry.original_file == + line_entry.original_file) { + SymbolContext prev_sc; + Address prev_address = + prev_line_entry.range.GetBaseAddress(); + prev_address.CalculateSymbolContext(&prev_sc); + if (prev_sc.block) { + Block *inlined_block = + prev_sc.block->GetContainingInlinedBlock(); + if (inlined_block) { + AddressRange inline_range; + inlined_block->GetRangeContainingAddress(prev_address, + inline_range); + if (!inline_range.ContainsFileAddress(cur_address)) { + + step_past_remaining_inline = true; } + } } + } } + + if (step_past_remaining_inline) { + uint32_t look_ahead_step = 1; + while (line_table->GetLineEntryAtIndex( + entry_idx + look_ahead_step, next_line_entry)) { + // Make sure we haven't wandered out of the function we + // started from... + Address next_line_address = + next_line_entry.range.GetBaseAddress(); + Function *next_line_function = + next_line_address.CalculateSymbolContextFunction(); + if (next_line_function != m_addr_context.function) + break; + + if (next_line_entry.original_file == + m_addr_context.line_entry.original_file) { + const bool abort_other_plans = false; + const RunMode stop_other_threads = RunMode::eAllThreads; + lldb::addr_t cur_pc = m_thread.GetStackFrameAtIndex(0) + ->GetRegisterContext() + ->GetPC(); + AddressRange step_range( + cur_pc, + next_line_address.GetLoadAddress(&GetTarget()) - + cur_pc); + + new_plan_sp = m_thread.QueueThreadPlanForStepOverRange( + abort_other_plans, step_range, sc, + stop_other_threads); + break; + } + look_ahead_step++; + } + } + } } + } } + } } + } - // If we get to this point, we're not going to use a previously set "next branch" breakpoint, so delete it: - ClearNextBranchBreakpoint(); - - - // If we haven't figured out something to do yet, then ask the ShouldStopHere callback: - if (!new_plan_sp) - { - new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order); - } + // If we get to this point, we're not going to use a previously set "next + // branch" breakpoint, so delete it: + ClearNextBranchBreakpoint(); - if (!new_plan_sp) - m_no_more_plans = true; - else - { - // Any new plan will be an implementation plan, so mark it private: - new_plan_sp->SetPrivate(true); - m_no_more_plans = false; - } + // If we haven't figured out something to do yet, then ask the ShouldStopHere + // callback: + if (!new_plan_sp) { + new_plan_sp = CheckShouldStopHereAndQueueStepOut(frame_order); + } - if (!new_plan_sp) - { - // For efficiencies sake, we know we're done here so we don't have to do this - // calculation again in MischiefManaged. - SetPlanComplete(); - return true; - } - else - return false; + if (!new_plan_sp) + m_no_more_plans = true; + else { + // Any new plan will be an implementation plan, so mark it private: + new_plan_sp->SetPrivate(true); + m_no_more_plans = false; + } + + if (!new_plan_sp) { + // For efficiencies sake, we know we're done here so we don't have to do + // this + // calculation again in MischiefManaged. + SetPlanComplete(); + return true; + } else + return false; } -bool -ThreadPlanStepOverRange::DoPlanExplainsStop (Event *event_ptr) -{ - // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan above us) - // handle the stop. That way the user can see the stop, step around, and then when they - // are done, continue and have their step complete. The exception is if we've hit our - // "run to next branch" breakpoint. - // Note, unlike the step in range plan, we don't mark ourselves complete if we hit an - // unexplained breakpoint/crash. - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - bool return_value; - - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - - if (reason == eStopReasonTrace) - { - return_value = true; - } - else if (reason == eStopReasonBreakpoint) - { - return_value = NextRangeBreakpointExplainsStop(stop_info_sp); - } - else - { - if (log) - log->PutCString ("ThreadPlanStepInRange got asked if it explains the stop for some reason other than step."); - return_value = false; - } +bool ThreadPlanStepOverRange::DoPlanExplainsStop(Event *event_ptr) { + // For crashes, breakpoint hits, signals, etc, let the base plan (or some plan + // above us) + // handle the stop. That way the user can see the stop, step around, and then + // when they + // are done, continue and have their step complete. The exception is if we've + // hit our + // "run to next branch" breakpoint. + // Note, unlike the step in range plan, we don't mark ourselves complete if we + // hit an + // unexplained breakpoint/crash. + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + bool return_value; + + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + + if (reason == eStopReasonTrace) { + return_value = true; + } else if (reason == eStopReasonBreakpoint) { + return_value = NextRangeBreakpointExplainsStop(stop_info_sp); + } else { + if (log) + log->PutCString("ThreadPlanStepInRange got asked if it explains the " + "stop for some reason other than step."); + return_value = false; } - else - return_value = true; + } else + return_value = true; - return return_value; + return return_value; } -bool -ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool current_plan) -{ - if (resume_state != eStateSuspended && m_first_resume) - { - m_first_resume = false; - if (resume_state == eStateStepping && current_plan) - { - // See if we are about to step over an inlined call in the middle of the inlined stack, if so figure - // out its extents and reset our range to step over that. - bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); - if (in_inlined_stack) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("ThreadPlanStepInRange::DoWillResume: adjusting range to the frame at inlined depth %d.", - m_thread.GetCurrentInlinedDepth()); - StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); - if (stack_sp) - { - Block *frame_block = stack_sp->GetFrameBlock(); - lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); - AddressRange my_range; - if (frame_block->GetRangeContainingLoadAddress(curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) - { - m_address_ranges.clear(); - m_address_ranges.push_back(my_range); - if (log) - { - StreamString s; - const InlineFunctionInfo *inline_info = frame_block->GetInlinedFunctionInfo(); - const char *name; - if (inline_info) - name = inline_info->GetName(frame_block->CalculateSymbolContextFunction()->GetLanguage()).AsCString(); - else - name = "<unknown-notinlined>"; - - s.Printf ("Stepping over inlined function \"%s\" in inlined stack: ", name); - DumpRanges(&s); - log->PutCString(s.GetData()); - } - } - - } +bool ThreadPlanStepOverRange::DoWillResume(lldb::StateType resume_state, + bool current_plan) { + if (resume_state != eStateSuspended && m_first_resume) { + m_first_resume = false; + if (resume_state == eStateStepping && current_plan) { + // See if we are about to step over an inlined call in the middle of the + // inlined stack, if so figure + // out its extents and reset our range to step over that. + bool in_inlined_stack = m_thread.DecrementCurrentInlinedDepth(); + if (in_inlined_stack) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("ThreadPlanStepInRange::DoWillResume: adjusting range to " + "the frame at inlined depth %d.", + m_thread.GetCurrentInlinedDepth()); + StackFrameSP stack_sp = m_thread.GetStackFrameAtIndex(0); + if (stack_sp) { + Block *frame_block = stack_sp->GetFrameBlock(); + lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC(); + AddressRange my_range; + if (frame_block->GetRangeContainingLoadAddress( + curr_pc, m_thread.GetProcess()->GetTarget(), my_range)) { + m_address_ranges.clear(); + m_address_ranges.push_back(my_range); + if (log) { + StreamString s; + const InlineFunctionInfo *inline_info = + frame_block->GetInlinedFunctionInfo(); + const char *name; + if (inline_info) + name = + inline_info + ->GetName(frame_block->CalculateSymbolContextFunction() + ->GetLanguage()) + .AsCString(); + else + name = "<unknown-notinlined>"; + + s.Printf( + "Stepping over inlined function \"%s\" in inlined stack: ", + name); + DumpRanges(&s); + log->PutCString(s.GetData()); } + } } + } } - - return true; + } + + return true; } diff --git a/lldb/source/Target/ThreadPlanStepRange.cpp b/lldb/source/Target/ThreadPlanStepRange.cpp index 32e225c4af7..dcee82ea32a 100644 --- a/lldb/source/Target/ThreadPlanStepRange.cpp +++ b/lldb/source/Target/ThreadPlanStepRange.cpp @@ -35,504 +35,434 @@ using namespace lldb_private; // based on the value of \a type. //---------------------------------------------------------------------- -ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind, - const char *name, - Thread &thread, - const AddressRange &range, - const SymbolContext &addr_context, - lldb::RunMode stop_others, - bool given_ranges_only) : - ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), - m_addr_context (addr_context), - m_address_ranges (), - m_stop_others (stop_others), - m_stack_id (), - m_parent_stack_id(), - m_no_more_plans (false), - m_first_run_event (true), - m_use_fast_step(false), - m_given_ranges_only (given_ranges_only) -{ - m_use_fast_step = GetTarget().GetUseFastStepping(); - AddRange(range); - m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1); - if (parent_stack) - m_parent_stack_id = parent_stack->GetStackID(); +ThreadPlanStepRange::ThreadPlanStepRange(ThreadPlanKind kind, const char *name, + Thread &thread, + const AddressRange &range, + const SymbolContext &addr_context, + lldb::RunMode stop_others, + bool given_ranges_only) + : ThreadPlan(kind, name, thread, eVoteNoOpinion, eVoteNoOpinion), + m_addr_context(addr_context), m_address_ranges(), + m_stop_others(stop_others), m_stack_id(), m_parent_stack_id(), + m_no_more_plans(false), m_first_run_event(true), m_use_fast_step(false), + m_given_ranges_only(given_ranges_only) { + m_use_fast_step = GetTarget().GetUseFastStepping(); + AddRange(range); + m_stack_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + StackFrameSP parent_stack = m_thread.GetStackFrameAtIndex(1); + if (parent_stack) + m_parent_stack_id = parent_stack->GetStackID(); } -ThreadPlanStepRange::~ThreadPlanStepRange () -{ - ClearNextBranchBreakpoint(); -} +ThreadPlanStepRange::~ThreadPlanStepRange() { ClearNextBranchBreakpoint(); } -void -ThreadPlanStepRange::DidPush () -{ - // See if we can find a "next range" breakpoint: - SetNextBranchBreakpoint(); +void ThreadPlanStepRange::DidPush() { + // See if we can find a "next range" breakpoint: + SetNextBranchBreakpoint(); } -bool -ThreadPlanStepRange::ValidatePlan (Stream *error) -{ - return true; -} +bool ThreadPlanStepRange::ValidatePlan(Stream *error) { return true; } -Vote -ThreadPlanStepRange::ShouldReportStop (Event *event_ptr) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +Vote ThreadPlanStepRange::ShouldReportStop(Event *event_ptr) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; - if (log) - log->Printf ("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", vote); - return vote; + const Vote vote = IsPlanComplete() ? eVoteYes : eVoteNo; + if (log) + log->Printf("ThreadPlanStepRange::ShouldReportStop() returning vote %i\n", + vote); + return vote; } -void -ThreadPlanStepRange::AddRange(const AddressRange &new_range) -{ - // For now I'm just adding the ranges. At some point we may want to - // condense the ranges if they overlap, though I don't think it is likely - // to be very important. - m_address_ranges.push_back (new_range); - - // Fill the slot for this address range with an empty DisassemblerSP in the instruction ranges. I want the - // indices to match, but I don't want to do the work to disassemble this range if I don't step into it. - m_instruction_ranges.push_back (DisassemblerSP()); +void ThreadPlanStepRange::AddRange(const AddressRange &new_range) { + // For now I'm just adding the ranges. At some point we may want to + // condense the ranges if they overlap, though I don't think it is likely + // to be very important. + m_address_ranges.push_back(new_range); + + // Fill the slot for this address range with an empty DisassemblerSP in the + // instruction ranges. I want the + // indices to match, but I don't want to do the work to disassemble this range + // if I don't step into it. + m_instruction_ranges.push_back(DisassemblerSP()); } -void -ThreadPlanStepRange::DumpRanges(Stream *s) -{ - size_t num_ranges = m_address_ranges.size(); - if (num_ranges == 1) - { - m_address_ranges[0].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress); - } - else - { - for (size_t i = 0; i < num_ranges; i++) - { - s->Printf(" %" PRIu64 ": ", uint64_t(i)); - m_address_ranges[i].Dump (s, m_thread.CalculateTarget().get(), Address::DumpStyleLoadAddress); - } +void ThreadPlanStepRange::DumpRanges(Stream *s) { + size_t num_ranges = m_address_ranges.size(); + if (num_ranges == 1) { + m_address_ranges[0].Dump(s, m_thread.CalculateTarget().get(), + Address::DumpStyleLoadAddress); + } else { + for (size_t i = 0; i < num_ranges; i++) { + s->Printf(" %" PRIu64 ": ", uint64_t(i)); + m_address_ranges[i].Dump(s, m_thread.CalculateTarget().get(), + Address::DumpStyleLoadAddress); } + } } -bool -ThreadPlanStepRange::InRange () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - bool ret_value = false; - - lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); - - size_t num_ranges = m_address_ranges.size(); - for (size_t i = 0; i < num_ranges; i++) - { - ret_value = m_address_ranges[i].ContainsLoadAddress(pc_load_addr, m_thread.CalculateTarget().get()); - if (ret_value) - break; - } - - if (!ret_value && !m_given_ranges_only) - { - // See if we've just stepped to another part of the same line number... - StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); - - SymbolContext new_context(frame->GetSymbolContext(eSymbolContextEverything)); - if (m_addr_context.line_entry.IsValid() && new_context.line_entry.IsValid()) - { - if (m_addr_context.line_entry.original_file == new_context.line_entry.original_file) - { - if (m_addr_context.line_entry.line == new_context.line_entry.line) - { - m_addr_context = new_context; - AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange()); - ret_value = true; - if (log) - { - StreamString s; - m_addr_context.line_entry.Dump (&s, - m_thread.CalculateTarget().get(), - true, - Address::DumpStyleLoadAddress, - Address::DumpStyleLoadAddress, - true); - - log->Printf ("Step range plan stepped to another range of same line: %s", s.GetData()); - } - } - else if (new_context.line_entry.line == 0) - { - new_context.line_entry.line = m_addr_context.line_entry.line; - m_addr_context = new_context; - AddRange(m_addr_context.line_entry.GetSameLineContiguousAddressRange()); - ret_value = true; - if (log) - { - StreamString s; - m_addr_context.line_entry.Dump (&s, - m_thread.CalculateTarget().get(), - true, - Address::DumpStyleLoadAddress, - Address::DumpStyleLoadAddress, - true); - - log->Printf ("Step range plan stepped to a range at linenumber 0 stepping through that range: %s", s.GetData()); - } - } - else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress(m_thread.CalculateTarget().get()) - != pc_load_addr) - { - // Another thing that sometimes happens here is that we step out of one line into the MIDDLE of another - // line. So far I mostly see this due to bugs in the debug information. - // But we probably don't want to be in the middle of a line range, so in that case reset the stepping - // range to the line we've stepped into the middle of and continue. - m_addr_context = new_context; - m_address_ranges.clear(); - AddRange(m_addr_context.line_entry.range); - ret_value = true; - if (log) - { - StreamString s; - m_addr_context.line_entry.Dump (&s, - m_thread.CalculateTarget().get(), - true, - Address::DumpStyleLoadAddress, - Address::DumpStyleLoadAddress, - true); - - log->Printf ("Step range plan stepped to the middle of new line(%d): %s, continuing to clear this line.", - new_context.line_entry.line, - s.GetData()); - } - } - } +bool ThreadPlanStepRange::InRange() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + bool ret_value = false; + + lldb::addr_t pc_load_addr = m_thread.GetRegisterContext()->GetPC(); + + size_t num_ranges = m_address_ranges.size(); + for (size_t i = 0; i < num_ranges; i++) { + ret_value = m_address_ranges[i].ContainsLoadAddress( + pc_load_addr, m_thread.CalculateTarget().get()); + if (ret_value) + break; + } + + if (!ret_value && !m_given_ranges_only) { + // See if we've just stepped to another part of the same line number... + StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get(); + + SymbolContext new_context( + frame->GetSymbolContext(eSymbolContextEverything)); + if (m_addr_context.line_entry.IsValid() && + new_context.line_entry.IsValid()) { + if (m_addr_context.line_entry.original_file == + new_context.line_entry.original_file) { + if (m_addr_context.line_entry.line == new_context.line_entry.line) { + m_addr_context = new_context; + AddRange( + m_addr_context.line_entry.GetSameLineContiguousAddressRange()); + ret_value = true; + if (log) { + StreamString s; + m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), + true, Address::DumpStyleLoadAddress, + Address::DumpStyleLoadAddress, true); + + log->Printf( + "Step range plan stepped to another range of same line: %s", + s.GetData()); + } + } else if (new_context.line_entry.line == 0) { + new_context.line_entry.line = m_addr_context.line_entry.line; + m_addr_context = new_context; + AddRange( + m_addr_context.line_entry.GetSameLineContiguousAddressRange()); + ret_value = true; + if (log) { + StreamString s; + m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), + true, Address::DumpStyleLoadAddress, + Address::DumpStyleLoadAddress, true); + + log->Printf("Step range plan stepped to a range at linenumber 0 " + "stepping through that range: %s", + s.GetData()); + } + } else if (new_context.line_entry.range.GetBaseAddress().GetLoadAddress( + m_thread.CalculateTarget().get()) != pc_load_addr) { + // Another thing that sometimes happens here is that we step out of + // one line into the MIDDLE of another + // line. So far I mostly see this due to bugs in the debug + // information. + // But we probably don't want to be in the middle of a line range, so + // in that case reset the stepping + // range to the line we've stepped into the middle of and continue. + m_addr_context = new_context; + m_address_ranges.clear(); + AddRange(m_addr_context.line_entry.range); + ret_value = true; + if (log) { + StreamString s; + m_addr_context.line_entry.Dump(&s, m_thread.CalculateTarget().get(), + true, Address::DumpStyleLoadAddress, + Address::DumpStyleLoadAddress, true); + + log->Printf("Step range plan stepped to the middle of new " + "line(%d): %s, continuing to clear this line.", + new_context.line_entry.line, s.GetData()); + } } + } } + } - if (!ret_value && log) - log->Printf ("Step range plan out of range to 0x%" PRIx64, pc_load_addr); + if (!ret_value && log) + log->Printf("Step range plan out of range to 0x%" PRIx64, pc_load_addr); - return ret_value; + return ret_value; } -bool -ThreadPlanStepRange::InSymbol() -{ - lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); - if (m_addr_context.function != nullptr) - { - return m_addr_context.function->GetAddressRange().ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get()); - } - else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) - { - AddressRange range(m_addr_context.symbol->GetAddressRef(), m_addr_context.symbol->GetByteSize()); - return range.ContainsLoadAddress (cur_pc, m_thread.CalculateTarget().get()); - } - return false; +bool ThreadPlanStepRange::InSymbol() { + lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC(); + if (m_addr_context.function != nullptr) { + return m_addr_context.function->GetAddressRange().ContainsLoadAddress( + cur_pc, m_thread.CalculateTarget().get()); + } else if (m_addr_context.symbol && m_addr_context.symbol->ValueIsAddress()) { + AddressRange range(m_addr_context.symbol->GetAddressRef(), + m_addr_context.symbol->GetByteSize()); + return range.ContainsLoadAddress(cur_pc, m_thread.CalculateTarget().get()); + } + return false; } -// FIXME: This should also handle inlining if we aren't going to do inlining in the +// FIXME: This should also handle inlining if we aren't going to do inlining in +// the // main stack. // // Ideally we should remember the whole stack frame list, and then compare that // to the current list. -lldb::FrameComparison -ThreadPlanStepRange::CompareCurrentFrameToStartFrame() -{ - FrameComparison frame_order; - - StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - - if (cur_frame_id == m_stack_id) - { - frame_order = eFrameCompareEqual; - } - else if (cur_frame_id < m_stack_id) - { - frame_order = eFrameCompareYounger; - } +lldb::FrameComparison ThreadPlanStepRange::CompareCurrentFrameToStartFrame() { + FrameComparison frame_order; + + StackID cur_frame_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); + + if (cur_frame_id == m_stack_id) { + frame_order = eFrameCompareEqual; + } else if (cur_frame_id < m_stack_id) { + frame_order = eFrameCompareYounger; + } else { + StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1); + StackID cur_parent_id; + if (cur_parent_frame) + cur_parent_id = cur_parent_frame->GetStackID(); + if (m_parent_stack_id.IsValid() && cur_parent_id.IsValid() && + m_parent_stack_id == cur_parent_id) + frame_order = eFrameCompareSameParent; else - { - StackFrameSP cur_parent_frame = m_thread.GetStackFrameAtIndex(1); - StackID cur_parent_id; - if (cur_parent_frame) - cur_parent_id = cur_parent_frame->GetStackID(); - if (m_parent_stack_id.IsValid() - && cur_parent_id.IsValid() - && m_parent_stack_id == cur_parent_id) - frame_order = eFrameCompareSameParent; - else - frame_order = eFrameCompareOlder; - } - return frame_order; + frame_order = eFrameCompareOlder; + } + return frame_order; } -bool -ThreadPlanStepRange::StopOthers () -{ - return (m_stop_others == lldb::eOnlyThisThread || m_stop_others == lldb::eOnlyDuringStepping); +bool ThreadPlanStepRange::StopOthers() { + return (m_stop_others == lldb::eOnlyThisThread || + m_stop_others == lldb::eOnlyDuringStepping); } -InstructionList * -ThreadPlanStepRange::GetInstructionsForAddress(lldb::addr_t addr, size_t &range_index, size_t &insn_offset) -{ - size_t num_ranges = m_address_ranges.size(); - for (size_t i = 0; i < num_ranges; i++) - { - if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) - { - // Some joker added a zero size range to the stepping range... - if (m_address_ranges[i].GetByteSize() == 0) - return nullptr; - - if (!m_instruction_ranges[i]) - { - //Disassemble the address range given: - ExecutionContext exe_ctx (m_thread.GetProcess()); - const char *plugin_name = nullptr; - const char *flavor = nullptr; - const bool prefer_file_cache = true; - m_instruction_ranges[i] = Disassembler::DisassembleRange(GetTarget().GetArchitecture(), - plugin_name, - flavor, - exe_ctx, - m_address_ranges[i], - prefer_file_cache); - } - if (!m_instruction_ranges[i]) - return nullptr; - else - { - // Find where we are in the instruction list as well. If we aren't at an instruction, - // return nullptr. In this case, we're probably lost, and shouldn't try to do anything fancy. - - insn_offset = m_instruction_ranges[i]->GetInstructionList().GetIndexOfInstructionAtLoadAddress(addr, GetTarget()); - if (insn_offset == UINT32_MAX) - return nullptr; - else - { - range_index = i; - return &m_instruction_ranges[i]->GetInstructionList(); - } - } +InstructionList *ThreadPlanStepRange::GetInstructionsForAddress( + lldb::addr_t addr, size_t &range_index, size_t &insn_offset) { + size_t num_ranges = m_address_ranges.size(); + for (size_t i = 0; i < num_ranges; i++) { + if (m_address_ranges[i].ContainsLoadAddress(addr, &GetTarget())) { + // Some joker added a zero size range to the stepping range... + if (m_address_ranges[i].GetByteSize() == 0) + return nullptr; + + if (!m_instruction_ranges[i]) { + // Disassemble the address range given: + ExecutionContext exe_ctx(m_thread.GetProcess()); + const char *plugin_name = nullptr; + const char *flavor = nullptr; + const bool prefer_file_cache = true; + m_instruction_ranges[i] = Disassembler::DisassembleRange( + GetTarget().GetArchitecture(), plugin_name, flavor, exe_ctx, + m_address_ranges[i], prefer_file_cache); + } + if (!m_instruction_ranges[i]) + return nullptr; + else { + // Find where we are in the instruction list as well. If we aren't at + // an instruction, + // return nullptr. In this case, we're probably lost, and shouldn't try + // to do anything fancy. + + insn_offset = + m_instruction_ranges[i] + ->GetInstructionList() + .GetIndexOfInstructionAtLoadAddress(addr, GetTarget()); + if (insn_offset == UINT32_MAX) + return nullptr; + else { + range_index = i; + return &m_instruction_ranges[i]->GetInstructionList(); } + } } - return nullptr; + } + return nullptr; } -void -ThreadPlanStepRange::ClearNextBranchBreakpoint() -{ - if (m_next_branch_bp_sp) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf ("Removing next branch breakpoint: %d.", m_next_branch_bp_sp->GetID()); - GetTarget().RemoveBreakpointByID (m_next_branch_bp_sp->GetID()); - m_next_branch_bp_sp.reset(); - } +void ThreadPlanStepRange::ClearNextBranchBreakpoint() { + if (m_next_branch_bp_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Removing next branch breakpoint: %d.", + m_next_branch_bp_sp->GetID()); + GetTarget().RemoveBreakpointByID(m_next_branch_bp_sp->GetID()); + m_next_branch_bp_sp.reset(); + } } -bool -ThreadPlanStepRange::SetNextBranchBreakpoint () -{ - if (m_next_branch_bp_sp) - return true; +bool ThreadPlanStepRange::SetNextBranchBreakpoint() { + if (m_next_branch_bp_sp) + return true; - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - // Stepping through ranges using breakpoints doesn't work yet, but with this off we fall back to instruction - // single stepping. - if (!m_use_fast_step) - return false; - - lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC(); - // Find the current address in our address ranges, and fetch the disassembly if we haven't already: - size_t pc_index; - size_t range_index; - InstructionList *instructions = GetInstructionsForAddress (cur_addr, range_index, pc_index); - if (instructions == nullptr) - return false; - else - { - Target &target = GetThread().GetProcess()->GetTarget(); - uint32_t branch_index; - branch_index = instructions->GetIndexOfNextBranchInstruction (pc_index, target); - - Address run_to_address; - - // If we didn't find a branch, run to the end of the range. - if (branch_index == UINT32_MAX) - { - uint32_t last_index = instructions->GetSize() - 1; - if (last_index - pc_index > 1) - { - InstructionSP last_inst = instructions->GetInstructionAtIndex(last_index); - size_t last_inst_size = last_inst->GetOpcode().GetByteSize(); - run_to_address = last_inst->GetAddress(); - run_to_address.Slide(last_inst_size); - } - } - else if (branch_index - pc_index > 1) - { - run_to_address = instructions->GetInstructionAtIndex(branch_index)->GetAddress(); - } - - if (run_to_address.IsValid()) - { - const bool is_internal = true; - m_next_branch_bp_sp = GetTarget().CreateBreakpoint(run_to_address, is_internal, false); - if (m_next_branch_bp_sp) - { - if (log) - { - lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID; - BreakpointLocationSP bp_loc = m_next_branch_bp_sp->GetLocationAtIndex(0); - if (bp_loc) - { - BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite(); - if (bp_site) - { - bp_site_id = bp_site->GetID(); - } - } - log->Printf ("ThreadPlanStepRange::SetNextBranchBreakpoint - Setting breakpoint %d (site %d) to run to address 0x%" PRIx64, - m_next_branch_bp_sp->GetID(), - bp_site_id, - run_to_address.GetLoadAddress(&m_thread.GetProcess()->GetTarget())); - } - m_next_branch_bp_sp->SetThreadID(m_thread.GetID()); - m_next_branch_bp_sp->SetBreakpointKind ("next-branch-location"); - return true; - } - else - return false; - } - } + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + // Stepping through ranges using breakpoints doesn't work yet, but with this + // off we fall back to instruction + // single stepping. + if (!m_use_fast_step) return false; -} -bool -ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info_sp) -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (!m_next_branch_bp_sp) - return false; - - break_id_t bp_site_id = stop_info_sp->GetValue(); - BreakpointSiteSP bp_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id); - if (!bp_site_sp) - return false; - else if (!bp_site_sp->IsBreakpointAtThisSite (m_next_branch_bp_sp->GetID())) - return false; - else - { - // If we've hit the next branch breakpoint, then clear it. - size_t num_owners = bp_site_sp->GetNumberOfOwners(); - bool explains_stop = true; - // If all the owners are internal, then we are probably just stepping over this range from multiple threads, - // or multiple frames, so we want to continue. If one is not internal, then we should not explain the stop, - // and let the user breakpoint handle the stop. - for (size_t i = 0; i < num_owners; i++) - { - if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) - { - explains_stop = false; - break; + lldb::addr_t cur_addr = GetThread().GetRegisterContext()->GetPC(); + // Find the current address in our address ranges, and fetch the disassembly + // if we haven't already: + size_t pc_index; + size_t range_index; + InstructionList *instructions = + GetInstructionsForAddress(cur_addr, range_index, pc_index); + if (instructions == nullptr) + return false; + else { + Target &target = GetThread().GetProcess()->GetTarget(); + uint32_t branch_index; + branch_index = + instructions->GetIndexOfNextBranchInstruction(pc_index, target); + + Address run_to_address; + + // If we didn't find a branch, run to the end of the range. + if (branch_index == UINT32_MAX) { + uint32_t last_index = instructions->GetSize() - 1; + if (last_index - pc_index > 1) { + InstructionSP last_inst = + instructions->GetInstructionAtIndex(last_index); + size_t last_inst_size = last_inst->GetOpcode().GetByteSize(); + run_to_address = last_inst->GetAddress(); + run_to_address.Slide(last_inst_size); + } + } else if (branch_index - pc_index > 1) { + run_to_address = + instructions->GetInstructionAtIndex(branch_index)->GetAddress(); + } + + if (run_to_address.IsValid()) { + const bool is_internal = true; + m_next_branch_bp_sp = + GetTarget().CreateBreakpoint(run_to_address, is_internal, false); + if (m_next_branch_bp_sp) { + if (log) { + lldb::break_id_t bp_site_id = LLDB_INVALID_BREAK_ID; + BreakpointLocationSP bp_loc = + m_next_branch_bp_sp->GetLocationAtIndex(0); + if (bp_loc) { + BreakpointSiteSP bp_site = bp_loc->GetBreakpointSite(); + if (bp_site) { + bp_site_id = bp_site->GetID(); } + } + log->Printf("ThreadPlanStepRange::SetNextBranchBreakpoint - Setting " + "breakpoint %d (site %d) to run to address 0x%" PRIx64, + m_next_branch_bp_sp->GetID(), bp_site_id, + run_to_address.GetLoadAddress( + &m_thread.GetProcess()->GetTarget())); } - if (log) - log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %" PRIu64 " owners - explains stop: %u.", - (uint64_t)num_owners, - explains_stop); - ClearNextBranchBreakpoint(); - return explains_stop; + m_next_branch_bp_sp->SetThreadID(m_thread.GetID()); + m_next_branch_bp_sp->SetBreakpointKind("next-branch-location"); + return true; + } else + return false; } + } + return false; } -bool -ThreadPlanStepRange::WillStop () -{ - return true; +bool ThreadPlanStepRange::NextRangeBreakpointExplainsStop( + lldb::StopInfoSP stop_info_sp) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (!m_next_branch_bp_sp) + return false; + + break_id_t bp_site_id = stop_info_sp->GetValue(); + BreakpointSiteSP bp_site_sp = + m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id); + if (!bp_site_sp) + return false; + else if (!bp_site_sp->IsBreakpointAtThisSite(m_next_branch_bp_sp->GetID())) + return false; + else { + // If we've hit the next branch breakpoint, then clear it. + size_t num_owners = bp_site_sp->GetNumberOfOwners(); + bool explains_stop = true; + // If all the owners are internal, then we are probably just stepping over + // this range from multiple threads, + // or multiple frames, so we want to continue. If one is not internal, then + // we should not explain the stop, + // and let the user breakpoint handle the stop. + for (size_t i = 0; i < num_owners; i++) { + if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) { + explains_stop = false; + break; + } + } + if (log) + log->Printf("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit " + "next range breakpoint which has %" PRIu64 + " owners - explains stop: %u.", + (uint64_t)num_owners, explains_stop); + ClearNextBranchBreakpoint(); + return explains_stop; + } } -StateType -ThreadPlanStepRange::GetPlanRunState () -{ - if (m_next_branch_bp_sp) - return eStateRunning; - else - return eStateStepping; +bool ThreadPlanStepRange::WillStop() { return true; } + +StateType ThreadPlanStepRange::GetPlanRunState() { + if (m_next_branch_bp_sp) + return eStateRunning; + else + return eStateStepping; } -bool -ThreadPlanStepRange::MischiefManaged () -{ - // If we have pushed some plans between ShouldStop & MischiefManaged, then we're not done... - // I do this check first because we might have stepped somewhere that will fool InRange into - // thinking it needs to step past the end of that line. This happens, for instance, when stepping - // over inlined code that is in the middle of the current line. - - if (!m_no_more_plans) - return false; - - bool done = true; - if (!IsPlanComplete()) - { - if (InRange()) - { - done = false; - } - else - { - FrameComparison frame_order = CompareCurrentFrameToStartFrame(); - done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true; - } - } +bool ThreadPlanStepRange::MischiefManaged() { + // If we have pushed some plans between ShouldStop & MischiefManaged, then + // we're not done... + // I do this check first because we might have stepped somewhere that will + // fool InRange into + // thinking it needs to step past the end of that line. This happens, for + // instance, when stepping + // over inlined code that is in the middle of the current line. - if (done) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Completed step through range plan."); - ClearNextBranchBreakpoint(); - ThreadPlan::MischiefManaged (); - return true; - } - else - { - return false; + if (!m_no_more_plans) + return false; + + bool done = true; + if (!IsPlanComplete()) { + if (InRange()) { + done = false; + } else { + FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + done = (frame_order != eFrameCompareOlder) ? m_no_more_plans : true; } + } + + if (done) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Completed step through range plan."); + ClearNextBranchBreakpoint(); + ThreadPlan::MischiefManaged(); + return true; + } else { + return false; + } } -bool -ThreadPlanStepRange::IsPlanStale () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - FrameComparison frame_order = CompareCurrentFrameToStartFrame(); - - if (frame_order == eFrameCompareOlder) - { - if (log) - { - log->Printf("ThreadPlanStepRange::IsPlanStale returning true, we've stepped out."); - } - return true; +bool ThreadPlanStepRange::IsPlanStale() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + FrameComparison frame_order = CompareCurrentFrameToStartFrame(); + + if (frame_order == eFrameCompareOlder) { + if (log) { + log->Printf("ThreadPlanStepRange::IsPlanStale returning true, we've " + "stepped out."); } - else if (frame_order == eFrameCompareEqual && InSymbol()) - { - // If we are not in a place we should step through, we've gotten stale. - // One tricky bit here is that some stubs don't push a frame, so we should. - // check that we are in the same symbol. - if (!InRange()) - { - return true; - } + return true; + } else if (frame_order == eFrameCompareEqual && InSymbol()) { + // If we are not in a place we should step through, we've gotten stale. + // One tricky bit here is that some stubs don't push a frame, so we should. + // check that we are in the same symbol. + if (!InRange()) { + return true; } - return false; + } + return false; } diff --git a/lldb/source/Target/ThreadPlanStepThrough.cpp b/lldb/source/Target/ThreadPlanStepThrough.cpp index c345b6a7d4a..b9751614a52 100644 --- a/lldb/source/Target/ThreadPlanStepThrough.cpp +++ b/lldb/source/Target/ThreadPlanStepThrough.cpp @@ -12,6 +12,7 @@ // Other libraries and framework includes // Project includes #include "lldb/Target/ThreadPlanStepThrough.h" +#include "lldb/Breakpoint/Breakpoint.h" #include "lldb/Core/Log.h" #include "lldb/Core/Stream.h" #include "lldb/Target/DynamicLoader.h" @@ -19,268 +20,235 @@ #include "lldb/Target/Process.h" #include "lldb/Target/RegisterContext.h" #include "lldb/Target/Target.h" -#include "lldb/Breakpoint/Breakpoint.h" using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// ThreadPlanStepThrough: If the current instruction is a trampoline, step through it -// If it is the beginning of the prologue of a function, step through that as well. +// ThreadPlanStepThrough: If the current instruction is a trampoline, step +// through it +// If it is the beginning of the prologue of a function, step through that as +// well. // FIXME: At present only handles DYLD trampolines. //---------------------------------------------------------------------- -ThreadPlanStepThrough::ThreadPlanStepThrough (Thread &thread, StackID &m_stack_id, bool stop_others) : - ThreadPlan (ThreadPlan::eKindStepThrough, "Step through trampolines and prologues", thread, eVoteNoOpinion, eVoteNoOpinion), - m_start_address (0), - m_backstop_bkpt_id (LLDB_INVALID_BREAK_ID), - m_backstop_addr(LLDB_INVALID_ADDRESS), - m_return_stack_id (m_stack_id), - m_stop_others (stop_others) -{ - LookForPlanToStepThroughFromCurrentPC(); - - // If we don't get a valid step through plan, don't bother to set up a backstop. - if (m_sub_plan_sp) - { - m_start_address = GetThread().GetRegisterContext()->GetPC(0); - - // We are going to return back to the concrete frame 1, we might pass by some inlined code that we're in - // the middle of by doing this, but it's easier than trying to figure out where the inlined code might return to. - - StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID (m_stack_id); - - if (return_frame_sp) - { - m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress(m_thread.CalculateTarget().get()); - Breakpoint *return_bp = m_thread.GetProcess()->GetTarget().CreateBreakpoint (m_backstop_addr, true, false).get(); - if (return_bp != nullptr) - { - return_bp->SetThreadID(m_thread.GetID()); - m_backstop_bkpt_id = return_bp->GetID(); - return_bp->SetBreakpointKind("step-through-backstop"); - } - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - { - log->Printf ("Setting backstop breakpoint %d at address: 0x%" PRIx64, m_backstop_bkpt_id, m_backstop_addr); - } - } +ThreadPlanStepThrough::ThreadPlanStepThrough(Thread &thread, + StackID &m_stack_id, + bool stop_others) + : ThreadPlan(ThreadPlan::eKindStepThrough, + "Step through trampolines and prologues", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_start_address(0), m_backstop_bkpt_id(LLDB_INVALID_BREAK_ID), + m_backstop_addr(LLDB_INVALID_ADDRESS), m_return_stack_id(m_stack_id), + m_stop_others(stop_others) { + LookForPlanToStepThroughFromCurrentPC(); + + // If we don't get a valid step through plan, don't bother to set up a + // backstop. + if (m_sub_plan_sp) { + m_start_address = GetThread().GetRegisterContext()->GetPC(0); + + // We are going to return back to the concrete frame 1, we might pass by + // some inlined code that we're in + // the middle of by doing this, but it's easier than trying to figure out + // where the inlined code might return to. + + StackFrameSP return_frame_sp = m_thread.GetFrameWithStackID(m_stack_id); + + if (return_frame_sp) { + m_backstop_addr = return_frame_sp->GetFrameCodeAddress().GetLoadAddress( + m_thread.CalculateTarget().get()); + Breakpoint *return_bp = + m_thread.GetProcess() + ->GetTarget() + .CreateBreakpoint(m_backstop_addr, true, false) + .get(); + if (return_bp != nullptr) { + return_bp->SetThreadID(m_thread.GetID()); + m_backstop_bkpt_id = return_bp->GetID(); + return_bp->SetBreakpointKind("step-through-backstop"); + } + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + log->Printf("Setting backstop breakpoint %d at address: 0x%" PRIx64, + m_backstop_bkpt_id, m_backstop_addr); + } } + } } -ThreadPlanStepThrough::~ThreadPlanStepThrough () -{ - ClearBackstopBreakpoint (); -} +ThreadPlanStepThrough::~ThreadPlanStepThrough() { ClearBackstopBreakpoint(); } -void -ThreadPlanStepThrough::DidPush () -{ - if (m_sub_plan_sp) - PushPlan(m_sub_plan_sp); +void ThreadPlanStepThrough::DidPush() { + if (m_sub_plan_sp) + PushPlan(m_sub_plan_sp); } -void -ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() -{ - DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader(); - if (loader) - m_sub_plan_sp = loader->GetStepThroughTrampolinePlan (m_thread, m_stop_others); - - // If that didn't come up with anything, try the ObjC runtime plugin: - if (!m_sub_plan_sp.get()) - { - ObjCLanguageRuntime *objc_runtime = m_thread.GetProcess()->GetObjCLanguageRuntime(); - if (objc_runtime) - m_sub_plan_sp = objc_runtime->GetStepThroughTrampolinePlan (m_thread, m_stop_others); - } - - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - { - lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0); - if (m_sub_plan_sp) - { - StreamString s; - m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); - log->Printf ("Found step through plan from 0x%" PRIx64 ": %s", current_address, s.GetData()); - } - else - { - log->Printf ("Couldn't find step through plan from address 0x%" PRIx64 ".", current_address); - } +void ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC() { + DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader(); + if (loader) + m_sub_plan_sp = + loader->GetStepThroughTrampolinePlan(m_thread, m_stop_others); + + // If that didn't come up with anything, try the ObjC runtime plugin: + if (!m_sub_plan_sp.get()) { + ObjCLanguageRuntime *objc_runtime = + m_thread.GetProcess()->GetObjCLanguageRuntime(); + if (objc_runtime) + m_sub_plan_sp = + objc_runtime->GetStepThroughTrampolinePlan(m_thread, m_stop_others); + } + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) { + lldb::addr_t current_address = GetThread().GetRegisterContext()->GetPC(0); + if (m_sub_plan_sp) { + StreamString s; + m_sub_plan_sp->GetDescription(&s, lldb::eDescriptionLevelFull); + log->Printf("Found step through plan from 0x%" PRIx64 ": %s", + current_address, s.GetData()); + } else { + log->Printf("Couldn't find step through plan from address 0x%" PRIx64 ".", + current_address); } + } } -void -ThreadPlanStepThrough::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - s->Printf ("Step through"); - else - { - s->PutCString ("Stepping through trampoline code from: "); - s->Address(m_start_address, sizeof (addr_t)); - if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) - { - s->Printf(" with backstop breakpoint ID: %d at address: ", m_backstop_bkpt_id); - s->Address (m_backstop_addr, sizeof (addr_t)); - } - else - s->PutCString (" unable to set a backstop breakpoint."); - } +void ThreadPlanStepThrough::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) + s->Printf("Step through"); + else { + s->PutCString("Stepping through trampoline code from: "); + s->Address(m_start_address, sizeof(addr_t)); + if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { + s->Printf(" with backstop breakpoint ID: %d at address: ", + m_backstop_bkpt_id); + s->Address(m_backstop_addr, sizeof(addr_t)); + } else + s->PutCString(" unable to set a backstop breakpoint."); + } } -bool -ThreadPlanStepThrough::ValidatePlan (Stream *error) -{ - return m_sub_plan_sp.get() != nullptr; +bool ThreadPlanStepThrough::ValidatePlan(Stream *error) { + return m_sub_plan_sp.get() != nullptr; } -bool -ThreadPlanStepThrough::DoPlanExplainsStop (Event *event_ptr) -{ - // If we have a sub-plan, it will have been asked first if we explain the stop, and - // we won't get asked. The only time we would be the one directly asked this question - // is if we hit our backstop breakpoint. - - return HitOurBackstopBreakpoint(); +bool ThreadPlanStepThrough::DoPlanExplainsStop(Event *event_ptr) { + // If we have a sub-plan, it will have been asked first if we explain the + // stop, and + // we won't get asked. The only time we would be the one directly asked this + // question + // is if we hit our backstop breakpoint. + + return HitOurBackstopBreakpoint(); } -bool -ThreadPlanStepThrough::ShouldStop (Event *event_ptr) -{ - // If we've already marked ourselves done, then we're done... - if (IsPlanComplete()) - return true; - - // First, did we hit the backstop breakpoint? - if (HitOurBackstopBreakpoint()) - { - SetPlanComplete(true); - return true; - } +bool ThreadPlanStepThrough::ShouldStop(Event *event_ptr) { + // If we've already marked ourselves done, then we're done... + if (IsPlanComplete()) + return true; - // If we don't have a sub-plan, then we're also done (can't see how we would ever get here - // without a plan, but just in case. - - if (!m_sub_plan_sp) - { - SetPlanComplete(); - return true; - } - - // If the current sub plan is not done, we don't want to stop. Actually, we probably won't - // ever get here in this state, since we generally won't get asked any questions if out - // current sub-plan is not done... - if (!m_sub_plan_sp->IsPlanComplete()) - return false; - - // If our current sub plan failed, then let's just run to our backstop. If we can't do that then just stop. - if (!m_sub_plan_sp->PlanSucceeded()) - { - if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) - { - m_sub_plan_sp.reset(); - return false; - } - else - { - SetPlanComplete(false); - return true; - } - } - - // Next see if there is a specific step through plan at our current pc (these might - // chain, for instance stepping through a dylib trampoline to the objc dispatch function...) - LookForPlanToStepThroughFromCurrentPC(); - if (m_sub_plan_sp) - { - PushPlan (m_sub_plan_sp); - return false; - } - else - { - SetPlanComplete(); - return true; - } -} + // First, did we hit the backstop breakpoint? + if (HitOurBackstopBreakpoint()) { + SetPlanComplete(true); + return true; + } -bool -ThreadPlanStepThrough::StopOthers () -{ - return m_stop_others; -} + // If we don't have a sub-plan, then we're also done (can't see how we would + // ever get here + // without a plan, but just in case. -StateType -ThreadPlanStepThrough::GetPlanRunState () -{ - return eStateRunning; -} + if (!m_sub_plan_sp) { + SetPlanComplete(); + return true; + } + + // If the current sub plan is not done, we don't want to stop. Actually, we + // probably won't + // ever get here in this state, since we generally won't get asked any + // questions if out + // current sub-plan is not done... + if (!m_sub_plan_sp->IsPlanComplete()) + return false; -bool -ThreadPlanStepThrough::DoWillResume (StateType resume_state, bool current_plan) -{ + // If our current sub plan failed, then let's just run to our backstop. If we + // can't do that then just stop. + if (!m_sub_plan_sp->PlanSucceeded()) { + if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { + m_sub_plan_sp.reset(); + return false; + } else { + SetPlanComplete(false); + return true; + } + } + + // Next see if there is a specific step through plan at our current pc (these + // might + // chain, for instance stepping through a dylib trampoline to the objc + // dispatch function...) + LookForPlanToStepThroughFromCurrentPC(); + if (m_sub_plan_sp) { + PushPlan(m_sub_plan_sp); + return false; + } else { + SetPlanComplete(); return true; + } } -bool -ThreadPlanStepThrough::WillStop () -{ - return true; +bool ThreadPlanStepThrough::StopOthers() { return m_stop_others; } + +StateType ThreadPlanStepThrough::GetPlanRunState() { return eStateRunning; } + +bool ThreadPlanStepThrough::DoWillResume(StateType resume_state, + bool current_plan) { + return true; } -void -ThreadPlanStepThrough::ClearBackstopBreakpoint () -{ - if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) - { - m_thread.GetProcess()->GetTarget().RemoveBreakpointByID (m_backstop_bkpt_id); - m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; - } +bool ThreadPlanStepThrough::WillStop() { return true; } + +void ThreadPlanStepThrough::ClearBackstopBreakpoint() { + if (m_backstop_bkpt_id != LLDB_INVALID_BREAK_ID) { + m_thread.GetProcess()->GetTarget().RemoveBreakpointByID(m_backstop_bkpt_id); + m_backstop_bkpt_id = LLDB_INVALID_BREAK_ID; + } } -bool -ThreadPlanStepThrough::MischiefManaged () -{ - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); +bool ThreadPlanStepThrough::MischiefManaged() { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); - if (!IsPlanComplete()) - { - return false; - } - else - { - if (log) - log->Printf("Completed step through step plan."); - - ClearBackstopBreakpoint (); - ThreadPlan::MischiefManaged (); - return true; - } + if (!IsPlanComplete()) { + return false; + } else { + if (log) + log->Printf("Completed step through step plan."); + + ClearBackstopBreakpoint(); + ThreadPlan::MischiefManaged(); + return true; + } } -bool -ThreadPlanStepThrough::HitOurBackstopBreakpoint() -{ - StopInfoSP stop_info_sp(m_thread.GetStopInfo()); - if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) - { - break_id_t stop_value = (break_id_t) stop_info_sp->GetValue(); - BreakpointSiteSP cur_site_sp = m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); - if (cur_site_sp && cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) - { - StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - - if (cur_frame_zero_id == m_return_stack_id) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->PutCString ("ThreadPlanStepThrough hit backstop breakpoint."); - return true; - } - } +bool ThreadPlanStepThrough::HitOurBackstopBreakpoint() { + StopInfoSP stop_info_sp(m_thread.GetStopInfo()); + if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonBreakpoint) { + break_id_t stop_value = (break_id_t)stop_info_sp->GetValue(); + BreakpointSiteSP cur_site_sp = + m_thread.GetProcess()->GetBreakpointSiteList().FindByID(stop_value); + if (cur_site_sp && + cur_site_sp->IsBreakpointAtThisSite(m_backstop_bkpt_id)) { + StackID cur_frame_zero_id = + m_thread.GetStackFrameAtIndex(0)->GetStackID(); + + if (cur_frame_zero_id == m_return_stack_id) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->PutCString("ThreadPlanStepThrough hit backstop breakpoint."); + return true; + } } - return false; + } + return false; } diff --git a/lldb/source/Target/ThreadPlanStepUntil.cpp b/lldb/source/Target/ThreadPlanStepUntil.cpp index 2581fc7b522..a10e2f47c90 100644 --- a/lldb/source/Target/ThreadPlanStepUntil.cpp +++ b/lldb/source/Target/ThreadPlanStepUntil.cpp @@ -23,371 +23,317 @@ using namespace lldb; using namespace lldb_private; //---------------------------------------------------------------------- -// ThreadPlanStepUntil: Run until we reach a given line number or step out of the current frame +// ThreadPlanStepUntil: Run until we reach a given line number or step out of +// the current frame //---------------------------------------------------------------------- -ThreadPlanStepUntil::ThreadPlanStepUntil -( - Thread &thread, - lldb::addr_t *address_list, - size_t num_addresses, - bool stop_others, - uint32_t frame_idx -) : - ThreadPlan (ThreadPlan::eKindStepUntil, "Step until", thread, eVoteNoOpinion, eVoteNoOpinion), - m_step_from_insn (LLDB_INVALID_ADDRESS), - m_return_bp_id (LLDB_INVALID_BREAK_ID), - m_return_addr (LLDB_INVALID_ADDRESS), - m_stepped_out (false), - m_should_stop (false), - m_ran_analyze (false), - m_explains_stop (false), - m_until_points (), - m_stop_others (stop_others) -{ - // Stash away our "until" addresses: - TargetSP target_sp (m_thread.CalculateTarget()); - - StackFrameSP frame_sp (m_thread.GetStackFrameAtIndex (frame_idx)); - if (frame_sp) - { - m_step_from_insn = frame_sp->GetStackID().GetPC(); - lldb::user_id_t thread_id = m_thread.GetID(); - - // Find the return address and set a breakpoint there: - // FIXME - can we do this more securely if we know first_insn? - - StackFrameSP return_frame_sp (m_thread.GetStackFrameAtIndex(frame_idx + 1)); - if (return_frame_sp) - { - // TODO: add inline functionality - m_return_addr = return_frame_sp->GetStackID().GetPC(); - Breakpoint *return_bp = target_sp->CreateBreakpoint (m_return_addr, true, false).get(); - if (return_bp != nullptr) - { - return_bp->SetThreadID(thread_id); - m_return_bp_id = return_bp->GetID(); - return_bp->SetBreakpointKind ("until-return-backstop"); - } - } +ThreadPlanStepUntil::ThreadPlanStepUntil(Thread &thread, + lldb::addr_t *address_list, + size_t num_addresses, bool stop_others, + uint32_t frame_idx) + : ThreadPlan(ThreadPlan::eKindStepUntil, "Step until", thread, + eVoteNoOpinion, eVoteNoOpinion), + m_step_from_insn(LLDB_INVALID_ADDRESS), + m_return_bp_id(LLDB_INVALID_BREAK_ID), + m_return_addr(LLDB_INVALID_ADDRESS), m_stepped_out(false), + m_should_stop(false), m_ran_analyze(false), m_explains_stop(false), + m_until_points(), m_stop_others(stop_others) { + // Stash away our "until" addresses: + TargetSP target_sp(m_thread.CalculateTarget()); + + StackFrameSP frame_sp(m_thread.GetStackFrameAtIndex(frame_idx)); + if (frame_sp) { + m_step_from_insn = frame_sp->GetStackID().GetPC(); + lldb::user_id_t thread_id = m_thread.GetID(); + + // Find the return address and set a breakpoint there: + // FIXME - can we do this more securely if we know first_insn? + + StackFrameSP return_frame_sp(m_thread.GetStackFrameAtIndex(frame_idx + 1)); + if (return_frame_sp) { + // TODO: add inline functionality + m_return_addr = return_frame_sp->GetStackID().GetPC(); + Breakpoint *return_bp = + target_sp->CreateBreakpoint(m_return_addr, true, false).get(); + if (return_bp != nullptr) { + return_bp->SetThreadID(thread_id); + m_return_bp_id = return_bp->GetID(); + return_bp->SetBreakpointKind("until-return-backstop"); + } + } - m_stack_id = frame_sp->GetStackID(); - - // Now set breakpoints on all our return addresses: - for (size_t i = 0; i < num_addresses; i++) - { - Breakpoint *until_bp = target_sp->CreateBreakpoint (address_list[i], true, false).get(); - if (until_bp != nullptr) - { - until_bp->SetThreadID(thread_id); - m_until_points[address_list[i]] = until_bp->GetID(); - until_bp->SetBreakpointKind("until-target"); - } - else - { - m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID; - } - } + m_stack_id = frame_sp->GetStackID(); + + // Now set breakpoints on all our return addresses: + for (size_t i = 0; i < num_addresses; i++) { + Breakpoint *until_bp = + target_sp->CreateBreakpoint(address_list[i], true, false).get(); + if (until_bp != nullptr) { + until_bp->SetThreadID(thread_id); + m_until_points[address_list[i]] = until_bp->GetID(); + until_bp->SetBreakpointKind("until-target"); + } else { + m_until_points[address_list[i]] = LLDB_INVALID_BREAK_ID; + } } + } } -ThreadPlanStepUntil::~ThreadPlanStepUntil () -{ - Clear(); -} +ThreadPlanStepUntil::~ThreadPlanStepUntil() { Clear(); } -void -ThreadPlanStepUntil::Clear() -{ - TargetSP target_sp (m_thread.CalculateTarget()); - if (target_sp) - { - if (m_return_bp_id != LLDB_INVALID_BREAK_ID) - { - target_sp->RemoveBreakpointByID(m_return_bp_id); - m_return_bp_id = LLDB_INVALID_BREAK_ID; - } +void ThreadPlanStepUntil::Clear() { + TargetSP target_sp(m_thread.CalculateTarget()); + if (target_sp) { + if (m_return_bp_id != LLDB_INVALID_BREAK_ID) { + target_sp->RemoveBreakpointByID(m_return_bp_id); + m_return_bp_id = LLDB_INVALID_BREAK_ID; + } - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) - { - target_sp->RemoveBreakpointByID((*pos).second); - } + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + target_sp->RemoveBreakpointByID((*pos).second); } - m_until_points.clear(); + } + m_until_points.clear(); } -void -ThreadPlanStepUntil::GetDescription (Stream *s, lldb::DescriptionLevel level) -{ - if (level == lldb::eDescriptionLevelBrief) - { - s->Printf ("step until"); - if (m_stepped_out) - s->Printf (" - stepped out"); - } - else - { - if (m_until_points.size() == 1) - s->Printf ("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 " using breakpoint %d", - (uint64_t)m_step_from_insn, - (uint64_t) (*m_until_points.begin()).first, - (*m_until_points.begin()).second); - else - { - until_collection::iterator pos, end = m_until_points.end(); - s->Printf ("Stepping from address 0x%" PRIx64 " until we reach one of:", - (uint64_t)m_step_from_insn); - for (pos = m_until_points.begin(); pos != end; pos++) - { - s->Printf ("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t) (*pos).first, (*pos).second); - } - } - s->Printf(" stepped out address is 0x%" PRIx64 ".", (uint64_t) m_return_addr); +void ThreadPlanStepUntil::GetDescription(Stream *s, + lldb::DescriptionLevel level) { + if (level == lldb::eDescriptionLevelBrief) { + s->Printf("step until"); + if (m_stepped_out) + s->Printf(" - stepped out"); + } else { + if (m_until_points.size() == 1) + s->Printf("Stepping from address 0x%" PRIx64 " until we reach 0x%" PRIx64 + " using breakpoint %d", + (uint64_t)m_step_from_insn, + (uint64_t)(*m_until_points.begin()).first, + (*m_until_points.begin()).second); + else { + until_collection::iterator pos, end = m_until_points.end(); + s->Printf("Stepping from address 0x%" PRIx64 " until we reach one of:", + (uint64_t)m_step_from_insn); + for (pos = m_until_points.begin(); pos != end; pos++) { + s->Printf("\n\t0x%" PRIx64 " (bp: %d)", (uint64_t)(*pos).first, + (*pos).second); + } } + s->Printf(" stepped out address is 0x%" PRIx64 ".", + (uint64_t)m_return_addr); + } } -bool -ThreadPlanStepUntil::ValidatePlan (Stream *error) -{ - if (m_return_bp_id == LLDB_INVALID_BREAK_ID) +bool ThreadPlanStepUntil::ValidatePlan(Stream *error) { + if (m_return_bp_id == LLDB_INVALID_BREAK_ID) + return false; + else { + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + if (!LLDB_BREAK_ID_IS_VALID((*pos).second)) return false; - else - { - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) - { - if (!LLDB_BREAK_ID_IS_VALID ((*pos).second)) - return false; - } - return true; } + return true; + } } -void -ThreadPlanStepUntil::AnalyzeStop() -{ - if (m_ran_analyze) +void ThreadPlanStepUntil::AnalyzeStop() { + if (m_ran_analyze) + return; + + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + m_should_stop = true; + m_explains_stop = false; + + if (stop_info_sp) { + StopReason reason = stop_info_sp->GetStopReason(); + + if (reason == eStopReasonBreakpoint) { + // If this is OUR breakpoint, we're fine, otherwise we don't know why this + // happened... + BreakpointSiteSP this_site = + m_thread.GetProcess()->GetBreakpointSiteList().FindByID( + stop_info_sp->GetValue()); + if (!this_site) { + m_explains_stop = false; return; - - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - m_should_stop = true; - m_explains_stop = false; - - if (stop_info_sp) - { - StopReason reason = stop_info_sp->GetStopReason(); - - if (reason == eStopReasonBreakpoint) - { - // If this is OUR breakpoint, we're fine, otherwise we don't know why this happened... - BreakpointSiteSP this_site = m_thread.GetProcess()->GetBreakpointSiteList().FindByID (stop_info_sp->GetValue()); - if (!this_site) - { - m_explains_stop = false; - return; + } + + if (this_site->IsBreakpointAtThisSite(m_return_bp_id)) { + // If we are at our "step out" breakpoint, and the stack depth has + // shrunk, then + // this is indeed our stop. + // If the stack depth has grown, then we've hit our step out breakpoint + // recursively. + // If we are the only breakpoint at that location, then we do explain + // the stop, and + // we'll just continue. + // If there was another breakpoint here, then we don't explain the stop, + // but we won't + // mark ourselves Completed, because maybe that breakpoint will + // continue, and then + // we'll finish the "until". + bool done; + StackID cur_frame_zero_id; + + done = (m_stack_id < cur_frame_zero_id); + + if (done) { + m_stepped_out = true; + SetPlanComplete(); + } else + m_should_stop = false; + + if (this_site->GetNumberOfOwners() == 1) + m_explains_stop = true; + else + m_explains_stop = false; + return; + } else { + // Check if we've hit one of our "until" breakpoints. + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + if (this_site->IsBreakpointAtThisSite((*pos).second)) { + // If we're at the right stack depth, then we're done. + + bool done; + StackID frame_zero_id = + m_thread.GetStackFrameAtIndex(0)->GetStackID(); + + if (frame_zero_id == m_stack_id) + done = true; + else if (frame_zero_id < m_stack_id) + done = false; + else { + StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1); + + // But if we can't even unwind one frame we should just get out of + // here & stop... + if (older_frame_sp) { + const SymbolContext &older_context = + older_frame_sp->GetSymbolContext(eSymbolContextEverything); + SymbolContext stack_context; + m_stack_id.GetSymbolContextScope()->CalculateSymbolContext( + &stack_context); + + done = (older_context == stack_context); + } else + done = false; } - if (this_site->IsBreakpointAtThisSite (m_return_bp_id)) - { - // If we are at our "step out" breakpoint, and the stack depth has shrunk, then - // this is indeed our stop. - // If the stack depth has grown, then we've hit our step out breakpoint recursively. - // If we are the only breakpoint at that location, then we do explain the stop, and - // we'll just continue. - // If there was another breakpoint here, then we don't explain the stop, but we won't - // mark ourselves Completed, because maybe that breakpoint will continue, and then - // we'll finish the "until". - bool done; - StackID cur_frame_zero_id; - - done = (m_stack_id < cur_frame_zero_id); - - if (done) - { - m_stepped_out = true; - SetPlanComplete(); - } - else - m_should_stop = false; - - if (this_site->GetNumberOfOwners() == 1) - m_explains_stop = true; - else - m_explains_stop = false; - return; - } + if (done) + SetPlanComplete(); else - { - // Check if we've hit one of our "until" breakpoints. - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) - { - if (this_site->IsBreakpointAtThisSite ((*pos).second)) - { - // If we're at the right stack depth, then we're done. - - bool done; - StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID(); - - if (frame_zero_id == m_stack_id) - done = true; - else if (frame_zero_id < m_stack_id) - done = false; - else - { - StackFrameSP older_frame_sp = m_thread.GetStackFrameAtIndex(1); - - // But if we can't even unwind one frame we should just get out of here & stop... - if (older_frame_sp) - { - const SymbolContext &older_context - = older_frame_sp->GetSymbolContext(eSymbolContextEverything); - SymbolContext stack_context; - m_stack_id.GetSymbolContextScope()->CalculateSymbolContext(&stack_context); - - done = (older_context == stack_context); - } - else - done = false; - } - - if (done) - SetPlanComplete(); - else - m_should_stop = false; - - // Otherwise we've hit this breakpoint recursively. If we're the - // only breakpoint here, then we do explain the stop, and we'll continue. - // If not then we should let higher plans handle this stop. - if (this_site->GetNumberOfOwners() == 1) - m_explains_stop = true; - else - { - m_should_stop = true; - m_explains_stop = false; - } - return; - } - } + m_should_stop = false; + + // Otherwise we've hit this breakpoint recursively. If we're the + // only breakpoint here, then we do explain the stop, and we'll + // continue. + // If not then we should let higher plans handle this stop. + if (this_site->GetNumberOfOwners() == 1) + m_explains_stop = true; + else { + m_should_stop = true; + m_explains_stop = false; } - // If we get here we haven't hit any of our breakpoints, so let the higher - // plans take care of the stop. - m_explains_stop = false; return; + } } - else if (IsUsuallyUnexplainedStopReason(reason)) - { - m_explains_stop = false; - } - else - { - m_explains_stop = true; - } + } + // If we get here we haven't hit any of our breakpoints, so let the higher + // plans take care of the stop. + m_explains_stop = false; + return; + } else if (IsUsuallyUnexplainedStopReason(reason)) { + m_explains_stop = false; + } else { + m_explains_stop = true; } + } } -bool -ThreadPlanStepUntil::DoPlanExplainsStop (Event *event_ptr) -{ - // We don't explain signals or breakpoints (breakpoints that handle stepping in or - // out will be handled by a child plan. - AnalyzeStop(); - return m_explains_stop; +bool ThreadPlanStepUntil::DoPlanExplainsStop(Event *event_ptr) { + // We don't explain signals or breakpoints (breakpoints that handle stepping + // in or + // out will be handled by a child plan. + AnalyzeStop(); + return m_explains_stop; } -bool -ThreadPlanStepUntil::ShouldStop (Event *event_ptr) -{ - // If we've told our self in ExplainsStop that we plan to continue, then - // do so here. Otherwise, as long as this thread has stopped for a reason, - // we will stop. +bool ThreadPlanStepUntil::ShouldStop(Event *event_ptr) { + // If we've told our self in ExplainsStop that we plan to continue, then + // do so here. Otherwise, as long as this thread has stopped for a reason, + // we will stop. - StopInfoSP stop_info_sp = GetPrivateStopInfo (); - if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone) - return false; + StopInfoSP stop_info_sp = GetPrivateStopInfo(); + if (!stop_info_sp || stop_info_sp->GetStopReason() == eStopReasonNone) + return false; - AnalyzeStop(); - return m_should_stop; + AnalyzeStop(); + return m_should_stop; } -bool -ThreadPlanStepUntil::StopOthers () -{ - return m_stop_others; -} +bool ThreadPlanStepUntil::StopOthers() { return m_stop_others; } + +StateType ThreadPlanStepUntil::GetPlanRunState() { return eStateRunning; } + +bool ThreadPlanStepUntil::DoWillResume(StateType resume_state, + bool current_plan) { + if (current_plan) { + TargetSP target_sp(m_thread.CalculateTarget()); + if (target_sp) { + Breakpoint *return_bp = + target_sp->GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(true); + + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + Breakpoint *until_bp = + target_sp->GetBreakpointByID((*pos).second).get(); + if (until_bp != nullptr) + until_bp->SetEnabled(true); + } + } + } -StateType -ThreadPlanStepUntil::GetPlanRunState () -{ - return eStateRunning; + m_should_stop = true; + m_ran_analyze = false; + m_explains_stop = false; + return true; } -bool -ThreadPlanStepUntil::DoWillResume (StateType resume_state, bool current_plan) -{ - if (current_plan) - { - TargetSP target_sp (m_thread.CalculateTarget()); - if (target_sp) - { - Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled (true); - - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) - { - Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); - if (until_bp != nullptr) - until_bp->SetEnabled (true); - } - } +bool ThreadPlanStepUntil::WillStop() { + TargetSP target_sp(m_thread.CalculateTarget()); + if (target_sp) { + Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); + if (return_bp != nullptr) + return_bp->SetEnabled(false); + + until_collection::iterator pos, end = m_until_points.end(); + for (pos = m_until_points.begin(); pos != end; pos++) { + Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); + if (until_bp != nullptr) + until_bp->SetEnabled(false); } - - m_should_stop = true; - m_ran_analyze = false; - m_explains_stop = false; - return true; + } + return true; } -bool -ThreadPlanStepUntil::WillStop () -{ - TargetSP target_sp (m_thread.CalculateTarget()); - if (target_sp) - { - Breakpoint *return_bp = target_sp->GetBreakpointByID(m_return_bp_id).get(); - if (return_bp != nullptr) - return_bp->SetEnabled (false); - - until_collection::iterator pos, end = m_until_points.end(); - for (pos = m_until_points.begin(); pos != end; pos++) - { - Breakpoint *until_bp = target_sp->GetBreakpointByID((*pos).second).get(); - if (until_bp != nullptr) - until_bp->SetEnabled (false); - } - } - return true; -} +bool ThreadPlanStepUntil::MischiefManaged() { + // I'm letting "PlanExplainsStop" do all the work, and just reporting that + // here. + bool done = false; + if (IsPlanComplete()) { + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP)); + if (log) + log->Printf("Completed step until plan."); -bool -ThreadPlanStepUntil::MischiefManaged () -{ - // I'm letting "PlanExplainsStop" do all the work, and just reporting that here. - bool done = false; - if (IsPlanComplete()) - { - Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP)); - if (log) - log->Printf("Completed step until plan."); - - Clear(); - done = true; - } - if (done) - ThreadPlan::MischiefManaged (); + Clear(); + done = true; + } + if (done) + ThreadPlan::MischiefManaged(); - return done; + return done; } diff --git a/lldb/source/Target/ThreadPlanTracer.cpp b/lldb/source/Target/ThreadPlanTracer.cpp index e3fcbaaaef7..892d64614cc 100644 --- a/lldb/source/Target/ThreadPlanTracer.cpp +++ b/lldb/source/Target/ThreadPlanTracer.cpp @@ -13,7 +13,6 @@ // Other libraries and framework includes // Project includes -#include "lldb/Target/ThreadPlan.h" #include "lldb/Core/ArchSpec.h" #include "lldb/Core/DataBufferHeap.h" #include "lldb/Core/DataExtractor.h" @@ -27,244 +26,206 @@ #include "lldb/Symbol/TypeList.h" #include "lldb/Symbol/TypeSystem.h" #include "lldb/Target/ABI.h" -#include "lldb/Target/RegisterContext.h" -#include "lldb/Target/Thread.h" #include "lldb/Target/Process.h" +#include "lldb/Target/RegisterContext.h" #include "lldb/Target/SectionLoadList.h" #include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Target/ThreadPlan.h" using namespace lldb; using namespace lldb_private; #pragma mark ThreadPlanTracer -ThreadPlanTracer::ThreadPlanTracer (Thread &thread, lldb::StreamSP &stream_sp) : - m_thread (thread), - m_single_step(true), - m_enabled (false), - m_stream_sp (stream_sp) -{ +ThreadPlanTracer::ThreadPlanTracer(Thread &thread, lldb::StreamSP &stream_sp) + : m_thread(thread), m_single_step(true), m_enabled(false), + m_stream_sp(stream_sp) {} + +ThreadPlanTracer::ThreadPlanTracer(Thread &thread) + : m_thread(thread), m_single_step(true), m_enabled(false), m_stream_sp() {} + +Stream *ThreadPlanTracer::GetLogStream() { + if (m_stream_sp) + return m_stream_sp.get(); + else { + TargetSP target_sp(m_thread.CalculateTarget()); + if (target_sp) + return target_sp->GetDebugger().GetOutputFile().get(); + } + return nullptr; } -ThreadPlanTracer::ThreadPlanTracer (Thread &thread) : - m_thread (thread), - m_single_step(true), - m_enabled (false), - m_stream_sp () -{ -} +void ThreadPlanTracer::Log() { + SymbolContext sc; + bool show_frame_index = false; + bool show_fullpaths = false; -Stream * -ThreadPlanTracer::GetLogStream () -{ - if (m_stream_sp) - return m_stream_sp.get(); - else - { - TargetSP target_sp (m_thread.CalculateTarget()); - if (target_sp) - return target_sp->GetDebugger().GetOutputFile().get(); - } - return nullptr; -} - -void -ThreadPlanTracer::Log() -{ - SymbolContext sc; - bool show_frame_index = false; - bool show_fullpaths = false; - - Stream *stream = GetLogStream(); - if (stream) - { - m_thread.GetStackFrameAtIndex(0)->Dump (stream, show_frame_index, show_fullpaths); - stream->Printf("\n"); - stream->Flush(); - } + Stream *stream = GetLogStream(); + if (stream) { + m_thread.GetStackFrameAtIndex(0)->Dump(stream, show_frame_index, + show_fullpaths); + stream->Printf("\n"); + stream->Flush(); + } } -bool -ThreadPlanTracer::TracerExplainsStop () -{ - if (m_enabled && m_single_step) - { - lldb::StopInfoSP stop_info = m_thread.GetStopInfo(); - return (stop_info->GetStopReason() == eStopReasonTrace); - } - else - return false; +bool ThreadPlanTracer::TracerExplainsStop() { + if (m_enabled && m_single_step) { + lldb::StopInfoSP stop_info = m_thread.GetStopInfo(); + return (stop_info->GetStopReason() == eStopReasonTrace); + } else + return false; } #pragma mark ThreadPlanAssemblyTracer -ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread, lldb::StreamSP &stream_sp) : - ThreadPlanTracer (thread, stream_sp), - m_disassembler_sp (), - m_intptr_type (), - m_register_values () -{ -} +ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread, + lldb::StreamSP &stream_sp) + : ThreadPlanTracer(thread, stream_sp), m_disassembler_sp(), m_intptr_type(), + m_register_values() {} -ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer (Thread &thread) : - ThreadPlanTracer (thread), - m_disassembler_sp (), - m_intptr_type (), - m_register_values () -{ -} +ThreadPlanAssemblyTracer::ThreadPlanAssemblyTracer(Thread &thread) + : ThreadPlanTracer(thread), m_disassembler_sp(), m_intptr_type(), + m_register_values() {} -Disassembler * -ThreadPlanAssemblyTracer::GetDisassembler () -{ - if (!m_disassembler_sp) - m_disassembler_sp = Disassembler::FindPlugin(m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr); - return m_disassembler_sp.get(); +Disassembler *ThreadPlanAssemblyTracer::GetDisassembler() { + if (!m_disassembler_sp) + m_disassembler_sp = Disassembler::FindPlugin( + m_thread.GetProcess()->GetTarget().GetArchitecture(), nullptr, nullptr); + return m_disassembler_sp.get(); } -TypeFromUser -ThreadPlanAssemblyTracer::GetIntPointerType() -{ - if (!m_intptr_type.IsValid ()) - { - TargetSP target_sp (m_thread.CalculateTarget()); - if (target_sp) - { - TypeSystem *type_system = target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC); - if (type_system) - m_intptr_type = TypeFromUser(type_system->GetBuiltinTypeForEncodingAndBitSize(eEncodingUint, target_sp->GetArchitecture().GetAddressByteSize() * 8)); - } +TypeFromUser ThreadPlanAssemblyTracer::GetIntPointerType() { + if (!m_intptr_type.IsValid()) { + TargetSP target_sp(m_thread.CalculateTarget()); + if (target_sp) { + TypeSystem *type_system = + target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC); + if (type_system) + m_intptr_type = + TypeFromUser(type_system->GetBuiltinTypeForEncodingAndBitSize( + eEncodingUint, + target_sp->GetArchitecture().GetAddressByteSize() * 8)); } - return m_intptr_type; + } + return m_intptr_type; } ThreadPlanAssemblyTracer::~ThreadPlanAssemblyTracer() = default; -void -ThreadPlanAssemblyTracer::TracingStarted () -{ - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); - - if (m_register_values.empty()) - m_register_values.resize (reg_ctx->GetRegisterCount()); -} +void ThreadPlanAssemblyTracer::TracingStarted() { + RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); -void -ThreadPlanAssemblyTracer::TracingEnded () -{ - m_register_values.clear(); + if (m_register_values.empty()) + m_register_values.resize(reg_ctx->GetRegisterCount()); } -void -ThreadPlanAssemblyTracer::Log () -{ - Stream *stream = GetLogStream (); - - if (!stream) - return; - - RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); - - lldb::addr_t pc = reg_ctx->GetPC(); - ProcessSP process_sp (m_thread.GetProcess()); - Address pc_addr; - bool addr_valid = false; - uint8_t buffer[16] = {0}; // Must be big enough for any single instruction - addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress (pc, pc_addr); - - pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, Address::DumpStyleModuleWithFileAddress); - stream->PutCString (" "); - - Disassembler *disassembler = GetDisassembler(); - if (disassembler) - { - Error err; - process_sp->ReadMemory(pc, buffer, sizeof(buffer), err); - - if (err.Success()) - { - DataExtractor extractor(buffer, sizeof(buffer), - process_sp->GetByteOrder(), - process_sp->GetAddressByteSize()); - - bool data_from_file = false; - if (addr_valid) - disassembler->DecodeInstructions (pc_addr, extractor, 0, 1, false, data_from_file); - else - disassembler->DecodeInstructions (Address (pc), extractor, 0, 1, false, data_from_file); - - InstructionList &instruction_list = disassembler->GetInstructionList(); - const uint32_t max_opcode_byte_size = instruction_list.GetMaxOpcocdeByteSize(); - - if (instruction_list.GetSize()) - { - const bool show_bytes = true; - const bool show_address = true; - Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get(); - const FormatEntity::Entry *disassemble_format = m_thread.GetProcess()->GetTarget().GetDebugger().GetDisassemblyFormat(); - instruction->Dump(stream, - max_opcode_byte_size, - show_address, - show_bytes, - nullptr, - nullptr, - nullptr, - disassemble_format, - 0); - } - } +void ThreadPlanAssemblyTracer::TracingEnded() { m_register_values.clear(); } + +void ThreadPlanAssemblyTracer::Log() { + Stream *stream = GetLogStream(); + + if (!stream) + return; + + RegisterContext *reg_ctx = m_thread.GetRegisterContext().get(); + + lldb::addr_t pc = reg_ctx->GetPC(); + ProcessSP process_sp(m_thread.GetProcess()); + Address pc_addr; + bool addr_valid = false; + uint8_t buffer[16] = {0}; // Must be big enough for any single instruction + addr_valid = process_sp->GetTarget().GetSectionLoadList().ResolveLoadAddress( + pc, pc_addr); + + pc_addr.Dump(stream, &m_thread, Address::DumpStyleResolvedDescription, + Address::DumpStyleModuleWithFileAddress); + stream->PutCString(" "); + + Disassembler *disassembler = GetDisassembler(); + if (disassembler) { + Error err; + process_sp->ReadMemory(pc, buffer, sizeof(buffer), err); + + if (err.Success()) { + DataExtractor extractor(buffer, sizeof(buffer), + process_sp->GetByteOrder(), + process_sp->GetAddressByteSize()); + + bool data_from_file = false; + if (addr_valid) + disassembler->DecodeInstructions(pc_addr, extractor, 0, 1, false, + data_from_file); + else + disassembler->DecodeInstructions(Address(pc), extractor, 0, 1, false, + data_from_file); + + InstructionList &instruction_list = disassembler->GetInstructionList(); + const uint32_t max_opcode_byte_size = + instruction_list.GetMaxOpcocdeByteSize(); + + if (instruction_list.GetSize()) { + const bool show_bytes = true; + const bool show_address = true; + Instruction *instruction = + instruction_list.GetInstructionAtIndex(0).get(); + const FormatEntity::Entry *disassemble_format = + m_thread.GetProcess() + ->GetTarget() + .GetDebugger() + .GetDisassemblyFormat(); + instruction->Dump(stream, max_opcode_byte_size, show_address, + show_bytes, nullptr, nullptr, nullptr, + disassemble_format, 0); + } } - - const ABI *abi = process_sp->GetABI().get(); - TypeFromUser intptr_type = GetIntPointerType(); - - if (abi && intptr_type.IsValid()) - { - ValueList value_list; - const int num_args = 1; - - for (int arg_index = 0; arg_index < num_args; ++arg_index) - { - Value value; - value.SetValueType (Value::eValueTypeScalar); -// value.SetContext (Value::eContextTypeClangType, intptr_type.GetOpaqueQualType()); - value.SetCompilerType (intptr_type); - value_list.PushValue (value); - } - - if (abi->GetArgumentValues (m_thread, value_list)) - { - for (int arg_index = 0; arg_index < num_args; ++arg_index) - { - stream->Printf("\n\targ[%d]=%llx", arg_index, value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong()); - - if (arg_index + 1 < num_args) - stream->PutCString (", "); - } - } + } + + const ABI *abi = process_sp->GetABI().get(); + TypeFromUser intptr_type = GetIntPointerType(); + + if (abi && intptr_type.IsValid()) { + ValueList value_list; + const int num_args = 1; + + for (int arg_index = 0; arg_index < num_args; ++arg_index) { + Value value; + value.SetValueType(Value::eValueTypeScalar); + // value.SetContext (Value::eContextTypeClangType, + // intptr_type.GetOpaqueQualType()); + value.SetCompilerType(intptr_type); + value_list.PushValue(value); } - RegisterValue reg_value; - for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount(); - reg_num < num_registers; - ++reg_num) - { - const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); - if (reg_ctx->ReadRegister (reg_info, reg_value)) - { - assert (reg_num < m_register_values.size()); - if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid || - reg_value != m_register_values[reg_num]) - { - if (reg_value.GetType() != RegisterValue::eTypeInvalid) - { - stream->PutCString ("\n\t"); - reg_value.Dump(stream, reg_info, true, false, eFormatDefault); - } - } - m_register_values[reg_num] = reg_value; + if (abi->GetArgumentValues(m_thread, value_list)) { + for (int arg_index = 0; arg_index < num_args; ++arg_index) { + stream->Printf( + "\n\targ[%d]=%llx", arg_index, + value_list.GetValueAtIndex(arg_index)->GetScalar().ULongLong()); + + if (arg_index + 1 < num_args) + stream->PutCString(", "); + } + } + } + + RegisterValue reg_value; + for (uint32_t reg_num = 0, num_registers = reg_ctx->GetRegisterCount(); + reg_num < num_registers; ++reg_num) { + const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoAtIndex(reg_num); + if (reg_ctx->ReadRegister(reg_info, reg_value)) { + assert(reg_num < m_register_values.size()); + if (m_register_values[reg_num].GetType() == RegisterValue::eTypeInvalid || + reg_value != m_register_values[reg_num]) { + if (reg_value.GetType() != RegisterValue::eTypeInvalid) { + stream->PutCString("\n\t"); + reg_value.Dump(stream, reg_info, true, false, eFormatDefault); } + } + m_register_values[reg_num] = reg_value; } - stream->EOL(); - stream->Flush(); + } + stream->EOL(); + stream->Flush(); } diff --git a/lldb/source/Target/ThreadSpec.cpp b/lldb/source/Target/ThreadSpec.cpp index f877f521bd5..1d217e00035 100644 --- a/lldb/source/Target/ThreadSpec.cpp +++ b/lldb/source/Target/ThreadSpec.cpp @@ -17,142 +17,107 @@ using namespace lldb; using namespace lldb_private; -ThreadSpec::ThreadSpec() : - m_index (UINT32_MAX), - m_tid (LLDB_INVALID_THREAD_ID), - m_name(), - m_queue_name () -{ -} +ThreadSpec::ThreadSpec() + : m_index(UINT32_MAX), m_tid(LLDB_INVALID_THREAD_ID), m_name(), + m_queue_name() {} -ThreadSpec::ThreadSpec(const ThreadSpec &rhs) : - m_index(rhs.m_index), - m_tid(rhs.m_tid), - m_name(rhs.m_name), - m_queue_name(rhs.m_queue_name) -{ -} +ThreadSpec::ThreadSpec(const ThreadSpec &rhs) + : m_index(rhs.m_index), m_tid(rhs.m_tid), m_name(rhs.m_name), + m_queue_name(rhs.m_queue_name) {} -const ThreadSpec & -ThreadSpec::operator=(const ThreadSpec &rhs) -{ - m_index = rhs.m_index; - m_tid = rhs.m_tid; - m_name = rhs.m_name; - m_queue_name = rhs.m_queue_name; - return *this; +const ThreadSpec &ThreadSpec::operator=(const ThreadSpec &rhs) { + m_index = rhs.m_index; + m_tid = rhs.m_tid; + m_name = rhs.m_name; + m_queue_name = rhs.m_queue_name; + return *this; } -const char * -ThreadSpec::GetName () const -{ - return m_name.empty() ? nullptr : m_name.c_str(); +const char *ThreadSpec::GetName() const { + return m_name.empty() ? nullptr : m_name.c_str(); } -const char * -ThreadSpec::GetQueueName () const -{ - return m_queue_name.empty() ? nullptr : m_queue_name.c_str(); +const char *ThreadSpec::GetQueueName() const { + return m_queue_name.empty() ? nullptr : m_queue_name.c_str(); } -bool -ThreadSpec::TIDMatches (Thread &thread) const -{ - if (m_tid == LLDB_INVALID_THREAD_ID) - return true; - - lldb::tid_t thread_id = thread.GetID(); - return TIDMatches (thread_id); +bool ThreadSpec::TIDMatches(Thread &thread) const { + if (m_tid == LLDB_INVALID_THREAD_ID) + return true; + + lldb::tid_t thread_id = thread.GetID(); + return TIDMatches(thread_id); } -bool -ThreadSpec::IndexMatches (Thread &thread) const -{ - if (m_index == UINT32_MAX) - return true; - uint32_t index = thread.GetIndexID(); - return IndexMatches (index); +bool ThreadSpec::IndexMatches(Thread &thread) const { + if (m_index == UINT32_MAX) + return true; + uint32_t index = thread.GetIndexID(); + return IndexMatches(index); } -bool -ThreadSpec::NameMatches (Thread &thread) const -{ - if (m_name.empty()) - return true; - - const char *name = thread.GetName(); - return NameMatches (name); +bool ThreadSpec::NameMatches(Thread &thread) const { + if (m_name.empty()) + return true; + + const char *name = thread.GetName(); + return NameMatches(name); } -bool -ThreadSpec::QueueNameMatches (Thread &thread) const -{ - if (m_queue_name.empty()) - return true; - - const char *queue_name = thread.GetQueueName(); - return QueueNameMatches (queue_name); +bool ThreadSpec::QueueNameMatches(Thread &thread) const { + if (m_queue_name.empty()) + return true; + + const char *queue_name = thread.GetQueueName(); + return QueueNameMatches(queue_name); } -bool -ThreadSpec::ThreadPassesBasicTests (Thread &thread) const -{ - if (!HasSpecification()) - return true; - - if (!TIDMatches(thread)) - return false; - - if (!IndexMatches(thread)) - return false; - - if (!NameMatches (thread)) - return false; - - if (!QueueNameMatches (thread)) - return false; - +bool ThreadSpec::ThreadPassesBasicTests(Thread &thread) const { + if (!HasSpecification()) return true; + + if (!TIDMatches(thread)) + return false; + + if (!IndexMatches(thread)) + return false; + + if (!NameMatches(thread)) + return false; + + if (!QueueNameMatches(thread)) + return false; + + return true; } -bool -ThreadSpec::HasSpecification() const -{ - return (m_index != UINT32_MAX || m_tid != LLDB_INVALID_THREAD_ID || !m_name.empty() || !m_queue_name.empty()); +bool ThreadSpec::HasSpecification() const { + return (m_index != UINT32_MAX || m_tid != LLDB_INVALID_THREAD_ID || + !m_name.empty() || !m_queue_name.empty()); } -void -ThreadSpec::GetDescription (Stream *s, lldb::DescriptionLevel level) const -{ - if (!HasSpecification()) - { - if (level == eDescriptionLevelBrief) - { - s->PutCString("thread spec: no "); - } +void ThreadSpec::GetDescription(Stream *s, lldb::DescriptionLevel level) const { + if (!HasSpecification()) { + if (level == eDescriptionLevelBrief) { + s->PutCString("thread spec: no "); } - else - { - if (level == eDescriptionLevelBrief) - { - s->PutCString("thread spec: yes "); - } - else - { - if (GetTID() != LLDB_INVALID_THREAD_ID) - s->Printf("tid: 0x%" PRIx64 " ", GetTID()); - - if (GetIndex() != UINT32_MAX) - s->Printf("index: %d ", GetIndex()); - - const char *name = GetName(); - if (name) - s->Printf ("thread name: \"%s\" ", name); - - const char *queue_name = GetQueueName(); - if (queue_name) - s->Printf ("queue name: \"%s\" ", queue_name); - } + } else { + if (level == eDescriptionLevelBrief) { + s->PutCString("thread spec: yes "); + } else { + if (GetTID() != LLDB_INVALID_THREAD_ID) + s->Printf("tid: 0x%" PRIx64 " ", GetTID()); + + if (GetIndex() != UINT32_MAX) + s->Printf("index: %d ", GetIndex()); + + const char *name = GetName(); + if (name) + s->Printf("thread name: \"%s\" ", name); + const char *queue_name = GetQueueName(); + if (queue_name) + s->Printf("queue name: \"%s\" ", queue_name); } + } } diff --git a/lldb/source/Target/UnixSignals.cpp b/lldb/source/Target/UnixSignals.cpp index 92309065a91..cee69bf67db 100644 --- a/lldb/source/Target/UnixSignals.cpp +++ b/lldb/source/Target/UnixSignals.cpp @@ -7,340 +7,280 @@ // //===----------------------------------------------------------------------===// - // C Includes // C++ Includes // Other libraries and framework includes // Project includes #include "lldb/Target/UnixSignals.h" -#include "lldb/Core/ArchSpec.h" -#include "lldb/Host/StringConvert.h" #include "Plugins/Process/Utility/FreeBSDSignals.h" #include "Plugins/Process/Utility/LinuxSignals.h" #include "Plugins/Process/Utility/MipsLinuxSignals.h" #include "Plugins/Process/Utility/NetBSDSignals.h" +#include "lldb/Core/ArchSpec.h" +#include "lldb/Host/StringConvert.h" using namespace lldb_private; -UnixSignals::Signal::Signal(const char *name, - bool default_suppress, - bool default_stop, - bool default_notify, - const char *description, - const char *alias) : - m_name (name), - m_alias (alias), - m_description (), - m_suppress (default_suppress), - m_stop (default_stop), - m_notify (default_notify) -{ - if (description) - m_description.assign (description); +UnixSignals::Signal::Signal(const char *name, bool default_suppress, + bool default_stop, bool default_notify, + const char *description, const char *alias) + : m_name(name), m_alias(alias), m_description(), + m_suppress(default_suppress), m_stop(default_stop), + m_notify(default_notify) { + if (description) + m_description.assign(description); } -lldb::UnixSignalsSP -UnixSignals::Create(const ArchSpec &arch) -{ - const auto &triple = arch.GetTriple(); - switch (triple.getOS()) - { - case llvm::Triple::Linux: - { - switch (triple.getArch()) - { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - return std::make_shared<MipsLinuxSignals>(); - default: - return std::make_shared<LinuxSignals>(); - } - } - case llvm::Triple::FreeBSD: - case llvm::Triple::OpenBSD: - return std::make_shared<FreeBSDSignals>(); - case llvm::Triple::NetBSD: - return std::make_shared<NetBSDSignals>(); - default: - return std::make_shared<UnixSignals>(); +lldb::UnixSignalsSP UnixSignals::Create(const ArchSpec &arch) { + const auto &triple = arch.GetTriple(); + switch (triple.getOS()) { + case llvm::Triple::Linux: { + switch (triple.getArch()) { + case llvm::Triple::mips: + case llvm::Triple::mipsel: + case llvm::Triple::mips64: + case llvm::Triple::mips64el: + return std::make_shared<MipsLinuxSignals>(); + default: + return std::make_shared<LinuxSignals>(); } + } + case llvm::Triple::FreeBSD: + case llvm::Triple::OpenBSD: + return std::make_shared<FreeBSDSignals>(); + case llvm::Triple::NetBSD: + return std::make_shared<NetBSDSignals>(); + default: + return std::make_shared<UnixSignals>(); + } } //---------------------------------------------------------------------- // UnixSignals constructor //---------------------------------------------------------------------- -UnixSignals::UnixSignals () -{ - Reset (); -} +UnixSignals::UnixSignals() { Reset(); } -UnixSignals::UnixSignals(const UnixSignals &rhs) - : m_signals(rhs.m_signals) -{ -} +UnixSignals::UnixSignals(const UnixSignals &rhs) : m_signals(rhs.m_signals) {} UnixSignals::~UnixSignals() = default; -void -UnixSignals::Reset () -{ - // This builds one standard set of Unix Signals. If yours aren't quite in this - // order, you can either subclass this class, and use Add & Remove to change them - // or you can subclass and build them afresh in your constructor; - // - // Note: the signals below are the Darwin signals. Do not change these! - m_signals.clear(); - // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION - // ====== ============ ======== ====== ====== =================================================== - AddSignal (1, "SIGHUP", false, true , true , "hangup"); - AddSignal (2, "SIGINT", true , true , true , "interrupt"); - AddSignal (3, "SIGQUIT", false, true , true , "quit"); - AddSignal (4, "SIGILL", false, true , true , "illegal instruction"); - AddSignal (5, "SIGTRAP", true , true , true , "trace trap (not reset when caught)"); - AddSignal (6, "SIGABRT", false, true , true , "abort()"); - AddSignal (7, "SIGEMT", false, true , true , "pollable event"); - AddSignal (8, "SIGFPE", false, true , true , "floating point exception"); - AddSignal (9, "SIGKILL", false, true , true , "kill"); - AddSignal (10, "SIGBUS", false, true , true , "bus error"); - AddSignal (11, "SIGSEGV", false, true , true , "segmentation violation"); - AddSignal (12, "SIGSYS", false, true , true , "bad argument to system call"); - AddSignal (13, "SIGPIPE", false, true , true , "write on a pipe with no one to read it"); - AddSignal (14, "SIGALRM", false, false, false, "alarm clock"); - AddSignal (15, "SIGTERM", false, true , true , "software termination signal from kill"); - AddSignal (16, "SIGURG", false, false, false, "urgent condition on IO channel"); - AddSignal (17, "SIGSTOP", true , true , true , "sendable stop signal not from tty"); - AddSignal (18, "SIGTSTP", false, true , true , "stop signal from tty"); - AddSignal (19, "SIGCONT", false, true , true , "continue a stopped process"); - AddSignal (20, "SIGCHLD", false, false, false, "to parent on child stop or exit"); - AddSignal (21, "SIGTTIN", false, true , true , "to readers process group upon background tty read"); - AddSignal (22, "SIGTTOU", false, true , true , "to readers process group upon background tty write"); - AddSignal (23, "SIGIO", false, false, false, "input/output possible signal"); - AddSignal (24, "SIGXCPU", false, true , true , "exceeded CPU time limit"); - AddSignal (25, "SIGXFSZ", false, true , true , "exceeded file size limit"); - AddSignal (26, "SIGVTALRM", false, false, false, "virtual time alarm"); - AddSignal (27, "SIGPROF", false, false, false, "profiling time alarm"); - AddSignal (28, "SIGWINCH", false, false, false, "window size changes"); - AddSignal (29, "SIGINFO", false, true , true , "information request"); - AddSignal (30, "SIGUSR1", false, true , true , "user defined signal 1"); - AddSignal (31, "SIGUSR2", false, true , true , "user defined signal 2"); +void UnixSignals::Reset() { + // This builds one standard set of Unix Signals. If yours aren't quite in + // this + // order, you can either subclass this class, and use Add & Remove to change + // them + // or you can subclass and build them afresh in your constructor; + // + // Note: the signals below are the Darwin signals. Do not change these! + m_signals.clear(); + // SIGNO NAME SUPPRESS STOP NOTIFY DESCRIPTION + // ====== ============ ======== ====== ====== + // =================================================== + AddSignal(1, "SIGHUP", false, true, true, "hangup"); + AddSignal(2, "SIGINT", true, true, true, "interrupt"); + AddSignal(3, "SIGQUIT", false, true, true, "quit"); + AddSignal(4, "SIGILL", false, true, true, "illegal instruction"); + AddSignal(5, "SIGTRAP", true, true, true, + "trace trap (not reset when caught)"); + AddSignal(6, "SIGABRT", false, true, true, "abort()"); + AddSignal(7, "SIGEMT", false, true, true, "pollable event"); + AddSignal(8, "SIGFPE", false, true, true, "floating point exception"); + AddSignal(9, "SIGKILL", false, true, true, "kill"); + AddSignal(10, "SIGBUS", false, true, true, "bus error"); + AddSignal(11, "SIGSEGV", false, true, true, "segmentation violation"); + AddSignal(12, "SIGSYS", false, true, true, "bad argument to system call"); + AddSignal(13, "SIGPIPE", false, true, true, + "write on a pipe with no one to read it"); + AddSignal(14, "SIGALRM", false, false, false, "alarm clock"); + AddSignal(15, "SIGTERM", false, true, true, + "software termination signal from kill"); + AddSignal(16, "SIGURG", false, false, false, + "urgent condition on IO channel"); + AddSignal(17, "SIGSTOP", true, true, true, + "sendable stop signal not from tty"); + AddSignal(18, "SIGTSTP", false, true, true, "stop signal from tty"); + AddSignal(19, "SIGCONT", false, true, true, "continue a stopped process"); + AddSignal(20, "SIGCHLD", false, false, false, + "to parent on child stop or exit"); + AddSignal(21, "SIGTTIN", false, true, true, + "to readers process group upon background tty read"); + AddSignal(22, "SIGTTOU", false, true, true, + "to readers process group upon background tty write"); + AddSignal(23, "SIGIO", false, false, false, "input/output possible signal"); + AddSignal(24, "SIGXCPU", false, true, true, "exceeded CPU time limit"); + AddSignal(25, "SIGXFSZ", false, true, true, "exceeded file size limit"); + AddSignal(26, "SIGVTALRM", false, false, false, "virtual time alarm"); + AddSignal(27, "SIGPROF", false, false, false, "profiling time alarm"); + AddSignal(28, "SIGWINCH", false, false, false, "window size changes"); + AddSignal(29, "SIGINFO", false, true, true, "information request"); + AddSignal(30, "SIGUSR1", false, true, true, "user defined signal 1"); + AddSignal(31, "SIGUSR2", false, true, true, "user defined signal 2"); } -void -UnixSignals::AddSignal(int signo, - const char *name, - bool default_suppress, - bool default_stop, - bool default_notify, - const char *description, - const char *alias) -{ - Signal new_signal (name, default_suppress, default_stop, default_notify, description, alias); - m_signals.insert (std::make_pair(signo, new_signal)); +void UnixSignals::AddSignal(int signo, const char *name, bool default_suppress, + bool default_stop, bool default_notify, + const char *description, const char *alias) { + Signal new_signal(name, default_suppress, default_stop, default_notify, + description, alias); + m_signals.insert(std::make_pair(signo, new_signal)); } -void -UnixSignals::RemoveSignal (int signo) -{ - collection::iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - m_signals.erase (pos); +void UnixSignals::RemoveSignal(int signo) { + collection::iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) + m_signals.erase(pos); } -const char * -UnixSignals::GetSignalAsCString (int signo) const -{ - collection::const_iterator pos = m_signals.find (signo); - if (pos == m_signals.end()) - return nullptr; - else - return pos->second.m_name.GetCString (); +const char *UnixSignals::GetSignalAsCString(int signo) const { + collection::const_iterator pos = m_signals.find(signo); + if (pos == m_signals.end()) + return nullptr; + else + return pos->second.m_name.GetCString(); } -bool -UnixSignals::SignalIsValid (int32_t signo) const -{ - return m_signals.find (signo) != m_signals.end(); +bool UnixSignals::SignalIsValid(int32_t signo) const { + return m_signals.find(signo) != m_signals.end(); } -ConstString -UnixSignals::GetShortName(ConstString name) const -{ - if (name) - { - const char* signame = name.AsCString(); - return ConstString(signame + 3); // Remove "SIG" from name - } - return name; +ConstString UnixSignals::GetShortName(ConstString name) const { + if (name) { + const char *signame = name.AsCString(); + return ConstString(signame + 3); // Remove "SIG" from name + } + return name; } -int32_t -UnixSignals::GetSignalNumberFromName (const char *name) const -{ - ConstString const_name (name); +int32_t UnixSignals::GetSignalNumberFromName(const char *name) const { + ConstString const_name(name); - collection::const_iterator pos, end = m_signals.end (); - for (pos = m_signals.begin (); pos != end; pos++) - { - if ((const_name == pos->second.m_name) || (const_name == pos->second.m_alias) || - (const_name == GetShortName(pos->second.m_name)) || (const_name == GetShortName(pos->second.m_alias))) - return pos->first; - } - - const int32_t signo = StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0); - if (signo != LLDB_INVALID_SIGNAL_NUMBER) - return signo; - return LLDB_INVALID_SIGNAL_NUMBER; + collection::const_iterator pos, end = m_signals.end(); + for (pos = m_signals.begin(); pos != end; pos++) { + if ((const_name == pos->second.m_name) || + (const_name == pos->second.m_alias) || + (const_name == GetShortName(pos->second.m_name)) || + (const_name == GetShortName(pos->second.m_alias))) + return pos->first; + } + + const int32_t signo = + StringConvert::ToSInt32(name, LLDB_INVALID_SIGNAL_NUMBER, 0); + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + return signo; + return LLDB_INVALID_SIGNAL_NUMBER; } -int32_t -UnixSignals::GetFirstSignalNumber () const -{ - if (m_signals.empty()) - return LLDB_INVALID_SIGNAL_NUMBER; +int32_t UnixSignals::GetFirstSignalNumber() const { + if (m_signals.empty()) + return LLDB_INVALID_SIGNAL_NUMBER; - return (*m_signals.begin ()).first; + return (*m_signals.begin()).first; } -int32_t -UnixSignals::GetNextSignalNumber (int32_t current_signal) const -{ - collection::const_iterator pos = m_signals.find (current_signal); - collection::const_iterator end = m_signals.end(); +int32_t UnixSignals::GetNextSignalNumber(int32_t current_signal) const { + collection::const_iterator pos = m_signals.find(current_signal); + collection::const_iterator end = m_signals.end(); + if (pos == end) + return LLDB_INVALID_SIGNAL_NUMBER; + else { + pos++; if (pos == end) - return LLDB_INVALID_SIGNAL_NUMBER; + return LLDB_INVALID_SIGNAL_NUMBER; else - { - pos++; - if (pos == end) - return LLDB_INVALID_SIGNAL_NUMBER; - else - return pos->first; - } + return pos->first; + } } -const char * -UnixSignals::GetSignalInfo(int32_t signo, - bool &should_suppress, - bool &should_stop, - bool &should_notify) const -{ - collection::const_iterator pos = m_signals.find (signo); - if (pos == m_signals.end()) - return nullptr; - else - { - const Signal &signal = pos->second; - should_suppress = signal.m_suppress; - should_stop = signal.m_stop; - should_notify = signal.m_notify; - return signal.m_name.AsCString(""); - } +const char *UnixSignals::GetSignalInfo(int32_t signo, bool &should_suppress, + bool &should_stop, + bool &should_notify) const { + collection::const_iterator pos = m_signals.find(signo); + if (pos == m_signals.end()) + return nullptr; + else { + const Signal &signal = pos->second; + should_suppress = signal.m_suppress; + should_stop = signal.m_stop; + should_notify = signal.m_notify; + return signal.m_name.AsCString(""); + } } -bool -UnixSignals::GetShouldSuppress (int signo) const -{ - collection::const_iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - return pos->second.m_suppress; - return false; +bool UnixSignals::GetShouldSuppress(int signo) const { + collection::const_iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) + return pos->second.m_suppress; + return false; } -bool -UnixSignals::SetShouldSuppress (int signo, bool value) -{ - collection::iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - { - pos->second.m_suppress = value; - return true; - } - return false; +bool UnixSignals::SetShouldSuppress(int signo, bool value) { + collection::iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) { + pos->second.m_suppress = value; + return true; + } + return false; } -bool -UnixSignals::SetShouldSuppress (const char *signal_name, bool value) -{ - const int32_t signo = GetSignalNumberFromName (signal_name); - if (signo != LLDB_INVALID_SIGNAL_NUMBER) - return SetShouldSuppress (signo, value); - return false; +bool UnixSignals::SetShouldSuppress(const char *signal_name, bool value) { + const int32_t signo = GetSignalNumberFromName(signal_name); + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + return SetShouldSuppress(signo, value); + return false; } -bool -UnixSignals::GetShouldStop (int signo) const -{ - collection::const_iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - return pos->second.m_stop; - return false; +bool UnixSignals::GetShouldStop(int signo) const { + collection::const_iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) + return pos->second.m_stop; + return false; } -bool -UnixSignals::SetShouldStop (int signo, bool value) -{ - collection::iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - { - pos->second.m_stop = value; - return true; - } - return false; +bool UnixSignals::SetShouldStop(int signo, bool value) { + collection::iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) { + pos->second.m_stop = value; + return true; + } + return false; } -bool -UnixSignals::SetShouldStop (const char *signal_name, bool value) -{ - const int32_t signo = GetSignalNumberFromName (signal_name); - if (signo != LLDB_INVALID_SIGNAL_NUMBER) - return SetShouldStop (signo, value); - return false; +bool UnixSignals::SetShouldStop(const char *signal_name, bool value) { + const int32_t signo = GetSignalNumberFromName(signal_name); + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + return SetShouldStop(signo, value); + return false; } -bool -UnixSignals::GetShouldNotify (int signo) const -{ - collection::const_iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - return pos->second.m_notify; - return false; +bool UnixSignals::GetShouldNotify(int signo) const { + collection::const_iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) + return pos->second.m_notify; + return false; } -bool -UnixSignals::SetShouldNotify (int signo, bool value) -{ - collection::iterator pos = m_signals.find (signo); - if (pos != m_signals.end()) - { - pos->second.m_notify = value; - return true; - } - return false; +bool UnixSignals::SetShouldNotify(int signo, bool value) { + collection::iterator pos = m_signals.find(signo); + if (pos != m_signals.end()) { + pos->second.m_notify = value; + return true; + } + return false; } -bool -UnixSignals::SetShouldNotify (const char *signal_name, bool value) -{ - const int32_t signo = GetSignalNumberFromName (signal_name); - if (signo != LLDB_INVALID_SIGNAL_NUMBER) - return SetShouldNotify (signo, value); - return false; +bool UnixSignals::SetShouldNotify(const char *signal_name, bool value) { + const int32_t signo = GetSignalNumberFromName(signal_name); + if (signo != LLDB_INVALID_SIGNAL_NUMBER) + return SetShouldNotify(signo, value); + return false; } -int32_t -UnixSignals::GetNumSignals() const -{ - return m_signals.size(); -} +int32_t UnixSignals::GetNumSignals() const { return m_signals.size(); } -int32_t -UnixSignals::GetSignalAtIndex(int32_t index) const -{ - if (index < 0 || m_signals.size() <= static_cast<size_t>(index)) - return LLDB_INVALID_SIGNAL_NUMBER; - auto it = m_signals.begin(); - std::advance(it, index); - return it->first; +int32_t UnixSignals::GetSignalAtIndex(int32_t index) const { + if (index < 0 || m_signals.size() <= static_cast<size_t>(index)) + return LLDB_INVALID_SIGNAL_NUMBER; + auto it = m_signals.begin(); + std::advance(it, index); + return it->first; } diff --git a/lldb/source/Target/UnwindAssembly.cpp b/lldb/source/Target/UnwindAssembly.cpp index 3dc44359901..3b2b7bf1702 100644 --- a/lldb/source/Target/UnwindAssembly.cpp +++ b/lldb/source/Target/UnwindAssembly.cpp @@ -11,33 +11,28 @@ // C++ Includes // Other libraries and framework includes // Project includes -#include "lldb/lldb-private.h" -#include "lldb/Core/PluginManager.h" -#include "lldb/Core/PluginInterface.h" #include "lldb/Target/UnwindAssembly.h" +#include "lldb/Core/PluginInterface.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/lldb-private.h" using namespace lldb; using namespace lldb_private; -UnwindAssemblySP -UnwindAssembly::FindPlugin (const ArchSpec &arch) -{ - UnwindAssemblyCreateInstance create_callback; +UnwindAssemblySP UnwindAssembly::FindPlugin(const ArchSpec &arch) { + UnwindAssemblyCreateInstance create_callback; - for (uint32_t idx = 0; - (create_callback = PluginManager::GetUnwindAssemblyCreateCallbackAtIndex(idx)) != nullptr; - ++idx) - { - UnwindAssemblySP assembly_profiler_ap (create_callback (arch)); - if (assembly_profiler_ap) - return assembly_profiler_ap; - } - return nullptr; + for (uint32_t idx = 0; + (create_callback = PluginManager::GetUnwindAssemblyCreateCallbackAtIndex( + idx)) != nullptr; + ++idx) { + UnwindAssemblySP assembly_profiler_ap(create_callback(arch)); + if (assembly_profiler_ap) + return assembly_profiler_ap; + } + return nullptr; } -UnwindAssembly::UnwindAssembly (const ArchSpec &arch) : - m_arch (arch) -{ -} +UnwindAssembly::UnwindAssembly(const ArchSpec &arch) : m_arch(arch) {} UnwindAssembly::~UnwindAssembly() = default; |