summaryrefslogtreecommitdiff
path: root/source/Target
diff options
context:
space:
mode:
authorEd Maste <emaste@FreeBSD.org>2014-11-25 21:00:58 +0000
committerEd Maste <emaste@FreeBSD.org>2014-11-25 21:00:58 +0000
commit0cac4ca3916ac24ab6139d03cbfd18db9e715bfe (patch)
treec94307da318be46e5aeea1a325c1e91749506e4f /source/Target
parent03b99097822ca3ac69252d9afae716a584ed56c4 (diff)
downloadsrc-test2-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.tar.gz
src-test2-0cac4ca3916ac24ab6139d03cbfd18db9e715bfe.zip
Notes
Diffstat (limited to 'source/Target')
-rw-r--r--source/Target/ABI.cpp34
-rw-r--r--source/Target/FileAction.cpp95
-rw-r--r--source/Target/JITLoader.cpp38
-rw-r--r--source/Target/JITLoaderList.cpp77
-rw-r--r--source/Target/LanguageRuntime.cpp12
-rw-r--r--source/Target/Memory.cpp36
-rw-r--r--source/Target/NativeRegisterContext.cpp470
-rw-r--r--source/Target/NativeRegisterContextRegisterInfo.cpp44
-rw-r--r--source/Target/ObjCLanguageRuntime.cpp23
-rw-r--r--source/Target/PathMappingList.cpp4
-rw-r--r--source/Target/Platform.cpp103
-rw-r--r--source/Target/Process.cpp1458
-rw-r--r--source/Target/ProcessInfo.cpp138
-rw-r--r--source/Target/ProcessLaunchInfo.cpp459
-rw-r--r--source/Target/Queue.cpp15
-rw-r--r--source/Target/QueueItem.cpp85
-rw-r--r--source/Target/RegisterContext.cpp4
-rw-r--r--source/Target/SectionLoadHistory.cpp19
-rw-r--r--source/Target/SectionLoadList.cpp31
-rw-r--r--source/Target/StackFrame.cpp15
-rw-r--r--source/Target/StackFrameList.cpp4
-rw-r--r--source/Target/StackID.cpp5
-rw-r--r--source/Target/StopInfo.cpp106
-rw-r--r--source/Target/Target.cpp127
-rw-r--r--source/Target/TargetList.cpp183
-rw-r--r--source/Target/Thread.cpp335
-rw-r--r--source/Target/ThreadList.cpp11
-rw-r--r--source/Target/ThreadPlan.cpp15
-rw-r--r--source/Target/ThreadPlanBase.cpp4
-rw-r--r--source/Target/ThreadPlanCallFunction.cpp97
-rw-r--r--source/Target/ThreadPlanCallUserExpression.cpp52
-rw-r--r--source/Target/ThreadPlanRunToAddress.cpp2
-rw-r--r--source/Target/ThreadPlanShouldStopHere.cpp142
-rw-r--r--source/Target/ThreadPlanStepInRange.cpp132
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp94
-rw-r--r--source/Target/ThreadPlanStepOut.cpp179
-rw-r--r--source/Target/ThreadPlanStepOverRange.cpp58
-rw-r--r--source/Target/ThreadPlanStepRange.cpp19
-rw-r--r--source/Target/ThreadPlanStepUntil.cpp2
-rw-r--r--source/Target/ThreadPlanTracer.cpp11
40 files changed, 3505 insertions, 1233 deletions
diff --git a/source/Target/ABI.cpp b/source/Target/ABI.cpp
index 06215221d961..e02f360680fb 100644
--- a/source/Target/ABI.cpp
+++ b/source/Target/ABI.cpp
@@ -51,7 +51,6 @@ ABI::~ABI()
{
}
-
bool
ABI::GetRegisterInfoByName (const ConstString &name, RegisterInfo &info)
{
@@ -172,4 +171,37 @@ ABI::GetReturnValueObject (Thread &thread,
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;
+
+ /* this is a dummy and will only be called if an ABI does not override this */
+
+ 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;
+}
diff --git a/source/Target/FileAction.cpp b/source/Target/FileAction.cpp
new file mode 100644
index 000000000000..18b039998bc7
--- /dev/null
+++ b/source/Target/FileAction.cpp
@@ -0,0 +1,95 @@
+//===-- FileAction.cpp ------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include <fcntl.h>
+
+#if defined(_WIN32)
+#include "lldb/Host/Windows/win32.h" // For O_NOCTTY
+#endif
+
+#include "lldb/Target/FileAction.h"
+
+using namespace lldb_private;
+
+//----------------------------------------------------------------------------
+// FileAction member functions
+//----------------------------------------------------------------------------
+
+FileAction::FileAction()
+ : m_action(eFileActionNone)
+ , m_fd(-1)
+ , m_arg(-1)
+ , m_path()
+{
+}
+
+void
+FileAction::Clear()
+{
+ m_action = eFileActionNone;
+ m_fd = -1;
+ m_arg = -1;
+ m_path.clear();
+}
+
+const char *
+FileAction::GetPath() const
+{
+ if (m_path.empty())
+ return NULL;
+ return m_path.c_str();
+}
+
+bool
+FileAction::Open(int fd, const char *path, bool read, bool write)
+{
+ if ((read || write) && fd >= 0 && path && path[0])
+ {
+ 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_path.assign(path);
+ 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::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;
+}
diff --git a/source/Target/JITLoader.cpp b/source/Target/JITLoader.cpp
new file mode 100644
index 000000000000..8536d690ece0
--- /dev/null
+++ b/source/Target/JITLoader.cpp
@@ -0,0 +1,38 @@
+//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/JITLoaderList.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+JITLoader::LoadPlugins (Process *process, JITLoaderList &list)
+{
+ JITLoaderCreateInstance create_callback = NULL;
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetJITLoaderCreateCallbackAtIndex(idx)) != NULL; ++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()
+{
+}
diff --git a/source/Target/JITLoaderList.cpp b/source/Target/JITLoaderList.cpp
new file mode 100644
index 000000000000..24a73b7fd516
--- /dev/null
+++ b/source/Target/JITLoaderList.cpp
@@ -0,0 +1,77 @@
+//===-- JITLoader.cpp -------------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/JITLoaderList.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+JITLoaderList::JITLoaderList()
+ : m_jit_loaders_vec(), m_jit_loaders_mutex(Mutex::eMutexTypeRecursive)
+{
+}
+
+JITLoaderList::~JITLoaderList()
+{
+}
+
+void
+JITLoaderList::Append (const JITLoaderSP &jit_loader_sp)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ m_jit_loaders_vec.push_back(jit_loader_sp);
+}
+
+void
+JITLoaderList::Remove (const JITLoaderSP &jit_loader_sp)
+{
+ Mutex::Locker locker(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();
+}
+
+JITLoaderSP
+JITLoaderList::GetLoaderAtIndex (size_t idx)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ return m_jit_loaders_vec[idx];
+}
+
+void
+JITLoaderList::DidLaunch()
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ for (auto const &jit_loader : m_jit_loaders_vec)
+ jit_loader->DidLaunch();
+}
+
+void
+JITLoaderList::DidAttach()
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ for (auto const &jit_loader : m_jit_loaders_vec)
+ jit_loader->DidAttach();
+}
+
+void
+JITLoaderList::ModulesDidLoad(ModuleList &module_list)
+{
+ Mutex::Locker locker(m_jit_loaders_mutex);
+ for (auto const &jit_loader : m_jit_loaders_vec)
+ jit_loader->ModulesDidLoad(module_list);
+}
diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp
index a2b7f1d6ae85..9d48d8b2de7f 100644
--- a/source/Target/LanguageRuntime.cpp
+++ b/source/Target/LanguageRuntime.cpp
@@ -307,6 +307,18 @@ struct language_name_pair language_names[] =
{ "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 },
// Now synonyms, in arbitrary order
{ "objc", eLanguageTypeObjC },
{ "objc++", eLanguageTypeObjC_plus_plus }
diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp
index 3c8d483f3003..b212fcd23a45 100644
--- a/source/Target/Memory.cpp
+++ b/source/Target/Memory.cpp
@@ -9,6 +9,7 @@
#include "lldb/Target/Memory.h"
// C Includes
+#include <inttypes.h>
// C++ Includes
// Other libraries and framework includes
// Project includes
@@ -119,6 +120,19 @@ MemoryCache::Read (addr_t addr,
Error &error)
{
size_t bytes_left = 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_cache_line_byte_size)
+ {
+ return m_process.ReadMemoryFromInferior (addr, dst, dst_len, error);
+ }
+
if (dst && bytes_left > 0)
{
const uint32_t cache_line_byte_size = m_cache_line_byte_size;
@@ -227,16 +241,16 @@ 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);
- Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (m_offset_to_chunk_size.empty())
{
m_offset_to_chunk_size[0] = needed_chunks;
if (log)
- log->Printf ("[1] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, 0, needed_chunks, m_chunk_size);
+ log->Printf ("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", this, size, size, 0, needed_chunks, m_chunk_size);
addr = m_addr;
}
else
@@ -254,7 +268,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[2] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
+ log->Printf ("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -270,7 +284,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[3] AllocatedBlock::ReserveBlock (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", size, size, last_offset, needed_chunks, m_chunk_size);
+ log->Printf ("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -329,9 +343,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)
// return m_addr + m_chunk_size * first_chunk_idx;
// }
}
- Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
+
if (log)
- log->Printf ("AllocatedBlock::ReserveBlock (size = %u (0x%x)) => 0x%16.16" PRIx64, size, size, (uint64_t)addr);
+ log->Printf ("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, this, size, size, (uint64_t)addr);
return addr;
}
@@ -348,7 +362,7 @@ AllocatedBlock::FreeBlock (addr_t addr)
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (log)
- log->Printf ("AllocatedBlock::FreeBlock (addr = 0x%16.16" PRIx64 ") => %i", (uint64_t)addr, success);
+ log->Printf ("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", this, (uint64_t)addr, success, m_offset_to_chunk_size.size());
return success;
}
@@ -395,8 +409,8 @@ AllocatedMemoryCache::AllocatePage (uint32_t byte_size,
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
{
- log->Printf ("Process::DoAllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64,
- page_byte_size,
+ 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);
}
@@ -422,6 +436,8 @@ AllocatedMemoryCache::AllocateMemory (size_t byte_size,
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)
@@ -433,7 +449,7 @@ AllocatedMemoryCache::AllocateMemory (size_t byte_size,
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("AllocatedMemoryCache::AllocateMemory (byte_size = 0x%8.8zx, permissions = %s) => 0x%16.16" PRIx64, byte_size, GetPermissionsAsCString(permissions), (uint64_t)addr);
+ 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;
}
diff --git a/source/Target/NativeRegisterContext.cpp b/source/Target/NativeRegisterContext.cpp
new file mode 100644
index 000000000000..d84e2279a459
--- /dev/null
+++ b/source/Target/NativeRegisterContext.cpp
@@ -0,0 +1,470 @@
+//===-- NativeRegisterContext.cpp -------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/NativeRegisterContext.h"
+
+#include "lldb/Core/Log.h"
+#include "lldb/Core/RegisterValue.h"
+
+#include "lldb/lldb-private-log.h"
+
+#include "Host/common/NativeProcessProtocol.h"
+#include "Host/common/NativeThreadProtocol.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+NativeRegisterContext::NativeRegisterContext (NativeThreadProtocol &thread, uint32_t concrete_frame_idx) :
+ m_thread (thread),
+ m_concrete_frame_idx (concrete_frame_idx)
+{
+}
+
+//----------------------------------------------------------------------
+// Destructor
+//----------------------------------------------------------------------
+NativeRegisterContext::~NativeRegisterContext()
+{
+}
+
+// FIXME revisit invalidation, process stop ids, etc. Right now we don't
+// support caching in NativeRegisterContext. We can do this later by
+// utilizing NativeProcessProtocol::GetStopID () and adding a stop id to
+// NativeRegisterContext.
+
+// void
+// NativeRegisterContext::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);
+// }
+// }
+
+
+const RegisterInfo *
+NativeRegisterContext::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;
+}
+
+const RegisterInfo *
+NativeRegisterContext::GetRegisterInfo (uint32_t 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 *
+NativeRegisterContext::GetRegisterName (uint32_t reg)
+{
+ const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return nullptr;
+}
+
+const char*
+NativeRegisterContext::GetRegisterSetNameForRegisterAtIndex (uint32_t reg_index) const
+{
+ const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
+ if (!reg_info)
+ return nullptr;
+
+ for (uint32_t set_index = 0; set_index < GetRegisterSetCount (); ++set_index)
+ {
+ const RegisterSet *const reg_set = GetRegisterSet (set_index);
+ if (!reg_set)
+ continue;
+
+ for (uint32_t reg_num_index = 0; reg_num_index < reg_set->num_registers; ++reg_num_index)
+ {
+ const uint32_t reg_num = reg_set->registers[reg_num_index];
+ // FIXME double check we're checking the right register kind here.
+ if (reg_info->kinds[RegisterKind::eRegisterKindLLDB] == reg_num)
+ {
+ // The given register is a member of this register set. Return the register set name.
+ return reg_set->name;
+ }
+ }
+ }
+
+ // Didn't find it.
+ return nullptr;
+}
+
+lldb::addr_t
+NativeRegisterContext::GetPC (lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ if (log)
+ log->Printf ("NativeRegisterContext::%s using reg index %" PRIu32 " (default %" PRIu64 ")", __FUNCTION__, reg, fail_value);
+
+ const uint64_t retval = ReadRegisterAsUnsigned (reg, fail_value);
+
+ if (log)
+ log->Printf ("NativeRegisterContext::%s " PRIu32 " retval %" PRIu64, __FUNCTION__, retval);
+
+ return retval;
+}
+
+Error
+NativeRegisterContext::SetPC (lldb::addr_t pc)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
+ return WriteRegisterFromUnsigned (reg, pc);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetSP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetSP (lldb::addr_t sp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned (reg, sp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFP (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+Error
+NativeRegisterContext::SetFP (lldb::addr_t fp)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned (reg, fp);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetReturnAddress (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+lldb::addr_t
+NativeRegisterContext::GetFlags (lldb::addr_t fail_value)
+{
+ uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned (reg, fail_value);
+}
+
+
+lldb::addr_t
+NativeRegisterContext::ReadRegisterAsUnsigned (uint32_t reg, lldb::addr_t fail_value)
+{
+ if (reg != LLDB_INVALID_REGNUM)
+ return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
+ return fail_value;
+}
+
+uint64_t
+NativeRegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, lldb::addr_t fail_value)
+{
+ Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+
+ if (reg_info)
+ {
+ RegisterValue value;
+ Error error = ReadRegister (reg_info, value);
+ if (error.Success ())
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() succeeded, value %" PRIu64, __FUNCTION__, value.GetAsUInt64());
+ return value.GetAsUInt64();
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() failed, error %s", __FUNCTION__, error.AsCString ());
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("NativeRegisterContext::%s ReadRegister() null reg_info", __FUNCTION__);
+ }
+ return fail_value;
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
+{
+ if (reg == LLDB_INVALID_REGNUM)
+ return Error ("NativeRegisterContext::%s (): reg is invalid", __FUNCTION__);
+ return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
+}
+
+Error
+NativeRegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
+{
+ assert (reg_info);
+ if (!reg_info)
+ return Error ("reg_info is nullptr");
+
+ RegisterValue value;
+ if (!value.SetUInt(uval, reg_info->byte_size))
+ return Error ("RegisterValue::SetUInt () failed");
+
+ return WriteRegister (reg_info, value);
+}
+
+lldb::tid_t
+NativeRegisterContext::GetThreadID() const
+{
+ return m_thread.GetID();
+}
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareBreakpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
+{
+ return false;
+}
+
+
+uint32_t
+NativeRegisterContext::NumSupportedHardwareWatchpoints ()
+{
+ return 0;
+}
+
+uint32_t
+NativeRegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, uint32_t watch_flags)
+{
+ return LLDB_INVALID_INDEX32;
+}
+
+bool
+NativeRegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
+{
+ return false;
+}
+
+bool
+NativeRegisterContext::HardwareSingleStep (bool enable)
+{
+ return false;
+}
+
+Error
+NativeRegisterContext::ReadRegisterValueFromMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t src_addr,
+ lldb::addr_t src_len,
+ RegisterValue &reg_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 lldb::addr_t dst_len = reg_info->byte_size;
+
+ if (src_len > dst_len)
+ {
+ error.SetErrorStringWithFormat("%" PRIu64 " bytes is too big to store in register %s (%" PRIu64 " bytes)", src_len, reg_info->name, dst_len);
+ return error;
+ }
+
+ NativeProcessProtocolSP process_sp (m_thread.GetProcess ());
+ if (!process_sp)
+ {
+ error.SetErrorString("invalid process");
+ return error;
+ }
+
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Read the memory
+ lldb::addr_t bytes_read;
+ error = process_sp->ReadMemory (src_addr, src, src_len, bytes_read);
+ if (error.Fail ())
+ return error;
+
+ // Make sure the memory read succeeded...
+ if (bytes_read != src_len)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("read %" PRIu64 " of %" PRIu64 " 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.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ {
+ error.SetErrorString ( "NativeProcessProtocol::GetByteOrder () failed");
+ return error;
+ }
+
+ reg_value.SetFromMemoryData (
+ reg_info,
+ src,
+ src_len,
+ byte_order,
+ error);
+
+ return error;
+}
+
+Error
+NativeRegisterContext::WriteRegisterValueToMemory (
+ const RegisterInfo *reg_info,
+ lldb::addr_t dst_addr,
+ lldb::addr_t dst_len,
+ const RegisterValue &reg_value)
+{
+
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ Error error;
+
+ NativeProcessProtocolSP 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.
+ lldb::ByteOrder byte_order;
+ if (!process_sp->GetByteOrder (byte_order))
+ return Error ("NativeProcessProtocol::GetByteOrder () failed");
+
+ const lldb::addr_t bytes_copied = reg_value.GetAsMemoryData (
+ reg_info,
+ dst,
+ dst_len,
+ byte_order,
+ error);
+
+ if (error.Success())
+ {
+ if (bytes_copied == 0)
+ {
+ error.SetErrorString("byte copy failed.");
+ }
+ else
+ {
+ lldb::addr_t bytes_written;
+ error = process_sp->WriteMemory (dst_addr, dst, bytes_copied, bytes_written);
+ if (error.Fail ())
+ return error;
+
+ if (bytes_written != bytes_copied)
+ {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %" PRIu64 " of %" PRIu64 " bytes", bytes_written, bytes_copied);
+ }
+ }
+ }
+ }
+ else
+ error.SetErrorString("invalid process");
+
+ return error;
+}
+
+uint32_t
+NativeRegisterContext::ConvertRegisterKindToRegisterNumber (uint32_t kind, uint32_t num) const
+{
+ const uint32_t num_regs = GetRegisterCount();
+
+ assert (kind < kNumRegisterKinds);
+ for (uint32_t reg_idx = 0; reg_idx < num_regs; ++reg_idx)
+ {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex (reg_idx);
+
+ if (reg_info->kinds[kind] == num)
+ return reg_idx;
+ }
+
+ return LLDB_INVALID_REGNUM;
+}
+
+
diff --git a/source/Target/NativeRegisterContextRegisterInfo.cpp b/source/Target/NativeRegisterContextRegisterInfo.cpp
new file mode 100644
index 000000000000..e37014546646
--- /dev/null
+++ b/source/Target/NativeRegisterContextRegisterInfo.cpp
@@ -0,0 +1,44 @@
+//===-- NativeRegisterContex.cpp --------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/lldb-types.h"
+#include "lldb/lldb-private-forward.h"
+#include "lldb/Target/NativeRegisterContextRegisterInfo.h"
+
+using namespace lldb_private;
+
+NativeRegisterContextRegisterInfo::NativeRegisterContextRegisterInfo (NativeThreadProtocol &thread,
+ uint32_t concrete_frame_idx,
+ RegisterInfoInterface *register_info_interface) :
+ NativeRegisterContext (thread, concrete_frame_idx),
+ m_register_info_interface_up (register_info_interface)
+{
+ assert (register_info_interface && "null register_info_interface");
+}
+
+uint32_t
+NativeRegisterContextRegisterInfo::GetRegisterCount () const
+{
+ return m_register_info_interface_up->GetRegisterCount ();
+}
+
+const RegisterInfo *
+NativeRegisterContextRegisterInfo::GetRegisterInfoAtIndex (uint32_t reg_index) const
+{
+ if (reg_index <= GetRegisterCount ())
+ return m_register_info_interface_up->GetRegisterInfo () + reg_index;
+ else
+ return nullptr;
+}
+
+const RegisterInfoInterface&
+NativeRegisterContextRegisterInfo::GetRegisterInfoInterface () const
+{
+ return *m_register_info_interface_up;
+}
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index 64ddfcc6c796..1f2abd876c84 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -602,4 +602,27 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
}
+ClangASTType
+ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool allow_unknownanytype)
+{
+ if (m_scratch_ast_ctx_ap)
+ return RealizeType(*m_scratch_ast_ctx_ap, name, allow_unknownanytype);
+ return ClangASTType();
+}
+
+ClangASTType
+ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype)
+{
+ clang::ASTContext *clang_ast = ast_ctx.getASTContext();
+ if (!clang_ast)
+ return ClangASTType();
+ return RealizeType(*clang_ast, name, allow_unknownanytype);
+}
+
+ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
+ObjCLanguageRuntime::EncodingToTypeSP
+ObjCLanguageRuntime::GetEncodingToType ()
+{
+ return nullptr;
+}
diff --git a/source/Target/PathMappingList.cpp b/source/Target/PathMappingList.cpp
index db23a0b27130..2fd517829b8c 100644
--- a/source/Target/PathMappingList.cpp
+++ b/source/Target/PathMappingList.cpp
@@ -132,7 +132,7 @@ PathMappingList::Replace (const ConstString &path,
}
bool
-PathMappingList::Remove (off_t index, bool notify)
+PathMappingList::Remove (size_t index, bool notify)
{
if (index >= m_pairs.size())
return false;
@@ -161,7 +161,7 @@ PathMappingList::Dump (Stream *s, int pair_index)
}
else
{
- if (pair_index < numPairs)
+ if (static_cast<unsigned int>(pair_index) < numPairs)
s->Printf("%s -> %s",
m_pairs[pair_index].first.GetCString(), m_pairs[pair_index].second.GetCString());
}
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp
index d6010fb22a5b..fe73be2d05b9 100644
--- a/source/Target/Platform.cpp
+++ b/source/Target/Platform.cpp
@@ -19,7 +19,9 @@
#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Host/FileSpec.h"
+#include "lldb/Host/FileSystem.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/Target.h"
#include "lldb/Utility/Utils.h"
@@ -91,7 +93,7 @@ Platform::GetFileWithUUID (const FileSpec &platform_file,
}
FileSpecList
-Platform::LocateExecutableScriptingResources (Target *target, Module &module)
+Platform::LocateExecutableScriptingResources (Target *target, Module &module, Stream* feedback_stream)
{
return FileSpecList();
}
@@ -257,11 +259,12 @@ Platform::Platform (bool is_host) :
m_ssh_opts (),
m_ignores_remote_hostname (false),
m_trap_handlers(),
- m_calculated_trap_handlers (false)
+ m_calculated_trap_handlers (false),
+ m_trap_handler_mutex()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Platform::Platform()", this);
+ log->Printf ("%p Platform::Platform()", static_cast<void*>(this));
}
//------------------------------------------------------------------
@@ -274,7 +277,7 @@ Platform::~Platform()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Platform::~Platform()", this);
+ log->Printf ("%p Platform::~Platform()", static_cast<void*>(this));
}
void
@@ -347,9 +350,7 @@ Platform::GetOSVersion (uint32_t &major,
if (!success)
{
// We have a local host platform
- success = Host::GetOSVersion (m_major_os_version,
- m_minor_os_version,
- m_update_os_version);
+ success = HostInfo::GetOSVersion(m_major_os_version, m_minor_os_version, m_update_os_version);
m_os_version_set_while_connected = success;
}
}
@@ -396,8 +397,14 @@ Platform::GetOSVersion (uint32_t &major,
bool
Platform::GetOSBuildString (std::string &s)
{
+ s.clear();
+
if (IsHost())
- return Host::GetOSBuildString (s);
+#if !defined(__linux__)
+ return HostInfo::GetOSBuildString(s);
+#else
+ return false;
+#endif
else
return GetRemoteOSBuildString (s);
}
@@ -406,7 +413,11 @@ bool
Platform::GetOSKernelDescription (std::string &s)
{
if (IsHost())
- return Host::GetOSKernelDescription (s);
+#if !defined(__linux__)
+ return HostInfo::GetOSKernelDescription(s);
+#else
+ return false;
+#endif
else
return GetRemoteOSKernelDescription (s);
}
@@ -493,8 +504,8 @@ RecurseCopy_Callback (void *baton,
dst_file.GetFilename() = src.GetFilename();
char buf[PATH_MAX];
-
- rc_baton->error = Host::Readlink (src.GetPath().c_str(), buf, sizeof(buf));
+
+ rc_baton->error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
if (rc_baton->error.Fail())
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
@@ -526,6 +537,7 @@ RecurseCopy_Callback (void *baton,
case FileSpec::eFileTypeInvalid:
case FileSpec::eFileTypeOther:
case FileSpec::eFileTypeUnknown:
+ default:
rc_baton->error.SetErrorStringWithFormat("invalid file detected during copy: %s", src.GetPath().c_str());
return FileSpec::eEnumerateDirectoryResultQuit; // got an error, bail out
break;
@@ -647,7 +659,7 @@ Platform::Install (const FileSpec& src, const FileSpec& dst)
if (GetFileExists (fixed_dst))
Unlink (fixed_dst.GetPath().c_str());
char buf[PATH_MAX];
- error = Host::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
+ error = FileSystem::Readlink(src.GetPath().c_str(), buf, sizeof(buf));
if (error.Success())
error = CreateSymlink(dst.GetPath().c_str(), buf);
}
@@ -699,7 +711,7 @@ Error
Platform::MakeDirectory (const char *path, uint32_t permissions)
{
if (IsHost())
- return Host::MakeDirectory (path, permissions);
+ return FileSystem::MakeDirectory(path, permissions);
else
{
Error error;
@@ -712,7 +724,7 @@ Error
Platform::GetFilePermissions (const char *path, uint32_t &file_permissions)
{
if (IsHost())
- return Host::GetFilePermissions(path, file_permissions);
+ return FileSystem::GetFilePermissions(path, file_permissions);
else
{
Error error;
@@ -725,7 +737,7 @@ Error
Platform::SetFilePermissions (const char *path, uint32_t file_permissions)
{
if (IsHost())
- return Host::SetFilePermissions(path, file_permissions);
+ return FileSystem::SetFilePermissions(path, file_permissions);
else
{
Error error;
@@ -744,7 +756,7 @@ const char *
Platform::GetHostname ()
{
if (IsHost())
- return "localhost";
+ return "127.0.0.1";
if (m_name.empty())
return NULL;
@@ -764,30 +776,34 @@ Platform::SetRemoteWorkingDirectory(const ConstString &path)
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 (Host::GetUserName(uid, name))
+ if (HostInfo::LookupUserName(uid, name))
return SetCachedUserName (uid, name.c_str(), name.size());
}
+#endif
return NULL;
}
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 (Host::GetGroupName(gid, name))
+ if (HostInfo::LookupGroupName(gid, name))
return SetCachedGroupName (gid, name.c_str(), name.size());
}
+#endif
return NULL;
}
@@ -798,8 +814,8 @@ Platform::SetOSVersion (uint32_t major,
{
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 Host::GetOSVersion(...).
+ // 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
@@ -902,7 +918,7 @@ Platform::GetSystemArchitecture()
if (!m_system_arch.IsValid())
{
// We have a local host platform
- m_system_arch = Host::GetArchitecture();
+ m_system_arch = HostInfo::GetArchitecture();
m_system_arch_set_while_connected = m_system_arch.IsValid();
}
}
@@ -1180,11 +1196,32 @@ Platform::CalculateMD5 (const FileSpec& file_spec,
uint64_t &high)
{
if (IsHost())
- return Host::CalculateMD5(file_spec, low, high);
+ return FileSystem::CalculateMD5(file_spec, low, high);
else
return false;
}
+Error
+Platform::LaunchNativeProcess (
+ ProcessLaunchInfo &launch_info,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+ // Platforms should override this implementation if they want to
+ // support lldb-gdbserver.
+ return Error("unimplemented");
+}
+
+Error
+Platform::AttachNativeProcess (lldb::pid_t pid,
+ lldb_private::NativeProcessProtocol::NativeDelegate &native_delegate,
+ NativeProcessProtocolSP &process_sp)
+{
+ // Platforms should override this implementation if they want to
+ // support lldb-gdbserver.
+ return Error("unimplemented");
+}
+
void
Platform::SetLocalCacheDirectory (const char* local)
{
@@ -1200,23 +1237,23 @@ Platform::GetLocalCacheDirectory ()
static OptionDefinition
g_rsync_option_table[] =
{
- { LLDB_OPT_SET_ALL, false, "rsync" , 'r', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Enable rsync." },
- { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." },
- { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." },
- { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument, NULL, 0, eArgTypeNone , "Do not automatically fill in the remote hostname when composing the rsync command." },
+ { LLDB_OPT_SET_ALL, false, "rsync" , 'r', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Enable rsync." },
+ { LLDB_OPT_SET_ALL, false, "rsync-opts" , 'R', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific options required for rsync to work." },
+ { LLDB_OPT_SET_ALL, false, "rsync-prefix" , 'P', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeCommandName , "Platform-specific rsync prefix put before the remote path." },
+ { LLDB_OPT_SET_ALL, false, "ignore-remote-hostname" , 'i', OptionParser::eNoArgument, NULL, NULL, 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, NULL, 0, eArgTypeNone , "Enable SSH." },
- { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', OptionParser::eRequiredArgument, NULL, 0, eArgTypeCommandName , "Platform-specific options required for SSH to work." },
+ { LLDB_OPT_SET_ALL, false, "ssh" , 's', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone , "Enable SSH." },
+ { LLDB_OPT_SET_ALL, false, "ssh-opts" , 'S', OptionParser::eRequiredArgument, NULL, NULL, 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, NULL, 0, eArgTypePath , "Path in which to store local copies of files." },
+ { LLDB_OPT_SET_ALL, false, "local-cache-dir" , 'c', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePath , "Path in which to store local copies of files." },
};
OptionGroupPlatformRSync::OptionGroupPlatformRSync ()
@@ -1398,8 +1435,12 @@ Platform::GetTrapHandlerSymbolNames ()
{
if (!m_calculated_trap_handlers)
{
- CalculateTrapHandlerSymbolNames();
- m_calculated_trap_handlers = true;
+ Mutex::Locker locker (m_trap_handler_mutex);
+ if (!m_calculated_trap_handlers)
+ {
+ CalculateTrapHandlerSymbolNames();
+ m_calculated_trap_handlers = true;
+ }
}
return m_trap_handlers;
}
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index 1256ad34c975..a1049787d821 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -27,9 +27,11 @@
#include "lldb/Expression/ClangUserExpression.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/Pipe.h"
#include "lldb/Host/Terminal.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/JITLoader.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -45,10 +47,6 @@
#include "lldb/Target/ThreadPlanBase.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
-#ifndef LLDB_DISABLE_POSIX
-#include <spawn.h>
-#endif
-
using namespace lldb;
using namespace lldb_private;
@@ -82,7 +80,7 @@ public:
virtual const Property *
GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
- // When gettings the value for a key from the process options, we will always
+ // 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)
@@ -321,8 +319,8 @@ ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_a
}
else
{
- s.Printf ("PID PARENT USER ARCH %s\n", label);
- s.PutCString ("====== ====== ========== ======= ============================\n");
+ s.Printf ("PID PARENT USER TRIPLE %s\n", label);
+ s.PutCString ("====== ====== ========== ======================== ============================\n");
}
}
@@ -364,10 +362,9 @@ ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_ar
}
else
{
- s.Printf ("%-10s %-7d %s ",
+ s.Printf ("%-10s %-24s ",
platform->GetUserName (m_euid),
- (int)m_arch.GetTriple().getArchName().size(),
- m_arch.GetTriple().getArchName().data());
+ m_arch.IsValid() ? m_arch.GetTriple().str().c_str() : "");
}
if (verbose || show_args)
@@ -392,361 +389,6 @@ ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_ar
}
}
-
-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
-ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
-{
- // If notthing was specified, then check the process for any default
- // settings that were set with "settings set"
- if (m_file_actions.empty())
- {
- if (m_flags.Test(eLaunchFlagDisableSTDIO))
- {
- 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_path;
- FileSpec out_path;
- FileSpec err_path;
- if (target)
- {
- in_path = target->GetStandardInputPath();
- out_path = target->GetStandardOutputPath();
- err_path = target->GetStandardErrorPath();
- }
-
- if (in_path || out_path || err_path)
- {
- char path[PATH_MAX];
- if (in_path && in_path.GetPath(path, sizeof(path)))
- AppendOpenFileAction(STDIN_FILENO, path, true, false);
-
- if (out_path && out_path.GetPath(path, sizeof(path)))
- AppendOpenFileAction(STDOUT_FILENO, path, false, true);
-
- if (err_path && err_path.GetPath(path, sizeof(path)))
- AppendOpenFileAction(STDERR_FILENO, path, false, true);
- }
- else if (default_to_use_pty)
- {
- if (m_pty.OpenFirstAvailableMaster (O_RDWR|O_NOCTTY, NULL, 0))
- {
- const char *slave_path = m_pty.GetSlaveName (NULL, 0);
- AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
- AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
- AppendOpenFileAction(STDERR_FILENO, slave_path, 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))
- {
- const char *shell_executable = GetShell();
- if (shell_executable)
- {
- char shell_resolved_path[PATH_MAX];
-
- if (localhost)
- {
- FileSpec shell_filespec (shell_executable, true);
-
- if (!shell_filespec.Exists())
- {
- // Resolve the path in case we just got "bash", "sh" or "tcsh"
- if (!shell_filespec.ResolveExecutableLocation ())
- {
- error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
- return false;
- }
- }
- shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
- shell_executable = shell_resolved_path;
- }
-
- const char **argv = GetArguments().GetConstArgumentVector ();
- if (argv == NULL || argv[0] == NULL)
- return false;
- Args shell_arguments;
- std::string safe_arg;
- shell_arguments.AppendArgument (shell_executable);
- 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];
- if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
- {
- // 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")
- const char *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 && working_dir[0])
- {
- new_path += working_dir;
- }
- 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;
- }
- const char *curr_path = getenv("PATH");
- if (curr_path)
- {
- if (new_path.size() > empty_path_len)
- new_path += ':';
- new_path += curr_path;
- }
- new_path += "\" ";
- shell_command.PutCString(new_path.c_str());
- }
-
- shell_command.PutCString ("exec");
-
- // Only Apple supports /usr/bin/arch being able to specify the architecture
- if (GetArchitecture().IsValid())
- {
- 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] != NULL; ++i)
- {
- const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
- shell_command.Printf(" %s", arg);
- }
- }
- shell_arguments.AppendArgument (shell_command.GetString().c_str());
- m_executable.SetFile(shell_executable, false);
- m_arguments = shell_arguments;
- return true;
- }
- else
- {
- error.SetErrorString ("invalid shell path");
- }
- }
- else
- {
- error.SetErrorString ("not launching in shell");
- }
- return false;
-}
-
-
-bool
-ProcessLaunchInfo::FileAction::Open (int fd, const char *path, bool read, bool write)
-{
- if ((read || write) && fd >= 0 && path && path[0])
- {
- 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_path.assign (path);
- return true;
- }
- else
- {
- Clear();
- }
- return false;
-}
-
-bool
-ProcessLaunchInfo::FileAction::Close (int fd)
-{
- Clear();
- if (fd >= 0)
- {
- m_action = eFileActionClose;
- m_fd = fd;
- }
- return m_fd >= 0;
-}
-
-
-bool
-ProcessLaunchInfo::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;
-}
-
-
-
-#ifndef LLDB_DISABLE_POSIX
-bool
-ProcessLaunchInfo::FileAction::AddPosixSpawnFileAction (void *_file_actions,
- const FileAction *info,
- Log *log,
- Error& error)
-{
- if (info == NULL)
- return false;
-
- posix_spawn_file_actions_t *file_actions = reinterpret_cast<posix_spawn_file_actions_t *>(_file_actions);
-
- switch (info->m_action)
- {
- case eFileActionNone:
- error.Clear();
- break;
-
- case eFileActionClose:
- if (info->m_fd == -1)
- error.SetErrorString ("invalid fd for posix_spawn_file_actions_addclose(...)");
- else
- {
- error.SetError (::posix_spawn_file_actions_addclose (file_actions, info->m_fd),
- eErrorTypePOSIX);
- if (log && (error.Fail() || log))
- error.PutToLog(log, "posix_spawn_file_actions_addclose (action=%p, fd=%i)",
- file_actions, info->m_fd);
- }
- break;
-
- case eFileActionDuplicate:
- if (info->m_fd == -1)
- error.SetErrorString ("invalid fd for posix_spawn_file_actions_adddup2(...)");
- else if (info->m_arg == -1)
- error.SetErrorString ("invalid duplicate fd for posix_spawn_file_actions_adddup2(...)");
- else
- {
- error.SetError (::posix_spawn_file_actions_adddup2 (file_actions, info->m_fd, info->m_arg),
- eErrorTypePOSIX);
- if (log && (error.Fail() || log))
- error.PutToLog(log, "posix_spawn_file_actions_adddup2 (action=%p, fd=%i, dup_fd=%i)",
- file_actions, info->m_fd, info->m_arg);
- }
- break;
-
- case eFileActionOpen:
- if (info->m_fd == -1)
- error.SetErrorString ("invalid fd in posix_spawn_file_actions_addopen(...)");
- else
- {
- int oflag = info->m_arg;
-
- mode_t mode = 0;
-
- if (oflag & O_CREAT)
- mode = 0640;
-
- error.SetError (::posix_spawn_file_actions_addopen (file_actions,
- info->m_fd,
- info->m_path.c_str(),
- oflag,
- mode),
- eErrorTypePOSIX);
- if (error.Fail() || log)
- error.PutToLog(log,
- "posix_spawn_file_actions_addopen (action=%p, fd=%i, path='%s', oflag=%i, mode=%i)",
- file_actions, info->m_fd, info->m_path.c_str(), oflag, mode);
- }
- break;
- }
- return error.Success();
-}
-#endif
-
Error
ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *option_arg)
{
@@ -760,45 +402,44 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
break;
case 'i': // STDIN for read only
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDIN_FILENO, option_arg, true, false))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDIN_FILENO, option_arg, true, false))
+ launch_info.AppendFileAction (action);
break;
+ }
case 'o': // Open STDOUT for write only
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDOUT_FILENO, option_arg, false, true))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDOUT_FILENO, option_arg, false, true))
+ launch_info.AppendFileAction (action);
break;
+ }
case 'e': // STDERR for write only
- {
- ProcessLaunchInfo::FileAction action;
- if (action.Open (STDERR_FILENO, option_arg, false, true))
- launch_info.AppendFileAction (action);
- }
+ {
+ FileAction action;
+ if (action.Open (STDERR_FILENO, option_arg, false, true))
+ launch_info.AppendFileAction (action);
break;
-
+ }
case 'p': // Process plug-in name
launch_info.SetProcessPluginName (option_arg);
break;
case 'n': // Disable STDIO
- {
- ProcessLaunchInfo::FileAction action;
- 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);
- }
+ {
+ FileAction action;
+ 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 (option_arg);
@@ -813,11 +454,18 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
launch_info.GetArchitecture().SetTriple (option_arg);
break;
- case 'A':
- launch_info.GetFlags().Set (eLaunchFlagDisableASLR);
+ 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 'c':
+ }
+
+ case 'c':
if (option_arg && option_arg[0])
launch_info.SetShell (option_arg);
else
@@ -831,7 +479,6 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
default:
error.SetErrorStringWithFormat("unrecognized short option character '%c'", short_option);
break;
-
}
return error;
}
@@ -839,23 +486,23 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
OptionDefinition
ProcessLaunchCommandOptions::g_option_table[] =
{
-{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
-{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Disable address space layout randomization when launching a process."},
-{ LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
-{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
-{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."},
-{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, NULL, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."},
-{ LLDB_OPT_SET_ALL, false, "shell", 'c', OptionParser::eOptionalArgument, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
+{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process."},
+{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeBoolean, "Set whether to disable address space layout randomization when launching a process."},
+{ LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypePlugin, "Name of the process plugin you want to use."},
+{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
+{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."},
+{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."},
+{ LLDB_OPT_SET_ALL, false, "shell", 'c', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
-{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>."},
-{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>."},
-{ LLDB_OPT_SET_1 , false, "stderr", 'e', OptionParser::eRequiredArgument, NULL, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>."},
+{ LLDB_OPT_SET_1 , false, "stderr", 'e', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>."},
-{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."},
+{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."},
-{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
+{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process."},
-{ 0 , false, NULL, 0, 0, NULL, 0, eArgTypeNone, NULL }
+{ 0 , false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -1006,6 +653,13 @@ Process::GetStaticBroadcasterClass ()
// Process constructor
//----------------------------------------------------------------------
Process::Process(Target &target, Listener &listener) :
+ Process(target, listener, Host::GetUnixSignals ())
+{
+ // This constructor just delegates to the full Process constructor,
+ // defaulting to using the Host's UnixSignals.
+}
+
+Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :
ProcessProperties (false),
UserID (LLDB_INVALID_PROCESS_ID),
Broadcaster (&(target.GetDebugger()), "lldb.process"),
@@ -1035,7 +689,7 @@ Process::Process(Target &target, Listener &listener) :
m_listener (listener),
m_breakpoint_site_list (),
m_dynamic_checkers_ap (),
- m_unix_signals (),
+ m_unix_signals_sp (unix_signals_sp),
m_abi_sp (),
m_process_input_reader (),
m_stdio_communication ("process.stdio"),
@@ -1044,6 +698,7 @@ Process::Process(Target &target, Listener &listener) :
m_stderr_data (),
m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
m_profile_data (),
+ m_iohandler_sync (false),
m_memory_cache (*this),
m_allocated_memory_cache (*this),
m_should_detach (false),
@@ -1062,7 +717,10 @@ Process::Process(Target &target, Listener &listener) :
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Process::Process()", this);
+ log->Printf ("%p Process::Process()", static_cast<void*>(this));
+
+ if (!m_unix_signals_sp)
+ m_unix_signals_sp.reset (new UnixSignals ());
SetEventName (eBroadcastBitStateChanged, "state-changed");
SetEventName (eBroadcastBitInterrupt, "interrupt");
@@ -1089,6 +747,8 @@ Process::Process(Target &target, Listener &listener) :
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");
}
//----------------------------------------------------------------------
@@ -1098,7 +758,7 @@ Process::~Process()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Process::~Process()", this);
+ log->Printf ("%p Process::~Process()", static_cast<void*>(this));
StopPrivateStateThread();
}
@@ -1154,6 +814,7 @@ Process::Finalize()
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();
@@ -1241,6 +902,34 @@ Process::GetNextEvent (EventSP &event_sp)
return state;
}
+bool
+Process::SyncIOHandler (uint64_t timeout_msec)
+{
+ bool timed_out = false;
+
+ // don't sync (potentially context switch) in case where there is no process IO
+ if (m_process_input_reader)
+ {
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+
+ m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out);
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if(log)
+ {
+ if(timed_out)
+ log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec);
+ else
+ log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
+ }
+
+ // reset sync one-shot so it will be ready for next time
+ m_iohandler_sync.SetValue(false, eBroadcastNever);
+ }
+
+ return !timed_out;
+}
StateType
Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener)
@@ -1258,7 +947,8 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p)", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p)", __FUNCTION__,
+ static_cast<const void*>(timeout));
if (!wait_always &&
StateIsStoppedState(state, true) &&
@@ -1375,12 +1065,13 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp,
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__,
+ static_cast<const void*>(timeout));
Listener *listener = hijack_listener;
if (listener == NULL)
listener = &m_listener;
-
+
StateType state = eStateInvalid;
if (listener->WaitForEventForBroadcasterWithType (timeout,
this,
@@ -1395,8 +1086,7 @@ Process::WaitForStateChangedEvents (const TimeValue *timeout, EventSP &event_sp,
if (log)
log->Printf ("Process::%s (timeout = %p, event_sp) => %s",
- __FUNCTION__,
- timeout,
+ __FUNCTION__, static_cast<const void*>(timeout),
StateAsCString(state));
return state;
}
@@ -1435,7 +1125,8 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__,
+ static_cast<const void*>(timeout));
StateType state = eStateInvalid;
if (m_private_state_listener.WaitForEventForBroadcasterWithType (timeout,
@@ -1449,12 +1140,9 @@ Process::WaitForStateChangedEventsPrivate (const TimeValue *timeout, EventSP &ev
// to the command-line, and that could disable the log, which would render the
// log we got above invalid.
if (log)
- {
- if (state == eStateInvalid)
- log->Printf ("Process::%s (timeout = %p, event_sp) => TIMEOUT", __FUNCTION__, timeout);
- else
- log->Printf ("Process::%s (timeout = %p, event_sp) => %s", __FUNCTION__, timeout, StateAsCString(state));
- }
+ log->Printf ("Process::%s (timeout = %p, event_sp) => %s",
+ __FUNCTION__, static_cast<const void *>(timeout),
+ state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));
return state;
}
@@ -1464,7 +1152,8 @@ Process::WaitForEventsPrivate (const TimeValue *timeout, EventSP &event_sp, bool
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__, timeout);
+ log->Printf ("Process::%s (timeout = %p, event_sp)...", __FUNCTION__,
+ static_cast<const void*>(timeout));
if (control_only)
return m_private_state_listener.WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp);
@@ -1523,12 +1212,11 @@ Process::SetExitStatus (int status, const char *cstr)
DidExit ();
SetPrivateState (eStateExited);
- CancelWatchForSTDIN (true);
return true;
}
// This static callback can be used to watch for local child processes on
-// the current host. The the child process exits, the process will be
+// 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
@@ -1766,6 +1454,9 @@ Process::GetPrivateState ()
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;
@@ -1874,9 +1565,27 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
expr_options.SetUnwindOnError(true);
expr_options.SetIgnoreBreakpoints(true);
expr_options.SetExecutionPolicy(eExecutionPolicyAlways);
+ expr_options.SetResultIsInternal(true);
+
StreamString expr;
- expr.Printf("dlopen (\"%s\", 2)", path);
- const char *prefix = "extern \"C\" void* dlopen (const char *path, int mode);\n";
+ expr.Printf(R"(
+ struct __lldb_dlopen_result { void *image_ptr; const char *error_str; } the_result;
+ the_result.image_ptr = dlopen ("%s", 2);
+ if (the_result.image_ptr == (void *) 0x0)
+ {
+ the_result.error_str = dlerror();
+ }
+ else
+ {
+ the_result.error_str = (const char *) 0x0;
+ }
+ the_result;
+ )",
+ path);
+ const char *prefix = R"(
+ extern "C" void* dlopen (const char *path, int mode);
+ extern "C" const char *dlerror (void);
+ )";
lldb::ValueObjectSP result_valobj_sp;
Error expr_error;
ClangUserExpression::Evaluate (exe_ctx,
@@ -1891,7 +1600,8 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
if (error.Success())
{
Scalar scalar;
- if (result_valobj_sp->ResolveValue (scalar))
+ ValueObjectSP image_ptr_sp = result_valobj_sp->GetChildAtIndex(0, true);
+ if (image_ptr_sp && image_ptr_sp->ResolveValue (scalar))
{
addr_t image_ptr = scalar.ULongLong(LLDB_INVALID_ADDRESS);
if (image_ptr != 0 && image_ptr != LLDB_INVALID_ADDRESS)
@@ -1900,9 +1610,28 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
m_image_tokens.push_back (image_ptr);
return image_token;
}
+ else if (image_ptr == 0)
+ {
+ ValueObjectSP error_str_sp = result_valobj_sp->GetChildAtIndex(1, true);
+ if (error_str_sp)
+ {
+ if (error_str_sp->IsCStringContainer(true))
+ {
+ StreamString s;
+ size_t num_chars = error_str_sp->ReadPointedString (s, error);
+ if (error.Success() && num_chars > 0)
+ {
+ error.Clear();
+ error.SetErrorStringWithFormat("dlopen error: %s", s.GetData());
+ }
+ }
+ }
+ }
}
}
}
+ else
+ error = expr_error;
}
}
}
@@ -2169,7 +1898,7 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
symbol->GetAddress().GetLoadAddress(&m_target),
owner->GetBreakpoint().GetID(),
owner->GetID(),
- error.AsCString() ? error.AsCString() : "unkown error");
+ error.AsCString() ? error.AsCString() : "unknown error");
return LLDB_INVALID_BREAK_ID;
}
Address resolved_address(load_addr);
@@ -2217,7 +1946,7 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
load_addr,
owner->GetBreakpoint().GetID(),
owner->GetID(),
- error.AsCString() ? error.AsCString() : "unkown error");
+ error.AsCString() ? error.AsCString() : "unknown error");
}
}
}
@@ -2379,7 +2108,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes();
if (break_op_size > 0)
{
- // Clear a software breakoint instruction
+ // Clear a software breakpoint instruction
uint8_t curr_break_op[8];
assert (break_op_size <= sizeof(curr_break_op));
bool break_op_found = false;
@@ -2881,6 +2610,7 @@ Process::CanJIT ()
{
if (m_can_jit == eCanJITDontKnow)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
Error err;
uint64_t allocated_memory = AllocateMemory(8,
@@ -2888,9 +2618,17 @@ Process::CanJIT ()
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);
}
@@ -2930,13 +2668,14 @@ Process::DeallocateMemory (addr_t ptr)
ModuleSP
Process::ReadModuleFromMemory (const FileSpec& file_spec,
- lldb::addr_t header_addr)
+ lldb::addr_t header_addr,
+ size_t size_to_read)
{
ModuleSP module_sp (new Module (file_spec, ArchSpec()));
if (module_sp)
{
Error error;
- ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error);
+ ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error, size_to_read);
if (objfile)
return module_sp;
}
@@ -2989,6 +2728,7 @@ 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();
@@ -3065,6 +2805,8 @@ Process::Launch (ProcessLaunchInfo &launch_info)
if (dyld)
dyld->DidLaunch();
+ GetJITLoaders().DidLaunch();
+
SystemRuntime *system_runtime = GetSystemRuntime ();
if (system_runtime)
system_runtime->DidLaunch();
@@ -3111,6 +2853,8 @@ Process::LoadCore ()
DynamicLoader *dyld = GetDynamicLoader ();
if (dyld)
dyld->DidAttach();
+
+ GetJITLoaders().DidAttach();
SystemRuntime *system_runtime = GetSystemRuntime ();
if (system_runtime)
@@ -3134,6 +2878,23 @@ Process::GetDynamicLoader ()
return m_dyld_ap.get();
}
+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;
+}
+
SystemRuntime *
Process::GetSystemRuntime ()
{
@@ -3142,12 +2903,25 @@ Process::GetSystemRuntime ()
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::NextEventAction::EventActionResult
Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
StateType state = ProcessEventData::GetStateFromEvent (event_sp.get());
- switch (state)
+ if (log)
+ log->Printf ("Process::AttachCompletionHandler::%s called with state %s (%d)", __FUNCTION__, StateAsCString(state), static_cast<int> (state));
+
+ switch (state)
{
case eStateRunning:
case eStateConnected:
@@ -3165,11 +2939,18 @@ Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
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);
+
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));
+
m_process->CompleteAttach ();
return eEventActionSuccess;
}
@@ -3204,6 +2985,7 @@ 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();
@@ -3276,7 +3058,17 @@ Process::Attach (ProcessAttachInfo &attach_info)
{
match_info.GetProcessInfo().GetExecutableFile().GetPath (process_name, sizeof(process_name));
if (num_matches > 1)
- error.SetErrorStringWithFormat ("more than one process named %s", process_name);
+ {
+ 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);
}
@@ -3340,9 +3132,26 @@ Process::Attach (ProcessAttachInfo &attach_info)
void
Process::CompleteAttach ()
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ 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.
- DidAttach();
+ ArchSpec process_arch;
+ DidAttach(process_arch);
+
+ if (process_arch.IsValid())
+ {
+ m_target.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.
@@ -3359,15 +3168,21 @@ Process::CompleteAttach ()
{
m_target.SetPlatform (platform_sp);
m_target.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 ());
}
}
- else
+ else if (!process_arch.IsValid())
{
ProcessInstanceInfo process_info;
platform_sp->GetProcessInfo (GetID(), process_info);
const ArchSpec &process_arch = process_info.GetArchitecture();
if (process_arch.IsValid() && !m_target.GetArchitecture().IsExactMatch(process_arch))
+ {
m_target.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 ());
+ }
}
}
@@ -3375,11 +3190,33 @@ Process::CompleteAttach ()
// plug-in
DynamicLoader *dyld = GetDynamicLoader ();
if (dyld)
+ {
dyld->DidAttach();
+ if (log)
+ {
+ ModuleSP exe_module_sp = m_target.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 = m_target.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, NULL));
// Figure out which one is the executable, and set that in our target:
@@ -3399,7 +3236,16 @@ Process::CompleteAttach ()
}
}
if (new_executable_module_sp)
+ {
m_target.SetExecutableModule (new_executable_module_sp, false);
+ if (log)
+ {
+ ModuleSP exe_module_sp = m_target.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>");
+ }
+ }
}
Error
@@ -3520,6 +3366,7 @@ Process::Halt (bool clear_thread_plans)
EventSP event_sp;
Error error (WillHalt());
+ bool restored_process_events = false;
if (error.Success())
{
@@ -3531,6 +3378,10 @@ Process::Halt (bool clear_thread_plans)
{
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...
+ RestorePrivateProcessEvents();
+ restored_process_events = true;
SetExitStatus(SIGKILL, "Cancelled async attach.");
Destroy ();
}
@@ -3547,7 +3398,7 @@ Process::Halt (bool clear_thread_plans)
// Wait for 1 second for the process to stop.
TimeValue timeout_time;
timeout_time = TimeValue::Now();
- timeout_time.OffsetWithSeconds(1);
+ timeout_time.OffsetWithSeconds(10);
bool got_event = halt_listener.WaitForEvent (&timeout_time, event_sp);
StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
@@ -3579,7 +3430,8 @@ Process::Halt (bool clear_thread_plans)
}
}
// Resume our private state thread before we post the event (if any)
- RestorePrivateProcessEvents();
+ if (!restored_process_events)
+ RestorePrivateProcessEvents();
// Post any event we might have consumed. If all goes well, we will have
// stopped the process, intercepted the event and set the interrupted
@@ -3671,6 +3523,9 @@ Process::Detach (bool keep_stopped)
}
}
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+
error = DoDetach(keep_stopped);
if (error.Success())
{
@@ -3738,9 +3593,14 @@ Process::Destroy ()
}
m_stdio_communication.StopReadThread();
m_stdio_communication.Disconnect();
+
if (m_process_input_reader)
+ {
+ m_process_input_reader->SetIsDone(true);
+ m_process_input_reader->Cancel();
m_process_input_reader.reset();
-
+ }
+
// 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)
@@ -3831,7 +3691,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
break;
default:
// TODO: make this work correctly. For now always report
- // run if we aren't running so we don't miss any runnning
+ // 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
@@ -3866,32 +3726,33 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
{
if (log)
log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s",
- event_ptr,
+ 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) == false;
-
+
if (was_restarted || should_resume || m_resume_requested)
{
Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);
if (log)
log->Printf ("Process::ShouldBroadcastEvent: should_stop: %i state: %s was_restarted: %i stop_vote: %d.",
- should_resume,
- StateAsCString(state),
- was_restarted,
- stop_vote);
-
+ should_resume, StateAsCString(state),
+ was_restarted, stop_vote);
+
switch (stop_vote)
{
case eVoteYes:
@@ -3902,15 +3763,17 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
return_value = false;
break;
}
-
+
if (!was_restarted)
{
if (log)
- log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s", event_ptr, StateAsCString(state));
+ log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s",
+ static_cast<void*>(event_ptr),
+ StateAsCString(state));
ProcessEventData::SetRestartedInEvent(event_ptr, true);
PrivateResume ();
}
-
+
}
else
{
@@ -3921,7 +3784,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
}
break;
}
-
+
// Forcing the next event delivery is a one shot deal. So reset it here.
m_force_next_event_delivery = false;
@@ -3931,14 +3794,13 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
// 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",
- event_ptr,
- StateAsCString(state),
+ static_cast<void*>(event_ptr), StateAsCString(state),
StateAsCString(m_last_broadcast_state),
return_value ? "YES" : "NO");
return return_value;
@@ -3960,11 +3822,23 @@ Process::StartPrivateStateThread (bool force)
// 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 (already_running)
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
+
+ if (Host::MAX_THREAD_NAME_LENGTH <= 16)
+ {
+ // 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
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
-
+ {
+ 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.
m_private_state_thread = Host::ThreadCreate (thread_name, Process::PrivateStateThread, this, NULL);
bool success = IS_VALID_LLDB_HOST_THREAD(m_private_state_thread);
@@ -4116,6 +3990,7 @@ Process::HandlePrivateEvent (EventSP &event_sp)
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",
@@ -4123,7 +3998,7 @@ Process::HandlePrivateEvent (EventSP &event_sp)
GetID(),
StateAsCString(new_state),
StateAsCString (GetState ()),
- IsHijackedForEvent(eBroadcastBitStateChanged) ? "hijacked" : "public");
+ is_hijacked ? "hijacked" : "public");
}
Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
if (StateIsRunningState (new_state))
@@ -4132,9 +4007,46 @@ Process::HandlePrivateEvent (EventSP &event_sp)
// as this means the curses GUI is in use...
if (!GetTarget().GetDebugger().IsForwardingEvents())
PushProcessIOHandler ();
+ m_iohandler_sync.SetValue(true, eBroadcastAlways);
+ }
+ else if (StateIsStoppedState(new_state, false))
+ {
+ m_iohandler_sync.SetValue(false, eBroadcastNever);
+ 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 || m_target.GetDebugger().IsHandlingEvents() == false)
+ PopProcessIOHandler ();
+ }
}
- else if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
- PopProcessIOHandler ();
BroadcastEvent (event_sp);
}
@@ -4168,7 +4080,8 @@ Process::RunPrivateStateThread ()
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...",
+ __FUNCTION__, static_cast<void*>(this), GetID());
bool exit_now = false;
while (!exit_now)
@@ -4178,13 +4091,15 @@ Process::RunPrivateStateThread ()
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__, this, GetID(), event_sp->GetType());
+ 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 managment below
+ break; // doing any internal state management below
case eBroadcastInternalStateControlPause:
control_only = true;
@@ -4194,7 +4109,7 @@ Process::RunPrivateStateThread ()
control_only = false;
break;
}
-
+
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
continue;
}
@@ -4203,13 +4118,17 @@ Process::RunPrivateStateThread ()
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__, this, GetID());
+ 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, NULL);
}
else
{
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.",
+ __FUNCTION__, static_cast<void*>(this),
+ GetID());
Halt();
}
continue;
@@ -4233,7 +4152,9 @@ Process::RunPrivateStateThread ()
internal_state == eStateDetached )
{
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...", __FUNCTION__, this, GetID(), StateAsCString(internal_state));
+ 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;
}
@@ -4241,7 +4162,8 @@ Process::RunPrivateStateThread ()
// Verify log is still enabled before attempting to write to it...
if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...", __FUNCTION__, this, GetID());
+ log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...",
+ __FUNCTION__, static_cast<void*>(this), GetID());
m_public_run_lock.SetStopped();
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
@@ -4303,8 +4225,14 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
return;
m_process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
-
- // If we're stopped and haven't restarted, then do the breakpoint commands here:
+
+ // 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)
{
ThreadList &curr_thread_list = m_process_sp->GetThreadList();
@@ -4418,7 +4346,8 @@ void
Process::ProcessEventData::Dump (Stream *s) const
{
if (m_process_sp)
- s->Printf(" process = %p (pid = %" PRIu64 "), ", m_process_sp.get(), m_process_sp->GetID());
+ s->Printf(" process = %p (pid = %" PRIu64 "), ",
+ static_cast<void*>(m_process_sp.get()), m_process_sp->GetID());
s->Printf("state = %s", StateAsCString(GetState()));
}
@@ -4601,7 +4530,9 @@ Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ 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);
@@ -4631,7 +4562,9 @@ Process::GetSTDOUT (char *buf, size_t buf_size, Error &error)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ 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);
@@ -4657,7 +4590,9 @@ Process::GetSTDERR (char *buf, size_t buf_size, Error &error)
{
Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")", buf, (uint64_t)buf_size);
+ 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);
@@ -4680,13 +4615,6 @@ Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_
process->AppendSTDOUT (static_cast<const char *>(src), src_len);
}
-void
-Process::ResetProcessIOHandler ()
-{
- m_process_input_reader.reset();
-}
-
-
class IOHandlerProcessSTDIO :
public IOHandler
{
@@ -4697,8 +4625,7 @@ public:
m_process (process),
m_read_file (),
m_write_file (write_fd, false),
- m_pipe_read(),
- m_pipe_write()
+ m_pipe ()
{
m_read_file.SetDescriptor(GetInputFD(), false);
}
@@ -4712,30 +4639,15 @@ public:
bool
OpenPipes ()
{
- if (m_pipe_read.IsValid() && m_pipe_write.IsValid())
+ if (m_pipe.IsValid())
return true;
-
- int fds[2];
-#ifdef _MSC_VER
- // pipe is not supported on windows so default to a fail condition
- int err = 1;
-#else
- int err = pipe(fds);
-#endif
- if (err == 0)
- {
- m_pipe_read.SetDescriptor(fds[0], true);
- m_pipe_write.SetDescriptor(fds[1], true);
- return true;
- }
- return false;
+ return m_pipe.Open();
}
void
ClosePipes()
{
- m_pipe_read.Close();
- m_pipe_write.Close();
+ m_pipe.Close();
}
// Each IOHandler gets to run until it is done. It should read data
@@ -4750,14 +4662,14 @@ public:
if (OpenPipes())
{
const int read_fd = m_read_file.GetDescriptor();
- const int pipe_read_fd = m_pipe_read.GetDescriptor();
+ const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
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 _MSC_VER
+#ifndef _WIN32
while (!GetIsDone())
{
fd_set read_fdset;
@@ -4791,9 +4703,19 @@ public:
if (FD_ISSET (pipe_read_fd, &read_fdset))
{
// Consume the interrupt byte
- n = 1;
- m_pipe_read.Read (&ch, n);
- SetIsDone(true);
+ if (m_pipe.Read (&ch, 1) == 1)
+ {
+ switch (ch)
+ {
+ case 'q':
+ SetIsDone(true);
+ break;
+ case 'i':
+ if (StateIsRunningState(m_process->GetState()))
+ m_process->Halt();
+ break;
+ }
+ }
}
}
}
@@ -4828,16 +4750,40 @@ public:
virtual void
Cancel ()
{
- size_t n = 1;
- char ch = 'q';
- m_pipe_write.Write (&ch, n);
+ char ch = 'q'; // Send 'q' for quit
+ m_pipe.Write (&ch, 1);
}
- virtual void
+ virtual bool
Interrupt ()
{
- if (StateIsRunningState(m_process->GetState()))
- m_process->SendAsyncInterrupt();
+ // 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->Halt() from a
+ // much safer location in code.
+ if (m_active)
+ {
+ char ch = 'i'; // Send 'i' for interrupt
+ return m_pipe.Write (&ch, 1) == 1;
+ }
+ 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;
}
virtual void
@@ -4850,28 +4796,10 @@ 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)
- File m_pipe_read;
- File m_pipe_write;
-
+ Pipe m_pipe;
};
void
-Process::WatchForSTDIN (IOHandler &io_handler)
-{
-}
-
-void
-Process::CancelWatchForSTDIN (bool exited)
-{
- if (m_process_input_reader)
- {
- if (exited)
- m_process_input_reader->SetIsDone(true);
- m_process_input_reader->Cancel();
- }
-}
-
-void
Process::SetSTDIOFileDescriptor (int fd)
{
// First set up the Read Thread for reading/handling process I/O
@@ -4894,7 +4822,15 @@ Process::SetSTDIOFileDescriptor (int fd)
}
}
-void
+bool
+Process::ProcessIOHandlerIsActive ()
+{
+ IOHandlerSP io_handler_sp (m_process_input_reader);
+ if (io_handler_sp)
+ return m_target.GetDebugger().IsTopIOHandler (io_handler_sp);
+ return false;
+}
+bool
Process::PushProcessIOHandler ()
{
IOHandlerSP io_handler_sp (m_process_input_reader);
@@ -4902,18 +4838,18 @@ Process::PushProcessIOHandler ()
{
io_handler_sp->SetIsDone(false);
m_target.GetDebugger().PushIOHandler (io_handler_sp);
+ return true;
}
+ return false;
}
-void
+bool
Process::PopProcessIOHandler ()
{
IOHandlerSP io_handler_sp (m_process_input_reader);
if (io_handler_sp)
- {
- io_handler_sp->Cancel();
- m_target.GetDebugger().PopIOHandler (io_handler_sp);
- }
+ return m_target.GetDebugger().PopIOHandler (io_handler_sp);
+ return false;
}
// The process needs to know about installed plug-ins
@@ -4929,52 +4865,52 @@ Process::SettingsTerminate ()
Thread::SettingsTerminate ();
}
-ExecutionResults
+ExpressionResults
Process::RunThreadPlan (ExecutionContext &exe_ctx,
lldb::ThreadPlanSP &thread_plan_sp,
const EvaluateExpressionOptions &options,
Stream &errors)
{
- ExecutionResults return_value = eExecutionSetupError;
-
+ ExpressionResults return_value = eExpressionSetupError;
+
if (thread_plan_sp.get() == NULL)
{
errors.Printf("RunThreadPlan called with empty thread plan.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
if (!thread_plan_sp->ValidatePlan(NULL))
{
errors.Printf ("RunThreadPlan called with an invalid thread plan.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
if (exe_ctx.GetProcessPtr() != this)
{
errors.Printf("RunThreadPlan called on wrong process.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
Thread *thread = exe_ctx.GetThreadPtr();
if (thread == NULL)
{
errors.Printf("RunThreadPlan called with invalid thread.");
- return eExecutionSetupError;
+ return eExpressionSetupError;
}
-
+
// 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.
-
+
bool orig_plan_private = thread_plan_sp->GetPrivate();
thread_plan_sp->SetPrivate(false);
-
+
if (m_private_state.GetValue() != eStateStopped)
{
errors.Printf ("RunThreadPlan called while the private state was not stopped.");
- return eExecutionSetupError;
+ 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();
@@ -4985,17 +4921,17 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (!selected_frame_sp)
{
errors.Printf("RunThreadPlan called without a selected frame on thread %d", thread_idx_id);
- return eExecutionSetupError;
+ 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)
@@ -5021,7 +4957,6 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// 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;
@@ -5036,13 +4971,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// 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.
@@ -5051,22 +4986,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// is only cosmetic, and this functionality is only of use to lldb developers who can
// live with not pretty...
thread->Flush();
- return eExecutionStoppedForDebug;
+ return eExpressionStoppedForDebug;
}
-
+
Listener listener("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);
-
+
if (log)
{
StreamString s;
@@ -5076,66 +5011,114 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
thread->GetID(),
s.GetData());
}
-
+
bool got_event;
lldb::EventSP event_sp;
lldb::StateType stop_state = lldb::eStateInvalid;
-
+
TimeValue* timeout_ptr = NULL;
TimeValue real_timeout;
-
+
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;
- TimeValue one_thread_timeout = TimeValue::Now();
- TimeValue final_timeout = one_thread_timeout;
+ // 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.
- uint32_t timeout_usec = options.GetTimeoutUsec();
- if (options.GetTryAllThreads())
+ if (!options.GetStopOthers() || !options.GetTryAllThreads())
{
- // If we are running all threads then we take half the time to run all threads, bounded by
- // .25 sec.
- if (options.GetTimeoutUsec() == 0)
- one_thread_timeout.OffsetWithMicroSeconds(default_one_thread_timeout_usec);
- else
- {
- uint64_t computed_timeout = timeout_usec / 2;
- if (computed_timeout > default_one_thread_timeout_usec)
- computed_timeout = default_one_thread_timeout_usec;
- one_thread_timeout.OffsetWithMicroSeconds(computed_timeout);
- }
- final_timeout.OffsetWithMicroSeconds (timeout_usec);
+ before_first_timeout = false;
+ one_thread_timeout_usec = 0;
+ all_threads_timeout_usec = timeout_usec;
}
else
{
- if (timeout_usec != 0)
- final_timeout.OffsetWithMicroSeconds(timeout_usec);
+ 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)
+ {
+ errors.Printf("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.PeekAtNextEvent();
if (other_events != NULL)
{
errors.Printf("Calling RunThreadPlan with pending events on the queue.");
- return eExecutionSetupError;
+ 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.
+#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;
+
+
while (1)
{
// We usually want to resume the process if we get to the top of the loop.
@@ -5146,11 +5129,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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++;
@@ -5160,14 +5143,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
errors.Printf("Error resuming inferior the %d time: \"%s\".\n",
num_resumes,
resume_error.AsCString());
- return_value = eExecutionSetupError;
+ return_value = eExpressionSetupError;
break;
}
}
-
+
TimeValue resume_timeout = TimeValue::Now();
resume_timeout.OffsetWithMicroSeconds(500000);
-
+
got_event = listener.WaitForEvent(&resume_timeout, event_sp);
if (!got_event)
{
@@ -5176,16 +5159,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
num_resumes);
errors.Printf("Didn't get any event after resume %d, exiting.", num_resumes);
- return_value = eExecutionSetupError;
+ 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());
@@ -5198,20 +5181,20 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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.
Halt();
}
-
+
errors.Printf("Didn't get running event after initial resume, got %s instead.",
StateAsCString(stop_state));
- return_value = eExecutionSetupError;
+ 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.
@@ -5225,17 +5208,25 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (log)
log->PutCString ("Process::RunThreadPlan(): waiting for next event.");
}
-
+
if (before_first_timeout)
{
if (options.GetTryAllThreads())
+ {
+ one_thread_timeout = TimeValue::Now();
+ one_thread_timeout.OffsetWithMicroSeconds(one_thread_timeout_usec);
timeout_ptr = &one_thread_timeout;
+ }
else
{
if (timeout_usec == 0)
timeout_ptr = NULL;
else
+ {
+ final_timeout = TimeValue::Now();
+ final_timeout.OffsetWithMicroSeconds (timeout_usec);
timeout_ptr = &final_timeout;
+ }
}
}
else
@@ -5243,12 +5234,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (timeout_usec == 0)
timeout_ptr = NULL;
else
+ {
+ final_timeout = TimeValue::Now();
+ final_timeout.OffsetWithMicroSeconds (all_threads_timeout_usec);
timeout_ptr = &final_timeout;
+ }
}
-
+
do_resume = true;
handle_running_event = true;
-
+
// Now wait for the process to stop again:
event_sp.reset();
@@ -5266,8 +5261,18 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
+#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.WaitForEvent (timeout_ptr, event_sp);
-
+
if (got_event)
{
if (event_sp.get())
@@ -5276,7 +5281,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
if (event_sp->GetType() == eBroadcastBitInterrupt)
{
Halt();
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
errors.Printf ("Execution halted by user interrupt.");
if (log)
log->Printf ("Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting.");
@@ -5287,7 +5292,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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:
@@ -5299,7 +5304,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// 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 = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
}
else
{
@@ -5313,17 +5318,15 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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)
@@ -5334,7 +5337,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// after this point.
if (thread_plan_sp)
thread_plan_sp->SetPrivate (orig_plan_private);
- return_value = eExecutionCompleted;
+ return_value = eExpressionCompleted;
}
else
{
@@ -5343,7 +5346,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription());
- return_value = eExecutionHitBreakpoint;
+ return_value = eExpressionHitBreakpoint;
if (!options.DoesIgnoreBreakpoints())
{
event_to_broadcast_sp = event_sp;
@@ -5355,7 +5358,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
if (!options.DoesUnwindOnError())
event_to_broadcast_sp = event_sp;
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
}
}
}
@@ -5374,16 +5377,16 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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;
-
+
errors.Printf ("Execution stopped with unexpected state.\n");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
break;
}
}
-
+
if (keep_going)
continue;
else
@@ -5393,7 +5396,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString ("Process::RunThreadPlan(): got_event was true, but the event pointer was null. How odd...");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
break;
}
}
@@ -5402,15 +5405,24 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// 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())
{
- uint64_t remaining_time = final_timeout - TimeValue::Now();
if (before_first_timeout)
- log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
- "running till for %" PRIu64 " usec with all threads enabled.",
- remaining_time);
+ {
+ 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.",
@@ -5421,13 +5433,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
"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;
@@ -5445,12 +5457,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString ("Process::RunThreadPlan(): Halt succeeded.");
-
+
real_timeout = TimeValue::Now();
real_timeout.OffsetWithMicroSeconds(500000);
got_event = listener.WaitForEvent(&real_timeout, event_sp);
-
+
if (got_event)
{
stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
@@ -5461,22 +5473,22 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
&& 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 = eExecutionCompleted;
+ return_value = eExpressionCompleted;
back_to_top = false;
break;
}
-
+
if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
{
if (log)
@@ -5491,11 +5503,11 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
- return_value = eExecutionInterrupted;
+ 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;
@@ -5512,7 +5524,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
// Running all threads failed, so return Interrupted.
if (log)
log->PutCString("Process::RunThreadPlan(): running all threads timed out.");
- return_value = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
back_to_top = false;
break;
}
@@ -5522,7 +5534,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{ 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 = eExecutionInterrupted;
+ return_value = eExpressionInterrupted;
back_to_top = false;
break;
}
@@ -5533,14 +5545,14 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
continue;
}
}
-
+
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 (IS_VALID_LLDB_HOST_THREAD(backup_private_state_thread))
{
@@ -5554,23 +5566,23 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
m_public_state.SetValueNoLock(old_state);
}
-
+
// 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 == eExecutionInterrupted && options.DoesUnwindOnError())
- || (return_value == eExecutionHitBreakpoint && options.DoesIgnoreBreakpoints());
-
- if (return_value == eExecutionCompleted
+ 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 == eExecutionInterrupted || return_value == eExecutionHitBreakpoint)
+ if (return_value == eExpressionInterrupted || return_value == eExpressionHitBreakpoint)
{
if (log)
{
@@ -5585,7 +5597,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
StreamString ts;
const char *event_explanation = NULL;
-
+
do
{
if (!event_sp)
@@ -5607,7 +5619,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
event_explanation = "<no event data>";
break;
}
-
+
Process *process = event_data->GetProcessSP().get();
if (!process)
@@ -5615,34 +5627,34 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
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] ");
-
+
lldb::StopInfoSP stop_info_sp = thread->GetStopInfo();
if (stop_info_sp)
{
@@ -5652,35 +5664,37 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
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 (should_unwind)
{
if (log)
- log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.", thread_plan_sp.get());
+ log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.",
+ static_cast<void*>(thread_plan_sp.get()));
thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
thread_plan_sp->SetPrivate (orig_plan_private);
}
else
{
if (log)
- log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.", thread_plan_sp.get());
+ log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.",
+ static_cast<void*>(thread_plan_sp.get()));
}
}
- else if (return_value == eExecutionSetupError)
+ else if (return_value == eExpressionSetupError)
{
if (log)
log->PutCString("Process::RunThreadPlan(): execution set up error.");
-
+
if (options.DoesUnwindOnError())
{
thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
@@ -5693,13 +5707,13 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
if (log)
log->PutCString("Process::RunThreadPlan(): thread plan is done");
- return_value = eExecutionCompleted;
+ return_value = eExpressionCompleted;
}
else if (thread->WasThreadPlanDiscarded (thread_plan_sp.get()))
{
if (log)
log->PutCString("Process::RunThreadPlan(): thread plan was discarded");
- return_value = eExecutionDiscarded;
+ return_value = eExpressionDiscarded;
}
else
{
@@ -5714,7 +5728,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
}
-
+
// 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.
@@ -5723,10 +5737,10 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
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())
@@ -5739,46 +5753,52 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
}
}
}
-
+
// 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);
}
-
+
return return_value;
}
const char *
-Process::ExecutionResultAsCString (ExecutionResults result)
+Process::ExecutionResultAsCString (ExpressionResults result)
{
const char *result_name;
switch (result)
{
- case eExecutionCompleted:
- result_name = "eExecutionCompleted";
+ case eExpressionCompleted:
+ result_name = "eExpressionCompleted";
break;
- case eExecutionDiscarded:
- result_name = "eExecutionDiscarded";
+ case eExpressionDiscarded:
+ result_name = "eExpressionDiscarded";
break;
- case eExecutionInterrupted:
- result_name = "eExecutionInterrupted";
+ case eExpressionInterrupted:
+ result_name = "eExpressionInterrupted";
break;
- case eExecutionHitBreakpoint:
- result_name = "eExecutionHitBreakpoint";
+ case eExpressionHitBreakpoint:
+ result_name = "eExpressionHitBreakpoint";
break;
- case eExecutionSetupError:
- result_name = "eExecutionSetupError";
+ case eExpressionSetupError:
+ result_name = "eExpressionSetupError";
break;
- case eExecutionTimedOut:
- result_name = "eExecutionTimedOut";
+ case eExpressionParseError:
+ result_name = "eExpressionParseError";
break;
- case eExecutionStoppedForDebug:
- result_name = "eExecutionStoppedForDebug";
+ case eExpressionResultUnavailable:
+ result_name = "eExpressionResultUnavailable";
+ break;
+ case eExpressionTimedOut:
+ result_name = "eExpressionTimedOut";
+ break;
+ case eExpressionStoppedForDebug:
+ result_name = "eExpressionStoppedForDebug";
break;
}
return result_name;
@@ -5823,25 +5843,47 @@ Process::GetThreadStatus (Stream &strm,
{
size_t num_thread_infos_dumped = 0;
- Mutex::Locker locker (GetThreadList().GetMutex());
- const size_t num_threads = GetThreadList().GetSize();
+ // 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<uint32_t> thread_index_array;
+ //Scope for thread list locker;
+ {
+ Mutex::Locker locker (GetThreadList().GetMutex());
+ ThreadList &curr_thread_list = GetThreadList();
+ num_threads = curr_thread_list.GetSize();
+ uint32_t idx;
+ thread_index_array.resize(num_threads);
+ for (idx = 0; idx < num_threads; ++idx)
+ thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
+ }
+
for (uint32_t i = 0; i < num_threads; i++)
{
- Thread *thread = GetThreadList().GetThreadAtIndex(i).get();
- if (thread)
+ ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_index_array[i]));
+ if (thread_sp)
{
if (only_threads_with_stop_reason)
{
- StopInfoSP stop_info_sp = thread->GetStopInfo();
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
if (stop_info_sp.get() == NULL || !stop_info_sp->IsValid())
continue;
}
- thread->GetStatus (strm,
+ 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;
}
@@ -5897,6 +5939,10 @@ Process::Flush ()
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);
@@ -5905,6 +5951,7 @@ Process::DidExec ()
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();
@@ -5955,3 +6002,14 @@ Process::ResolveIndirectFunction(const Address *address, Error &error)
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);
+}
diff --git a/source/Target/ProcessInfo.cpp b/source/Target/ProcessInfo.cpp
new file mode 100644
index 000000000000..22da2c6a2a29
--- /dev/null
+++ b/source/Target/ProcessInfo.cpp
@@ -0,0 +1,138 @@
+//===-- ProcessInfo.cpp -----------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Target/ProcessInfo.h"
+
+// C Includes
+#include <limits.h>
+
+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 (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;
+}
+
+const char *
+ProcessInfo::GetName() const
+{
+ return m_executable.GetFilename().GetCString();
+}
+
+size_t
+ProcessInfo::GetNameLength() const
+{
+ return m_executable.GetFilename().GetLength();
+}
+
+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
+{
+ if (m_arg0.empty())
+ return NULL;
+ return m_arg0.c_str();
+}
+
+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 (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/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp
new file mode 100644
index 000000000000..830f1470ed98
--- /dev/null
+++ b/source/Target/ProcessLaunchInfo.cpp
@@ -0,0 +1,459 @@
+//===-- ProcessLaunchInfo.cpp -----------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "lldb/Host/Config.h"
+
+#ifndef LLDB_DISABLE_POSIX
+#include <spawn.h>
+#endif
+
+#include "lldb/Target/ProcessLaunchInfo.h"
+#include "lldb/Target/FileAction.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------------
+// ProcessLaunchInfo member functions
+//----------------------------------------------------------------------------
+
+ProcessLaunchInfo::ProcessLaunchInfo () :
+ ProcessInfo(),
+ m_working_dir (),
+ m_plugin_name (),
+ m_shell (),
+ m_flags (0),
+ m_file_actions (),
+ m_pty (),
+ m_resume_count (0),
+ m_monitor_callback (NULL),
+ m_monitor_callback_baton (NULL),
+ m_monitor_signals (false),
+ m_hijack_listener_sp ()
+{
+}
+
+ProcessLaunchInfo::ProcessLaunchInfo(const char *stdin_path, const char *stdout_path, const char *stderr_path,
+ const char *working_directory, uint32_t launch_flags)
+ : ProcessInfo()
+ , m_working_dir()
+ , m_plugin_name()
+ , m_shell()
+ , m_flags(launch_flags)
+ , m_file_actions()
+ , m_pty()
+ , m_resume_count(0)
+ , m_monitor_callback(NULL)
+ , m_monitor_callback_baton(NULL)
+ , m_monitor_signals(false)
+ , m_hijack_listener_sp()
+{
+ if (stdin_path)
+ {
+ FileAction file_action;
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDIN_FILENO, stdin_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (stdout_path)
+ {
+ FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDOUT_FILENO, stdout_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (stderr_path)
+ {
+ FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDERR_FILENO, stderr_path, read, write))
+ AppendFileAction (file_action);
+ }
+ if (working_directory)
+ SetWorkingDirectory(working_directory);
+}
+
+bool
+ProcessLaunchInfo::AppendCloseFileAction (int fd)
+{
+ FileAction file_action;
+ if (file_action.Close (fd))
+ {
+ 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::AppendOpenFileAction (int fd, const char *path, bool read, bool write)
+{
+ FileAction file_action;
+ if (file_action.Open (fd, path, read, write))
+ {
+ AppendFileAction (file_action);
+ return true;
+ }
+ return false;
+}
+
+bool
+ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
+{
+ FileAction file_action;
+ if (file_action.Open (fd, "/dev/null", 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 NULL;
+}
+
+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 NULL;
+}
+
+const char *
+ProcessLaunchInfo::GetWorkingDirectory () const
+{
+ if (m_working_dir.empty())
+ return NULL;
+ return m_working_dir.c_str();
+}
+
+void
+ProcessLaunchInfo::SetWorkingDirectory (const char *working_dir)
+{
+ if (working_dir && working_dir[0])
+ m_working_dir.assign (working_dir);
+ else
+ m_working_dir.clear();
+}
+
+const char *
+ProcessLaunchInfo::GetProcessPluginName () const
+{
+ if (m_plugin_name.empty())
+ return NULL;
+ return m_plugin_name.c_str();
+}
+
+void
+ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
+{
+ if (plugin && plugin[0])
+ m_plugin_name.assign (plugin);
+ else
+ m_plugin_name.clear();
+}
+
+const char *
+ProcessLaunchInfo::GetShell () const
+{
+ if (m_shell.empty())
+ return NULL;
+ return m_shell.c_str();
+}
+
+void
+ProcessLaunchInfo::SetShell (const char * path)
+{
+ if (path && path[0])
+ {
+ m_shell.assign (path);
+ m_flags.Set (lldb::eLaunchFlagLaunchInShell);
+ }
+ else
+ {
+ m_shell.clear();
+ 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::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_hijack_listener_sp.reset();
+}
+
+void
+ProcessLaunchInfo::SetMonitorProcessCallback (Host::MonitorChildProcessCallback callback,
+ void *baton,
+ bool monitor_signals)
+{
+ m_monitor_callback = callback;
+ m_monitor_callback_baton = baton;
+ m_monitor_signals = monitor_signals;
+}
+
+bool
+ProcessLaunchInfo::MonitorProcess () const
+{
+ if (m_monitor_callback && ProcessIDIsValid())
+ {
+ Host::StartMonitoringChildProcess (m_monitor_callback,
+ m_monitor_callback_baton,
+ 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::FinalizeFileActions (Target *target, bool default_to_use_pty)
+{
+ // 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) == NULL || GetFileActionForFD(STDOUT_FILENO) == NULL ||
+ GetFileActionForFD(STDERR_FILENO) == NULL)
+ {
+ if (m_flags.Test(eLaunchFlagDisableSTDIO))
+ {
+ 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_path;
+ FileSpec out_path;
+ FileSpec err_path;
+ if (target)
+ {
+ in_path = target->GetStandardInputPath();
+ out_path = target->GetStandardOutputPath();
+ err_path = target->GetStandardErrorPath();
+ }
+
+ char path[PATH_MAX];
+ if (in_path && in_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDIN_FILENO, path, true, false);
+
+ if (out_path && out_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDOUT_FILENO, path, false, true);
+
+ if (err_path && err_path.GetPath(path, sizeof(path)))
+ AppendOpenFileAction(STDERR_FILENO, path, false, true);
+
+ if (default_to_use_pty && (!in_path || !out_path || !err_path)) {
+ if (m_pty.OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0)) {
+ const char *slave_path = m_pty.GetSlaveName(NULL, 0);
+
+ if (!in_path) {
+ AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
+ }
+
+ if (!out_path) {
+ AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
+ }
+
+ if (!err_path) {
+ AppendOpenFileAction(STDERR_FILENO, slave_path, 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))
+ {
+ const char *shell_executable = GetShell();
+ if (shell_executable)
+ {
+ char shell_resolved_path[PATH_MAX];
+
+ if (localhost)
+ {
+ FileSpec shell_filespec (shell_executable, true);
+
+ if (!shell_filespec.Exists())
+ {
+ // Resolve the path in case we just got "bash", "sh" or "tcsh"
+ if (!shell_filespec.ResolveExecutableLocation ())
+ {
+ error.SetErrorStringWithFormat("invalid shell path '%s'", shell_executable);
+ return false;
+ }
+ }
+ shell_filespec.GetPath (shell_resolved_path, sizeof(shell_resolved_path));
+ shell_executable = shell_resolved_path;
+ }
+
+ const char **argv = GetArguments().GetConstArgumentVector ();
+ if (argv == NULL || argv[0] == NULL)
+ return false;
+ Args shell_arguments;
+ std::string safe_arg;
+ shell_arguments.AppendArgument (shell_executable);
+ 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];
+ if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
+ {
+ // 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")
+ const char *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 && working_dir[0])
+ {
+ new_path += working_dir;
+ }
+ 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;
+ }
+ const char *curr_path = getenv("PATH");
+ if (curr_path)
+ {
+ if (new_path.size() > empty_path_len)
+ new_path += ':';
+ new_path += curr_path;
+ }
+ new_path += "\" ";
+ shell_command.PutCString(new_path.c_str());
+ }
+
+ 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] != NULL; ++i)
+ {
+ const char *arg = Args::GetShellSafeArgument (argv[i], safe_arg);
+ shell_command.Printf(" %s", arg);
+ }
+ }
+ shell_arguments.AppendArgument (shell_command.GetString().c_str());
+ m_executable.SetFile(shell_executable, false);
+ m_arguments = shell_arguments;
+ return true;
+ }
+ else
+ {
+ error.SetErrorString ("invalid shell path");
+ }
+ }
+ else
+ {
+ error.SetErrorString ("not launching in shell");
+ }
+ return false;
+}
diff --git a/source/Target/Queue.cpp b/source/Target/Queue.cpp
index 2b9d2a0ed9a4..7cfa6fa5582f 100644
--- a/source/Target/Queue.cpp
+++ b/source/Target/Queue.cpp
@@ -23,7 +23,8 @@ Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue
m_running_work_items_count(0),
m_pending_work_items_count(0),
m_pending_items(),
- m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS)
+ m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS),
+ m_kind (eQueueKindUnknown)
{
if (queue_name)
m_queue_name = queue_name;
@@ -125,3 +126,15 @@ Queue::GetPendingItems ()
}
return m_pending_items;
}
+
+lldb::QueueKind
+Queue::GetKind ()
+{
+ return m_kind;
+}
+
+void
+Queue::SetKind (lldb::QueueKind kind)
+{
+ m_kind = kind;
+}
diff --git a/source/Target/QueueItem.cpp b/source/Target/QueueItem.cpp
index bb6762829ca6..002187b8d204 100644
--- a/source/Target/QueueItem.cpp
+++ b/source/Target/QueueItem.cpp
@@ -15,10 +15,13 @@
using namespace lldb;
using namespace lldb_private;
-QueueItem::QueueItem (QueueSP queue_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_address (),
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),
@@ -30,6 +33,7 @@ QueueItem::QueueItem (QueueSP queue_sp) :
m_target_queue_label()
{
m_queue_wp = queue_sp;
+ m_process_wp = process_sp;
}
QueueItem::~QueueItem ()
@@ -37,8 +41,9 @@ QueueItem::~QueueItem ()
}
QueueItemKind
-QueueItem::GetKind() const
+QueueItem::GetKind()
{
+ FetchEntireItem ();
return m_kind;
}
@@ -63,6 +68,7 @@ QueueItem::SetAddress (Address addr)
ThreadSP
QueueItem::GetExtendedBacktraceThread (ConstString type)
{
+ FetchEntireItem ();
ThreadSP return_thread;
QueueSP queue_sp = m_queue_wp.lock();
if (queue_sp)
@@ -75,3 +81,76 @@ QueueItem::GetExtendedBacktraceThread (ConstString type)
}
return return_thread;
}
+
+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::queue_id_t
+QueueItem::GetEnqueueingQueueID ()
+{
+ FetchEntireItem ();
+ return m_enqueueing_queue_id;
+}
+
+uint32_t
+QueueItem::GetStopID ()
+{
+ FetchEntireItem ();
+ return m_stop_id;
+}
+
+std::vector<lldb::addr_t> &
+QueueItem::GetEnqueueingBacktrace ()
+{
+ FetchEntireItem ();
+ return m_backtrace;
+}
+
+std::string
+QueueItem::GetThreadLabel ()
+{
+ FetchEntireItem ();
+ return m_thread_label;
+}
+
+std::string
+QueueItem::GetQueueLabel ()
+{
+ FetchEntireItem ();
+ return m_queue_label;
+}
+
+
+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/source/Target/RegisterContext.cpp b/source/Target/RegisterContext.cpp
index 93dce3ea0edc..97f6f21c53c8 100644
--- a/source/Target/RegisterContext.cpp
+++ b/source/Target/RegisterContext.cpp
@@ -82,7 +82,7 @@ RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx
}
const RegisterInfo *
-RegisterContext::GetRegisterInfo (uint32_t kind, uint32_t num)
+RegisterContext::GetRegisterInfo (lldb::RegisterKind kind, uint32_t num)
{
const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
if (reg_num == LLDB_INVALID_REGNUM)
@@ -488,7 +488,7 @@ RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx)
bool
-RegisterContext::ConvertBetweenRegisterKinds (int source_rk, uint32_t source_regnum, int target_rk, uint32_t& target_regnum)
+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)
diff --git a/source/Target/SectionLoadHistory.cpp b/source/Target/SectionLoadHistory.cpp
index 527168ce42af..1e5c4175a2bf 100644
--- a/source/Target/SectionLoadHistory.cpp
+++ b/source/Target/SectionLoadHistory.cpp
@@ -47,15 +47,7 @@ SectionLoadHistory::GetLastStopID() const
SectionLoadList *
SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_only)
{
- if (m_stop_id_to_section_load_list.empty())
- {
- 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();
- }
- else
+ if (!m_stop_id_to_section_load_list.empty())
{
if (read_only)
{
@@ -65,7 +57,7 @@ SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_onl
if (stop_id == eStopIDNow)
{
// If we are asking for the latest and greatest value, it is always
- // at the end of our list becuase that will be the highest stop ID.
+ // 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();
}
@@ -105,13 +97,18 @@ SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_onl
return section_load_list_sp.get();
}
}
- return NULL;
+ 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;
+ Mutex::Locker locker(m_mutex);
SectionLoadList *section_load_list = GetSectionLoadListForStopID (eStopIDNow, read_only);
assert(section_load_list != NULL);
return *section_load_list;
diff --git a/source/Target/SectionLoadList.cpp b/source/Target/SectionLoadList.cpp
index 82f52f9db1b5..da3aea5034d1 100644
--- a/source/Target/SectionLoadList.cpp
+++ b/source/Target/SectionLoadList.cpp
@@ -81,19 +81,17 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t l
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
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__,
- section.get(),
+ __FUNCTION__, static_cast<void*>(section.get()),
module_file_spec.GetPath().c_str(),
- section->GetName().AsCString(),
- load_addr,
- module_sp.get());
+ section->GetName().AsCString(), load_addr,
+ static_cast<void*>(module_sp.get()));
}
if (section->GetByteSize() == 0)
@@ -118,7 +116,7 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t l
{
// 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
- // allways attribute the section to the be last section that claims it
+ // 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
@@ -155,8 +153,7 @@ SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP &section, addr_t l
if (log)
{
log->Printf ("SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 ") error: module has been deleted",
- __FUNCTION__,
- section.get(),
+ __FUNCTION__, static_cast<void*>(section.get()),
section->GetName().AsCString(),
load_addr);
}
@@ -177,14 +174,13 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp)
{
const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
log->Printf ("SectionLoadList::%s (section = %p (%s.%s))",
- __FUNCTION__,
- section_sp.get(),
+ __FUNCTION__, static_cast<void*>(section_sp.get()),
module_file_spec.GetPath().c_str(),
section_sp->GetName().AsCString());
}
Mutex::Locker locker(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())
{
@@ -209,11 +205,9 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp, addr_t l
{
const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ")",
- __FUNCTION__,
- section_sp.get(),
+ __FUNCTION__, static_cast<void*>(section_sp.get()),
module_file_spec.GetPath().c_str(),
- section_sp->GetName().AsCString(),
- load_addr);
+ section_sp->GetName().AsCString(), load_addr);
}
bool erased = false;
Mutex::Locker locker(m_mutex);
@@ -223,7 +217,7 @@ SectionLoadList::SetSectionUnloaded (const lldb::SectionSP &section_sp, addr_t l
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())
{
@@ -287,7 +281,8 @@ SectionLoadList::Dump (Stream &s, Target *target)
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, pos->second.get());
+ 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/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index a936a57d048d..e497b176ccfe 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -360,7 +360,7 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)
}
- // Resolve our PC to section offset if we haven't alreday done so
+ // 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))
@@ -861,7 +861,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
var_expr_path_strm.GetString().c_str());
}
- else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
+ 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\"",
@@ -937,7 +937,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
valobj_sp->GetTypeName().AsCString("<invalid type>"),
var_expr_path_strm.GetString().c_str());
}
- else if (child_index >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
+ 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\"",
@@ -1444,13 +1444,12 @@ StackFrame::GetStatus (Stream& strm,
const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false);
disasm_display = debugger.GetStopDisassemblyDisplay ();
- if (source_lines_before > 0 || source_lines_after > 0)
+ GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
+ if (m_sc.comp_unit && m_sc.line_entry.IsValid())
{
- GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
-
- if (m_sc.comp_unit && m_sc.line_entry.IsValid())
+ have_source = true;
+ if (source_lines_before > 0 || source_lines_after > 0)
{
- have_source = true;
target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file,
m_sc.line_entry.line,
source_lines_before,
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 631a77bd4951..99234dc61f1d 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -269,7 +269,7 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)
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 ot do that if end_idx is 0 since in that case we always
+ // 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...
@@ -491,7 +491,7 @@ StackFrameList::Dump (Stream *s)
for (pos = begin; pos != end; ++pos)
{
StackFrame *frame = (*pos).get();
- s->Printf("%p: ", frame);
+ s->Printf("%p: ", static_cast<void*>(frame));
if (frame)
{
frame->GetStackID().Dump (s);
diff --git a/source/Target/StackID.cpp b/source/Target/StackID.cpp
index 9e8c315d0704..ca337f914406 100644
--- a/source/Target/StackID.cpp
+++ b/source/Target/StackID.cpp
@@ -24,11 +24,12 @@ 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", (uint64_t)m_pc, (uint64_t)m_cfa, m_symbol_scope);
+ 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());
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index 3664e8f0c738..a37a4079ff11 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -108,7 +108,6 @@ namespace lldb_private
class StopInfoBreakpoint : public StopInfo
{
public:
-
StopInfoBreakpoint (Thread &thread, break_id_t break_id) :
StopInfo (thread, break_id),
m_description(),
@@ -121,7 +120,7 @@ public:
{
StoreBPInfo();
}
-
+
StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :
StopInfo (thread, break_id),
m_description(),
@@ -161,7 +160,7 @@ public:
virtual ~StopInfoBreakpoint ()
{
}
-
+
virtual StopReason
GetStopReason () const
{
@@ -199,7 +198,7 @@ public:
}
return false;
}
-
+
virtual bool
DoShouldNotify (Event *event_ptr)
{
@@ -252,7 +251,7 @@ public:
}
}
}
-
+
strm.Printf("breakpoint ");
bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
m_description.swap (strm.GetString());
@@ -290,7 +289,7 @@ public:
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());
}
}
@@ -307,20 +306,20 @@ protected:
assert (m_should_stop_is_valid);
return m_should_stop;
}
-
+
virtual void
PerformAction (Event *event_ptr)
{
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::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS);
-
+ 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.
@@ -332,13 +331,13 @@ protected:
m_should_stop_is_valid = true;
return;
}
-
+
BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
-
+
if (bp_site_sp)
{
size_t num_owners = bp_site_sp->GetNumberOfOwners();
-
+
if (num_owners == 0)
{
m_should_stop = true;
@@ -354,7 +353,7 @@ protected:
// 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;
ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
@@ -367,7 +366,7 @@ protected:
// 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,"
@@ -398,12 +397,12 @@ protected:
"running function, skipping commands and conditions to prevent recursion.");
return;
}
-
+
StoppointCallbackContext context (event_ptr, exe_ctx, false);
-
+
// Let's copy the breakpoint locations 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;
for (size_t j = 0; j < num_owners; j++)
site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
@@ -411,11 +410,11 @@ protected:
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()))
@@ -424,18 +423,20 @@ protected:
{
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(), thread_sp->GetID());
+ 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 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() != NULL)
{
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();
@@ -448,12 +449,10 @@ protected:
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();
- // If the condition fails to be parsed or run, we should stop.
- condition_says_stop = true;
}
else
{
@@ -461,36 +460,39 @@ protected:
{
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(), thread_sp->GetID(), condition_says_stop);
+ 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)
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 ())
@@ -706,7 +708,7 @@ protected:
{
// 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.
- ExecutionResults result_code;
+ ExpressionResults result_code;
EvaluateExpressionOptions expr_options;
expr_options.SetUnwindOnError(true);
expr_options.SetIgnoreBreakpoints(true);
@@ -718,7 +720,7 @@ protected:
NULL,
result_value_sp,
error);
- if (result_code == eExecutionCompleted)
+ if (result_code == eExpressionCompleted)
{
if (result_value_sp)
{
@@ -995,10 +997,11 @@ class StopInfoThreadPlan : public StopInfo
{
public:
- StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp) :
+ StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, ClangExpressionVariableSP &expression_variable_sp) :
StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),
m_plan_sp (plan_sp),
- m_return_valobj_sp (return_valobj_sp)
+ m_return_valobj_sp (return_valobj_sp),
+ m_expression_variable_sp (expression_variable_sp)
{
}
@@ -1030,6 +1033,12 @@ public:
return m_return_valobj_sp;
}
+ ClangExpressionVariableSP
+ GetExpressionVariable()
+ {
+ return m_expression_variable_sp;
+ }
+
protected:
virtual bool
ShouldStop (Event *event_ptr)
@@ -1043,6 +1052,7 @@ protected:
private:
ThreadPlanSP m_plan_sp;
ValueObjectSP m_return_valobj_sp;
+ ClangExpressionVariableSP m_expression_variable_sp;
};
class StopInfoExec : public StopInfo
@@ -1121,9 +1131,11 @@ StopInfo::CreateStopReasonToTrace (Thread &thread)
}
StopInfoSP
-StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp)
+StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp,
+ ValueObjectSP return_valobj_sp,
+ ClangExpressionVariableSP expression_variable_sp)
{
- return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp));
+ return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp, expression_variable_sp));
}
StopInfoSP
@@ -1149,3 +1161,15 @@ StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp)
else
return ValueObjectSP();
}
+
+ClangExpressionVariableSP
+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 ClangExpressionVariableSP();
+}
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index e7816266b415..d2d0b5098555 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -94,12 +94,12 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
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()", this);
+ 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());
@@ -113,7 +113,7 @@ Target::~Target()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Target::~Target()", this);
+ log->Printf ("%p Target::~Target()", static_cast<void*>(this));
DeleteCurrentProcess ();
}
@@ -486,9 +486,12 @@ Target::CreateFuncRegexBreakpoint (const FileSpecList *containingModules,
bool hardware)
{
SearchFilterSP filter_sp(GetSearchFilterForModuleAndCUList (containingModules, containingSourceFiles));
+ bool skip =
+ (skip_prologue == eLazyBoolCalculate) ? GetSkipPrologue()
+ : static_cast<bool>(skip_prologue);
BreakpointResolverSP resolver_sp(new BreakpointResolverName (NULL,
func_regex,
- skip_prologue == eLazyBoolCalculate ? GetSkipPrologue() : skip_prologue));
+ skip));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, true);
}
@@ -635,7 +638,7 @@ Target::CreateWatchpoint(lldb::addr_t addr, size_t size, const ClangASTType *typ
if (!CheckIfWatchpointsExhausted(this, error))
{
if (!OptionGroupWatchpoint::IsWatchSizeSupported(size))
- error.SetErrorStringWithFormat("watch size of %zu is not supported", size);
+ error.SetErrorStringWithFormat("watch size of %" PRIu64 " is not supported", (uint64_t)size);
}
wp_sp.reset();
}
@@ -1010,10 +1013,10 @@ LoadScriptingResourceForModule (const ModuleSP &module_sp, Target *target)
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());
}
+ if (feedback_stream.GetSize())
+ target->GetDebugger().GetErrorFile()->Printf("%s\n",
+ feedback_stream.GetData());
}
void
@@ -1047,7 +1050,7 @@ Target::SetExecutableModule (ModuleSP& executable_sp, bool get_dependent_files)
"Target::SetExecutableModule (executable = '%s')",
executable_sp->GetFileSpec().GetPath().c_str());
- m_images.Append(executable_sp); // The first image is our exectuable file
+ 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())
@@ -1142,41 +1145,44 @@ void
Target::ModuleAdded (const ModuleList& module_list, const ModuleSP &module_sp)
{
// A module is being added to this target for the first time
- ModuleList my_module_list;
- my_module_list.Append(module_sp);
- LoadScriptingResourceForModule(module_sp, this);
- ModulesDidLoad (my_module_list);
+ 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 added to this target for the first time
- ModuleList my_module_list;
- my_module_list.Append(module_sp);
- ModulesDidUnload (my_module_list, false);
+ 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
- m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
+ if (m_valid)
+ m_breakpoint_list.UpdateBreakpointsWhenModuleIsReplaced(old_module_sp, new_module_sp);
}
void
Target::ModulesDidLoad (ModuleList &module_list)
{
- if (module_list.GetSize())
+ if (m_valid && module_list.GetSize())
{
m_breakpoint_list.UpdateBreakpoints (module_list, true, false);
if (m_process_sp)
{
- SystemRuntime *sys_runtime = m_process_sp->GetSystemRuntime();
- if (sys_runtime)
- {
- sys_runtime->ModulesDidLoad (module_list);
- }
+ m_process_sp->ModulesDidLoad (module_list);
}
// TODO: make event data that packages up the module_list
BroadcastEvent (eBroadcastBitModulesLoaded, NULL);
@@ -1186,7 +1192,7 @@ Target::ModulesDidLoad (ModuleList &module_list)
void
Target::SymbolsDidLoad (ModuleList &module_list)
{
- if (module_list.GetSize())
+ if (m_valid && module_list.GetSize())
{
if (m_process_sp)
{
@@ -1206,7 +1212,7 @@ Target::SymbolsDidLoad (ModuleList &module_list)
void
Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
{
- if (module_list.GetSize())
+ if (m_valid && module_list.GetSize())
{
m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations);
// TODO: make event data that packages up the module_list
@@ -1255,7 +1261,7 @@ Target::ReadMemoryFromFileCache (const Address& addr, void *dst, size_t dst_len,
SectionSP section_sp (addr.GetSection());
if (section_sp)
{
- // If the contents of this section are encrypted, the on-disk file is unusuable. Read only from live memory.
+ // 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");
@@ -1320,7 +1326,7 @@ Target::ReadMemory (const Address& addr,
}
else
{
- // We have at least one section loaded. This can be becuase
+ // 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
@@ -1376,7 +1382,7 @@ Target::ReadMemory (const Address& addr,
}
// If the address is not section offset we have an address that
// doesn't resolve to any address in any currently loaded shared
- // libaries and we failed to read memory so there isn't anything
+ // 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())
@@ -1547,7 +1553,7 @@ Target::ReadPointerFromMemory (const Address& addr,
}
else
{
- // We have at least one section loaded. This can be becuase
+ // 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
@@ -1698,6 +1704,8 @@ Target::GetSharedModule (const ModuleSpec &module_spec, Error *error_ptr)
else
m_images.Append(module_sp);
}
+ else
+ module_sp.reset();
}
}
if (error_ptr)
@@ -1765,7 +1773,7 @@ Target::GetScratchClangASTContext(bool create_on_demand)
m_scratch_ast_context_ap.reset (new ClangASTContext(m_arch.GetTriple().str().c_str()));
m_scratch_ast_source_ap.reset (new ClangASTSource(shared_from_this()));
m_scratch_ast_source_ap->InstallASTContext(m_scratch_ast_context_ap->getASTContext());
- llvm::OwningPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy());
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> proxy_ast_source(m_scratch_ast_source_ap->CreateProxy());
m_scratch_ast_context_ap->SetExternalSource(proxy_ast_source);
}
return m_scratch_ast_context_ap.get();
@@ -1850,7 +1858,7 @@ Target::GetTargetFromContexts (const ExecutionContext *exe_ctx_ptr, const Symbol
return target;
}
-ExecutionResults
+ExpressionResults
Target::EvaluateExpression
(
const char *expr_cstr,
@@ -1861,7 +1869,7 @@ Target::EvaluateExpression
{
result_valobj_sp.reset();
- ExecutionResults execution_results = eExecutionSetupError;
+ ExpressionResults execution_results = eExpressionSetupError;
if (expr_cstr == NULL || expr_cstr[0] == '\0')
return execution_results;
@@ -1896,7 +1904,7 @@ Target::EvaluateExpression
if (persistent_var_sp)
{
result_valobj_sp = persistent_var_sp->GetValueObject ();
- execution_results = eExecutionCompleted;
+ execution_results = eExpressionCompleted;
}
else
{
@@ -2363,7 +2371,8 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
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 ())
{
m_process_sp = GetPlatform()->DebugProcess (launch_info,
@@ -2380,10 +2389,12 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
}
else
{
+ // Use a Process plugin to construct the process.
const char *plugin_name = launch_info.GetProcessPluginName();
CreateProcess (listener, plugin_name, NULL);
}
-
+
+ // Since we didn't have a platform launch the process, launch it here.
if (m_process_sp)
error = m_process_sp->Launch (launch_info);
}
@@ -2409,9 +2420,14 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
m_process_sp->RestoreProcessEvents ();
error = m_process_sp->PrivateResume();
-
+
if (error.Success())
{
+ // there is a race condition where this thread will return up the call stack to the main command
+ // handler and show an (lldb) prompt before HandlePrivateEvent (from PrivateStateThread) has
+ // a chance to call PushProcessIOHandler()
+ m_process_sp->SyncIOHandler(2000);
+
if (synchronous_execution)
{
state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get());
@@ -2429,6 +2445,27 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
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));
@@ -2616,6 +2653,7 @@ g_properties[] =
{ "input-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for reading its standard input." },
{ "output-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for writing its standard output." },
{ "error-path" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "The file/path to be used by the executable program for writing its standard error." },
+ { "detach-on-error" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "debugserver will detach (rather than killing) a process if it loses connection with lldb." },
{ "disable-aslr" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Disable Address Space Layout Randomization (ASLR)" },
{ "disable-stdio" , OptionValue::eTypeBoolean , false, false , NULL, NULL, "Disable stdin/stdout for process (e.g. for a GUI application)" },
{ "inline-breakpoint-strategy" , OptionValue::eTypeEnum , false, eInlineBreakpointsHeaders , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. "
@@ -2662,6 +2700,7 @@ enum
ePropertyInputPath,
ePropertyOutputPath,
ePropertyErrorPath,
+ ePropertyDetachOnError,
ePropertyDisableASLR,
ePropertyDisableSTDIO,
ePropertyInlineStrategy,
@@ -2699,7 +2738,7 @@ public:
virtual const Property *
GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
- // When gettings the value for a key from the target options, we will always
+ // 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)
@@ -2845,6 +2884,20 @@ TargetProperties::SetDisableASLR (bool b)
}
bool
+TargetProperties::GetDetachOnError () const
+{
+ const uint32_t idx = ePropertyDetachOnError;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+void
+TargetProperties::SetDetachOnError (bool b)
+{
+ const uint32_t idx = ePropertyDetachOnError;
+ m_collection_sp->SetPropertyAtIndexAsBoolean (NULL, idx, b);
+}
+
+bool
TargetProperties::GetDisableSTDIO () const
{
const uint32_t idx = ePropertyDisableSTDIO;
diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp
index c4da84fbf8be..5ee75ff74449 100644
--- a/source/Target/TargetList.cpp
+++ b/source/Target/TargetList.cpp
@@ -28,6 +28,8 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/TargetList.h"
+#include "llvm/ADT/SmallString.h"
+
using namespace lldb;
using namespace lldb_private;
@@ -85,12 +87,31 @@ TargetList::CreateTarget (Debugger &debugger,
ArchSpec platform_arch(arch);
+ bool prefer_platform_arch = false;
+
+ CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
+ if (platform_options && platform_options->PlatformWasSpecified ())
+ {
+ 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);
@@ -104,7 +125,17 @@ TargetList::CreateTarget (Debugger &debugger,
{
if (platform_arch.IsValid())
{
- if (!platform_arch.IsCompatibleMatch(matching_module_spec.GetArchitecture()))
+ 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
{
error.SetErrorStringWithFormat("the specified architecture '%s' is not compatible with '%s' in '%s'",
platform_arch.GetTriple().str().c_str(),
@@ -116,6 +147,7 @@ TargetList::CreateTarget (Debugger &debugger,
else
{
// Only one arch and none was specified
+ prefer_platform_arch = true;
platform_arch = matching_module_spec.GetArchitecture();
}
}
@@ -127,48 +159,114 @@ TargetList::CreateTarget (Debugger &debugger,
module_spec.GetArchitecture() = arch;
if (module_specs.FindMatchingModuleSpec(module_spec, matching_module_spec))
{
+ prefer_platform_arch = true;
platform_arch = matching_module_spec.GetArchitecture();
}
}
- // Don't just select the first architecture, we want to let the platform select
- // the best architecture first when there are multiple archs.
-// else
-// {
-// // No arch specified, select the first arch
-// if (module_specs.GetModuleSpecAtIndex(0, matching_module_spec))
-// {
-// 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::GetDefaultPlatform();
+ 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, NULL))
+ {
+ 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, NULL))
+ {
+ platforms.push_back(host_platform_sp);
+ continue;
+ }
+ }
+
+ // Just find a platform that matches the architecture in the executable file
+ platforms.push_back(Platform::GetPlatformForArchitecture(module_spec.GetArchitecture(), nullptr));
+ }
+ }
+
+ Platform *platform_ptr = NULL;
+ for (const auto &the_platform_sp : platforms)
+ {
+ if (platform_ptr)
+ {
+ if (platform_ptr->GetName() != the_platform_sp->GetName())
+ {
+ platform_ptr = NULL;
+ 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
+ {
+ // 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;
+ }
+ }
}
}
}
- CommandInterpreter &interpreter = debugger.GetCommandInterpreter();
- if (platform_options)
- {
- if (platform_options->PlatformWasSpecified ())
- {
- const bool select_platform = true;
- platform_sp = platform_options->CreatePlatformWithOptions (interpreter,
- arch,
- select_platform,
- error,
- platform_arch);
- if (!platform_sp)
- return error;
- }
- }
-
if (!platform_sp)
{
// Get the current platform and make sure it is compatible with the
// current architecture if we have a valid architecture.
platform_sp = debugger.GetPlatformList().GetSelectedPlatform ();
- if (arch.IsValid() && !platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ if (!prefer_platform_arch && arch.IsValid())
{
- platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ }
+ 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);
}
}
@@ -200,17 +298,10 @@ TargetList::CreateTarget (Debugger &debugger,
ArchSpec arch(specified_arch);
- if (platform_sp)
+ if (arch.IsValid())
{
- if (arch.IsValid())
- {
- if (!platform_sp->IsCompatibleArchitecture(arch, false, NULL))
- platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
- }
- }
- else if (arch.IsValid())
- {
- platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
+ if (!platform_sp || !platform_sp->IsCompatibleArchitecture(arch, false, NULL))
+ platform_sp = Platform::GetPlatformForArchitecture(specified_arch, &arch);
}
if (!platform_sp)
@@ -224,15 +315,13 @@ TargetList::CreateTarget (Debugger &debugger,
{
// 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
- char unglobbed_path[PATH_MAX];
- unglobbed_path[0] = '\0';
-
- size_t return_count = FileSpec::ResolveUsername(user_exe_path, unglobbed_path, sizeof(unglobbed_path));
-
- if (return_count == 0 || return_count >= sizeof(unglobbed_path))
- ::snprintf (unglobbed_path, sizeof(unglobbed_path), "%s", user_exe_path);
+ llvm::SmallString<64> unglobbed_path(user_exe_path);
+ FileSpec::ResolveUsername(unglobbed_path);
- file = FileSpec(unglobbed_path, false);
+ 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;
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index 39f269952882..a445517da6a8 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -26,6 +26,7 @@
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
#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"
@@ -61,6 +62,9 @@ Thread::GetGlobalProperties()
static PropertyDefinition
g_properties[] =
{
+ { "step-in-avoid-nodebug", OptionValue::eTypeBoolean, true, true, NULL, NULL, "If true, step-in will not stop in functions with no debug information." },
+ { "step-out-avoid-nodebug", OptionValue::eTypeBoolean, true, false, NULL, NULL, "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 , REG_EXTENDED, "^std::", NULL, "A regular expression defining functions step-in won't stop in." },
{ "step-avoid-libraries", OptionValue::eTypeFileSpecList , true , REG_EXTENDED, NULL, NULL, "A list of libraries that source stepping won't stop in." },
{ "trace-thread", OptionValue::eTypeBoolean, false, false, NULL, NULL, "If true, this thread will single-step and log execution." },
@@ -68,6 +72,8 @@ g_properties[] =
};
enum {
+ ePropertyStepInAvoidsNoDebug,
+ ePropertyStepOutAvoidsNoDebug,
ePropertyStepAvoidRegex,
ePropertyStepAvoidLibraries,
ePropertyEnableThreadTrace
@@ -93,7 +99,7 @@ public:
virtual const Property *
GetPropertyAtIndex (const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const
{
- // When gettings the value for a key from the thread options, we will always
+ // 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)
@@ -151,6 +157,21 @@ ThreadProperties::GetTraceEnabledState() const
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
}
+bool
+ThreadProperties::GetStepInAvoidsNoDebug() const
+{
+ const uint32_t idx = ePropertyStepInAvoidsNoDebug;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+bool
+ThreadProperties::GetStepOutAvoidsNoDebug() const
+{
+ const uint32_t idx = ePropertyStepOutAvoidsNoDebug;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
+}
+
+
//------------------------------------------------------------------
// Thread Event Data
//------------------------------------------------------------------
@@ -250,14 +271,14 @@ Thread::GetStaticBroadcasterClass ()
return class_name;
}
-Thread::Thread (Process &process, lldb::tid_t tid) :
+Thread::Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id) :
ThreadProperties (false),
UserID (tid),
Broadcaster(&process.GetTarget().GetDebugger(), Thread::GetStaticBroadcasterClass().AsCString()),
m_process_wp (process.shared_from_this()),
m_stop_info_sp (),
m_stop_info_stop_id (0),
- m_index_id (process.GetNextThreadIndexID(tid)),
+ m_index_id (use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)),
m_reg_context_sp (),
m_state (eStateUnloaded),
m_state_mutex (Mutex::eMutexTypeRecursive),
@@ -271,11 +292,14 @@ Thread::Thread (Process &process, lldb::tid_t tid) :
m_temporary_resume_state (eStateRunning),
m_unwinder_ap (),
m_destroy_called (false),
- m_override_should_notify (eLazyBoolCalculate)
+ 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 ")", this, GetID());
+ log->Printf ("%p Thread::Thread(tid = 0x%4.4" PRIx64 ")",
+ static_cast<void*>(this), GetID());
CheckInWithManager();
QueueFundamentalPlan(true);
@@ -286,7 +310,8 @@ Thread::~Thread()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
if (log)
- log->Printf ("%p Thread::~Thread(tid = 0x%4.4" PRIx64 ")", this, GetID());
+ 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);
}
@@ -395,7 +420,7 @@ Thread::GetStopInfo ()
const uint32_t stop_id = process_sp ? process_sp->GetStopID() : UINT32_MAX;
if (plan_sp && plan_sp->PlanSucceeded())
{
- return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject());
+ return StopInfo::CreateStopReasonWithPlan (plan_sp, GetReturnValueObject(), GetExpressionVariable());
}
else
{
@@ -475,7 +500,10 @@ Thread::SetStopInfo (const lldb::StopInfoSP &stop_info_sp)
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)\n", this, GetID(), stop_info_sp ? stop_info_sp->GetDescription() : "<NULL>", m_stop_info_stop_id);
+ 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
@@ -723,31 +751,27 @@ bool
Thread::ShouldStop (Event* event_ptr)
{
ThreadPlan *current_plan = GetCurrentPlan();
-
+
bool should_stop = true;
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
+
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());
+ __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());
+ __FUNCTION__, GetID (), GetProtocolID());
return false;
}
-
+
// 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
@@ -756,31 +780,29 @@ Thread::ShouldStop (Event* event_ptr)
{
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(),
+ __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__,
- this,
- GetID (),
+ __FUNCTION__, static_cast<void*>(this), GetID (),
GetProtocolID (),
- GetRegisterContext() ? GetRegisterContext()->GetPC() : LLDB_INVALID_ADDRESS);
+ 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.
@@ -823,15 +845,15 @@ Thread::ShouldStop (Event* event_ptr)
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)
@@ -848,21 +870,22 @@ Thread::ShouldStop (Event* event_ptr)
}
else
done_processing_current_plan = true;
-
+
break;
}
}
}
}
-
+
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);
-
+ 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))
{
@@ -878,10 +901,11 @@ Thread::ShouldStop (Event* event_ptr)
{
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);
+ log->Printf("Plan %s should stop: %d.",
+ current_plan->GetName(), should_stop);
if (current_plan->MischiefManaged())
{
if (should_stop)
@@ -913,7 +937,7 @@ Thread::ShouldStop (Event* event_ptr)
}
}
}
-
+
if (over_ride_stop)
should_stop = false;
@@ -921,7 +945,7 @@ Thread::ShouldStop (Event* event_ptr)
// 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 (should_stop)
{
ThreadPlan *plan_ptr = GetCurrentPlan();
@@ -930,16 +954,17 @@ Thread::ShouldStop (Event* event_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());
+ log->Printf("Plan %s being discarded in cleanup, it says it is already done.",
+ examined_plan->GetName());
DiscardThreadPlansUpToPlan(examined_plan);
}
}
}
-
+
}
if (log)
@@ -1016,37 +1041,33 @@ Vote
Thread::ShouldReportRun (Event* event_ptr)
{
StateType thread_state = GetResumeState ();
-
+
if (thread_state == eStateSuspended
|| thread_state == eStateInvalid)
{
return eVoteNoOpinion;
}
-
+
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(),
- this,
- GetID(),
+ 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(),
- this,
- GetID(),
+ GetIndexID(), static_cast<void*>(this), GetID(),
StateAsCString(GetTemporaryResumeState()),
GetCurrentPlan()->GetName());
-
+
return GetCurrentPlan()->ShouldReportRun (event_ptr);
}
}
@@ -1069,7 +1090,7 @@ Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
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();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
@@ -1078,8 +1099,7 @@ Thread::PushPlan (ThreadPlanSP &thread_plan_sp)
StreamString s;
thread_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
log->Printf("Thread::PushPlan(0x%p): \"%s\", tid = 0x%4.4" PRIx64 ".",
- this,
- s.GetData(),
+ static_cast<void*>(this), s.GetData(),
thread_plan_sp->GetThread().GetID());
}
}
@@ -1164,6 +1184,22 @@ Thread::GetReturnValueObject ()
return ValueObjectSP();
}
+ClangExpressionVariableSP
+Thread::GetExpressionVariable ()
+{
+ if (!m_completed_plan_stack.empty())
+ {
+ for (int i = m_completed_plan_stack.size() - 1; i >= 0; i--)
+ {
+ ClangExpressionVariableSP expression_variable_sp;
+ expression_variable_sp = m_completed_plan_stack[i]->GetExpressionVariable();
+ if (expression_variable_sp)
+ return expression_variable_sp;
+ }
+ }
+ return ClangExpressionVariableSP();
+}
+
bool
Thread::IsThreadPlanDone (ThreadPlan *plan)
{
@@ -1265,15 +1301,14 @@ 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(), up_to_plan_ptr);
- }
+ 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();
-
+
// If the input plan is NULL, 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 == NULL)
{
for (int i = stack_size - 1; i > 0; i--)
@@ -1425,12 +1460,13 @@ Thread::QueueThreadPlanForStepOverRange
bool abort_other_plans,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_other_threads
+ 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));
-
+ 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;
}
@@ -1443,17 +1479,21 @@ Thread::QueueThreadPlanForStepInRange
const SymbolContext &addr_context,
const char *step_in_target,
lldb::RunMode stop_other_threads,
- bool avoid_code_without_debug_info
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info
)
{
ThreadPlanSP thread_plan_sp;
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this, range, addr_context, stop_other_threads);
- if (avoid_code_without_debug_info)
- plan->GetFlags().Set (ThreadPlanShouldStopHere::eAvoidNoDebug);
- else
- plan->GetFlags().Clear (ThreadPlanShouldStopHere::eAvoidNoDebug);
+ ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this,
+ range,
+ addr_context,
+ stop_other_threads,
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
+
if (step_in_target)
plan->SetStepInTarget(step_in_target);
+
thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -1470,7 +1510,8 @@ Thread::QueueThreadPlanForStepOut
bool stop_other_threads,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_withoug_debug_info
)
{
ThreadPlanSP thread_plan_sp (new ThreadPlanStepOut (*this,
@@ -1479,7 +1520,42 @@ Thread::QueueThreadPlanForStepOut
stop_other_threads,
stop_vote,
run_vote,
- frame_idx));
+ frame_idx,
+ step_out_avoids_code_withoug_debug_info));
+
+ if (thread_plan_sp->ValidatePlan(NULL))
+ {
+ 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
+)
+{
+ ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this,
+ addr_context,
+ first_insn,
+ stop_other_threads,
+ stop_vote,
+ run_vote,
+ frame_idx,
+ eLazyBoolNo);
+ new_plan->ClearShouldStopHereCallbacks();
+ ThreadPlanSP thread_plan_sp(new_plan);
if (thread_plan_sp->ValidatePlan(NULL))
{
@@ -1651,6 +1727,9 @@ Thread::ClearStackFrames ()
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;
}
lldb::StackFrameSP
@@ -1896,6 +1975,21 @@ Thread::GetThreadLocalData (const ModuleSP module)
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());
+ }
+ }
+ return true;
+}
+
lldb::StackFrameSP
Thread::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
{
@@ -1995,6 +2089,82 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint
return num_frames_shown;
}
+bool
+Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json)
+{
+ DumpUsingSettingsFormat (strm, 0);
+ strm.Printf("\n");
+
+ StructuredData::ObjectSP thread_info = GetExtendedInfo();
+
+ if (thread_info && print_json)
+ {
+ thread_info->Dump (strm);
+ strm.Printf("\n");
+ 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 true;
+}
+
size_t
Thread::GetStackFrameStatus (Stream& strm,
uint32_t first_frame,
@@ -2021,6 +2191,7 @@ Thread::GetUnwinder ()
case llvm::Triple::x86_64:
case llvm::Triple::x86:
case llvm::Triple::arm:
+ case llvm::Triple::aarch64:
case llvm::Triple::thumb:
case llvm::Triple::mips64:
case llvm::Triple::hexagon:
@@ -2059,7 +2230,8 @@ Thread::IsStillAtLastBreakpointHit ()
{
lldb::addr_t pc = reg_ctx_sp->GetPC();
BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(pc);
- if (bp_site_sp && value == bp_site_sp->GetID())
+ if (bp_site_sp &&
+ static_cast<break_id_t>(value) == bp_site_sp->GetID())
return true;
}
}
@@ -2070,8 +2242,9 @@ Thread::IsStillAtLastBreakpointHit ()
Error
Thread::StepIn (bool source_step,
- bool avoid_code_without_debug_info)
-
+ LazyBool step_in_avoids_code_without_debug_info,
+ LazyBool step_out_avoids_code_without_debug_info)
+
{
Error error;
Process *process = GetProcess().get();
@@ -2090,7 +2263,8 @@ Thread::StepIn (bool source_step,
sc,
NULL,
run_mode,
- avoid_code_without_debug_info);
+ step_in_avoids_code_without_debug_info,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -2114,8 +2288,8 @@ Thread::StepIn (bool source_step,
}
Error
-Thread::StepOver (bool source_step)
-
+Thread::StepOver (bool source_step,
+ LazyBool step_out_avoids_code_without_debug_info)
{
Error error;
Process *process = GetProcess().get();
@@ -2133,7 +2307,8 @@ Thread::StepOver (bool source_step)
new_plan_sp = QueueThreadPlanForStepOverRange (abort_other_plans,
sc.line_entry.range,
sc,
- run_mode);
+ run_mode,
+ step_out_avoids_code_without_debug_info);
}
else
{
@@ -2187,4 +2362,4 @@ Thread::StepOut ()
error.SetErrorString("process not stopped");
}
return error;
-} \ No newline at end of file
+}
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
index 4fffdac9a34e..7fb16fdac5c0 100644
--- a/source/Target/ThreadList.cpp
+++ b/source/Target/ThreadList.cpp
@@ -262,7 +262,7 @@ ThreadList::ShouldStop (Event *event_ptr)
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
// The ShouldStop method of the threads can do a whole lot of work,
- // running breakpoint commands & conditions, etc. So we don't want
+ // 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
@@ -287,7 +287,16 @@ ThreadList::ShouldStop (Event *event_ptr)
}
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
diff --git a/source/Target/ThreadPlan.cpp b/source/Target/ThreadPlan.cpp
index 65d51bd01734..2c9b7fce7c24 100644
--- a/source/Target/ThreadPlan.cpp
+++ b/source/Target/ThreadPlan.cpp
@@ -161,16 +161,11 @@ ThreadPlan::WillResume (StateType resume_state, bool current_plan)
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(),
- &m_thread,
- m_thread.GetID(),
- (uint64_t)pc,
- (uint64_t)sp,
- (uint64_t)fp,
- m_name.c_str(),
- StateAsCString(resume_state),
- StopOthers());
+ __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);
diff --git a/source/Target/ThreadPlanBase.cpp b/source/Target/ThreadPlanBase.cpp
index 240f23a0b8f4..d70afae55573 100644
--- a/source/Target/ThreadPlanBase.cpp
+++ b/source/Target/ThreadPlanBase.cpp
@@ -151,7 +151,7 @@ ThreadPlanBase::ShouldStop (Event *event_ptr)
// 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.)", m_thread.GetID());
+ 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;
@@ -168,7 +168,7 @@ ThreadPlanBase::ShouldStop (Event *event_ptr)
if (stop_info_sp->ShouldStop(event_ptr))
{
if (log)
- log->Printf("Base plan discarding thread plans for thread tid = 0x%4.4" PRIx64 " (signal.)", m_thread.GetID());
+ 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;
}
diff --git a/source/Target/ThreadPlanCallFunction.cpp b/source/Target/ThreadPlanCallFunction.cpp
index 854750b85817..5a3ebd7b1284 100644
--- a/source/Target/ThreadPlanCallFunction.cpp
+++ b/source/Target/ThreadPlanCallFunction.cpp
@@ -12,7 +12,7 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "llvm/Support/MachO.h"
+
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/Breakpoint.h"
@@ -49,16 +49,16 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
ProcessSP process_sp (thread.GetProcess());
if (!process_sp)
return false;
-
+
abi = process_sp->GetABI().get();
-
+
if (!abi)
return false;
-
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP));
-
+
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...
@@ -68,17 +68,21 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
{
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.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
-
+
Module *exe_module = GetTarget().GetExecutableModulePointer();
if (exe_module == NULL)
{
m_constructor_errors.Printf ("Can't execute code without an executable module.");
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
else
@@ -90,23 +94,27 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
exe_module->GetFileSpec().GetFilename().AsCString());
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ 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.", this, m_constructor_errors.GetData());
+ log->Printf ("ThreadPlanCallFunction(%p): %s.",
+ static_cast<void*>(this),
+ m_constructor_errors.GetData());
return false;
}
}
-
+
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:");
@@ -115,11 +123,13 @@ ThreadPlanCallFunction::ConstructorSetup (Thread &thread,
{
m_constructor_errors.Printf ("Setting up ThreadPlanCallFunction, failed to checkpoint thread state.");
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): %s.", this, m_constructor_errors.GetData());
+ 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;
}
@@ -148,16 +158,16 @@ ThreadPlanCallFunction::ThreadPlanCallFunction (Thread &thread,
lldb::addr_t function_load_addr;
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;
}
@@ -198,15 +208,16 @@ 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.", this);
+ log->Printf ("ThreadPlanCallFunction(%p): Log called on ThreadPlanCallFunction that was never valid.",
+ static_cast<void*>(this));
return;
}
-
+
if (!m_takedown_done)
{
if (success)
@@ -220,14 +231,17 @@ ThreadPlanCallFunction::DoTakedown (bool success)
}
}
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
+ 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", this);
+ log->Printf("ThreadPlanCallFunction(%p): DoTakedown failed to restore register state",
+ static_cast<void*>(this));
}
SetPlanComplete(success);
ClearBreakpoints();
@@ -238,7 +252,9 @@ ThreadPlanCallFunction::DoTakedown (bool success)
else
{
if (log)
- log->Printf ("ThreadPlanCallFunction(%p): DoTakedown called as no-op for thread 0x%4.4" PRIx64 ", m_valid: %d complete: %d.\n", this, m_thread.GetID(), m_valid, IsPlanComplete());
+ 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());
}
}
@@ -317,6 +333,14 @@ ThreadPlanCallFunction::DoPlanExplainsStop (Event *event_ptr)
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: 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.
@@ -425,17 +449,6 @@ ThreadPlanCallFunction::StopOthers ()
return m_stop_other_threads;
}
-void
-ThreadPlanCallFunction::SetStopOthers (bool new_value)
-{
- if (m_subplan_sp)
- {
- ThreadPlanRunToAddress *address_plan = static_cast<ThreadPlanRunToAddress *>(m_subplan_sp.get());
- address_plan->SetStopOthers(new_value);
- }
- m_stop_other_threads = new_value;
-}
-
StateType
ThreadPlanCallFunction::GetPlanRunState ()
{
@@ -470,11 +483,12 @@ bool
ThreadPlanCallFunction::MischiefManaged ()
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
-
+
if (IsPlanComplete())
{
if (log)
- log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.", this);
+ log->Printf("ThreadPlanCallFunction(%p): Completed call function plan.",
+ static_cast<void*>(this));
ThreadPlan::MischiefManaged ();
return true;
@@ -547,6 +561,13 @@ ThreadPlanCallFunction::BreakpointsExplainStop()
return false;
}
+void
+ThreadPlanCallFunction::SetStopOthers (bool new_value)
+{
+ m_subplan_sp->SetStopOthers(new_value);
+}
+
+
bool
ThreadPlanCallFunction::RestoreThreadState()
{
diff --git a/source/Target/ThreadPlanCallUserExpression.cpp b/source/Target/ThreadPlanCallUserExpression.cpp
index 827de3e6057a..90b8cf81171f 100644
--- a/source/Target/ThreadPlanCallUserExpression.cpp
+++ b/source/Target/ThreadPlanCallUserExpression.cpp
@@ -12,7 +12,7 @@
// C Includes
// C++ Includes
// Other libraries and framework includes
-#include "llvm/Support/MachO.h"
+
// Project includes
#include "lldb/lldb-private-log.h"
#include "lldb/Breakpoint/Breakpoint.h"
@@ -21,6 +21,7 @@
#include "lldb/Core/Log.h"
#include "lldb/Core/Stream.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Process.h"
#include "lldb/Target/RegisterContext.h"
@@ -56,7 +57,54 @@ ThreadPlanCallUserExpression::~ThreadPlanCallUserExpression ()
void
ThreadPlanCallUserExpression::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
- ThreadPlanCallFunction::GetDescription (s, 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();
+}
+
+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));
+
+ 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();
+
+ function_stack_bottom = function_stack_pointer - HostInfo::GetPageSize();
+ function_stack_top = function_stack_pointer;
+
+ StreamString error_stream;
+
+ ExecutionContext exe_ctx(GetThread());
+
+ m_user_expression_sp->FinalizeJITExecution(error_stream, exe_ctx, m_result_var_sp, function_stack_bottom, function_stack_top);
+ }
+
+ ThreadPlan::MischiefManaged ();
+ return true;
+ }
+ else
+ {
+ return false;
+ }
}
StopInfoSP
diff --git a/source/Target/ThreadPlanRunToAddress.cpp b/source/Target/ThreadPlanRunToAddress.cpp
index 9e7713973054..e2f85c0c5f5f 100644
--- a/source/Target/ThreadPlanRunToAddress.cpp
+++ b/source/Target/ThreadPlanRunToAddress.cpp
@@ -69,7 +69,7 @@ ThreadPlanRunToAddress::ThreadPlanRunToAddress
m_addresses (addresses),
m_break_ids ()
{
- // Convert all addressses into opcode addresses to make sure we set
+ // 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();
diff --git a/source/Target/ThreadPlanShouldStopHere.cpp b/source/Target/ThreadPlanShouldStopHere.cpp
index 87662345a06d..e89f5d2bde1b 100644
--- a/source/Target/ThreadPlanShouldStopHere.cpp
+++ b/source/Target/ThreadPlanShouldStopHere.cpp
@@ -23,12 +23,23 @@ using namespace lldb_private;
//----------------------------------------------------------------------
// ThreadPlanShouldStopHere constructor
//----------------------------------------------------------------------
-ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner, ThreadPlanShouldStopHereCallback callback, void *baton) :
- m_callback (callback),
- m_baton (baton),
+ThreadPlanShouldStopHere::ThreadPlanShouldStopHere(ThreadPlan *owner) :
+ m_callbacks (),
+ m_baton (NULL),
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);
}
//----------------------------------------------------------------------
@@ -38,37 +49,120 @@ ThreadPlanShouldStopHere::~ThreadPlanShouldStopHere()
{
}
-void
-ThreadPlanShouldStopHere::SetShouldStopHereCallback (ThreadPlanShouldStopHereCallback callback, void *baton)
+bool
+ThreadPlanShouldStopHere::InvokeShouldStopHereCallback (FrameComparison operation)
{
- m_callback = callback;
- m_baton = baton;
-}
-
-ThreadPlanSP
-ThreadPlanShouldStopHere::InvokeShouldStopHereCallback ()
-{
- if (m_callback)
+ bool should_stop_here = true;
+ if (m_callbacks.should_stop_here_callback)
{
- ThreadPlanSP return_plan_sp(m_callback (m_owner, m_flags, m_baton));
+ 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);
- if (return_plan_sp)
- {
- StreamString s;
- return_plan_sp->GetDescription (&s, lldb::eDescriptionLevelFull);
- log->Printf ("ShouldStopHere callback found a step out plan from 0x%" PRIx64 ": %s.", current_addr, s.GetData());
- }
- else
- {
- log->Printf ("ShouldStopHere callback didn't find a step out plan from: 0x%" PRIx64 ".", current_addr);
- }
+ 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;
+}
+
+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.
+ StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
+ if (!frame)
return return_plan_sp;
+ SymbolContext sc;
+ sc = frame->GetSymbolContext (eSymbolContextLineEntry);
+ if (sc.line_entry.line == 0)
+ {
+ AddressRange range = sc.line_entry.range;
+ return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOverRange(false,
+ range,
+ sc,
+ eOnlyDuringStepping,
+ eLazyBoolNo);
+ }
+
+ if (!return_plan_sp)
+ return_plan_sp = current_plan->GetThread().QueueThreadPlanForStepOutNoShouldStop (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ frame_index);
+ 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();
}
+
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index c4cb9aba1b3e..3e9abef65573 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -31,7 +31,7 @@
using namespace lldb;
using namespace lldb_private;
-uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eAvoidNoDebug;
+uint32_t ThreadPlanStepInRange::s_default_flag_values = ThreadPlanShouldStopHere::eStepInAvoidNoDebug;
//----------------------------------------------------------------------
// ThreadPlanStepInRange: Step through a stack range, either stepping over or into
@@ -43,14 +43,18 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others
+ 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, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ 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
@@ -59,15 +63,19 @@ ThreadPlanStepInRange::ThreadPlanStepInRange
const AddressRange &range,
const SymbolContext &addr_context,
const char *step_into_target,
- lldb::RunMode stop_others
+ 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, ThreadPlanStepInRange::DefaultShouldStopHereCallback, NULL),
+ 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 ()
@@ -75,6 +83,48 @@ ThreadPlanStepInRange::~ThreadPlanStepInRange ()
}
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);
+
+ 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);
+}
+
+void
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
@@ -124,7 +174,8 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
{
// If we've just completed a virtual step, all we need to do is check for a ShouldStopHere plan, and otherwise
// we're done.
- m_sub_plan_sp = InvokeShouldStopHereCallback();
+ // 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
{
@@ -139,7 +190,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
FrameComparison frame_order = CompareCurrentFrameToStartFrame();
- if (frame_order == eFrameCompareOlder)
+ if (frame_order == eFrameCompareOlder || frame_order == eFrameCompareSameParent)
{
// If we're in an older frame then we should stop.
//
@@ -148,7 +199,12 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
// 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)
- return true;
+ {
+ // 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.");
@@ -196,7 +252,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
// 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 = InvokeShouldStopHereCallback();
+ 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.
@@ -251,12 +307,6 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
}
}
-void
-ThreadPlanStepInRange::SetFlagsToDefault ()
-{
- GetFlags().Set(ThreadPlanStepInRange::s_default_flag_values);
-}
-
void
ThreadPlanStepInRange::SetAvoidRegexp(const char *name)
{
@@ -344,25 +394,19 @@ ThreadPlanStepInRange::FrameMatchesAvoidCriteria ()
return false;
}
-ThreadPlanSP
-ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, void *baton)
+bool
+ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan, Flags &flags, FrameComparison operation, void *baton)
{
- bool should_step_out = false;
+ bool should_stop_here = true;
StackFrame *frame = current_plan->GetThread().GetStackFrameAtIndex(0).get();
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (flags.Test(eAvoidNoDebug))
- {
- if (!frame->HasDebugInformation())
- {
- if (log)
- log->Printf ("Stepping out of frame with no debug info");
-
- should_step_out = true;
- }
- }
+ // 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 (current_plan->GetKind() == eKindStepInRange)
+ 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)
@@ -373,7 +417,7 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
// 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_step_out = false;
+ should_stop_here = true;
}
else
{
@@ -381,42 +425,26 @@ ThreadPlanStepInRange::DefaultShouldStopHereCallback (ThreadPlan *current_plan,
const char *function_name = sc.GetFunctionName().AsCString();
if (function_name == NULL)
- should_step_out = true;
+ should_stop_here = false;
else if (strstr (function_name, target_name) == NULL)
- should_step_out = true;
+ should_stop_here = false;
}
- if (log && should_step_out)
+ 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_step_out)
+ 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_step_out = step_in_range_plan->FrameMatchesAvoidCriteria ();
+ should_stop_here = !step_in_range_plan->FrameMatchesAvoidCriteria ();
}
}
-
- if (should_step_out)
- {
- // FIXME: Make sure the ThreadPlanForStepOut does the right thing with inlined functions.
- // We really should have all plans take the tri-state for "stop others" so we can do the right
- // thing. For now let's be safe and always run others when we are likely to run arbitrary code.
- const bool stop_others = false;
- return current_plan->GetThread().QueueThreadPlanForStepOut (false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0); // Frame index
- }
-
- return ThreadPlanSP();
+ return should_stop_here;
}
bool
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
index f644ee88f701..fabf63b1e9d6 100644
--- a/source/Target/ThreadPlanStepInstruction.cpp
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -43,21 +43,28 @@ ThreadPlanStepInstruction::ThreadPlanStepInstruction
m_stop_other_threads (stop_other_threads),
m_step_over (step_over)
{
+ m_takes_iteration_count = true;
+ SetUpState();
+}
+
+ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
+{
+}
+
+void
+ThreadPlanStepInstruction::SetUpState()
+{
m_instruction_addr = m_thread.GetRegisterContext()->GetPC(0);
- StackFrameSP m_start_frame_sp(m_thread.GetStackFrameAtIndex(0));
- m_stack_id = m_start_frame_sp->GetStackID();
+ StackFrameSP start_frame_sp(m_thread.GetStackFrameAtIndex(0));
+ m_stack_id = start_frame_sp->GetStackID();
- m_start_has_symbol = m_start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
+ m_start_has_symbol = start_frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol != NULL;
StackFrameSP parent_frame_sp = m_thread.GetStackFrameAtIndex(1);
if (parent_frame_sp)
m_parent_frame_id = parent_frame_sp->GetStackID();
}
-ThreadPlanStepInstruction::~ThreadPlanStepInstruction ()
-{
-}
-
void
ThreadPlanStepInstruction::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
@@ -106,6 +113,37 @@ ThreadPlanStepInstruction::DoPlanExplainsStop (Event *event_ptr)
}
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)
+ {
+ if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
+ return true;
+ else
+ return false;
+ }
+ 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.
+ if (m_step_over)
+ return false;
+ else
+ return true;
+ }
+ 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)
@@ -118,8 +156,18 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
{
- SetPlanComplete();
- return true;
+ 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;
@@ -147,13 +195,13 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
// StepInstruction should probably have the tri-state RunMode, but for now it is safer to
// run others.
const bool stop_others = false;
- m_thread.QueueThreadPlanForStepOut(false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0);
+ m_thread.QueueThreadPlanForStepOutNoShouldStop(false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
return false;
}
else
@@ -182,8 +230,18 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (m_thread.GetRegisterContext()->GetPC(0) != m_instruction_addr)
{
- SetPlanComplete();
- return true;
+ 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;
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index c5efb5581527..b62f557319a8 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -26,10 +26,13 @@
#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/ThreadPlanStepOverRange.h"
+#include "lldb/Target/ThreadPlanStepThrough.h"
using namespace lldb;
using namespace lldb_private;
+uint32_t ThreadPlanStepOut::s_default_flag_values = 0;
+
//----------------------------------------------------------------------
// ThreadPlanStepOut: Step out of the current frame
//----------------------------------------------------------------------
@@ -41,20 +44,21 @@ ThreadPlanStepOut::ThreadPlanStepOut
bool stop_others,
Vote stop_vote,
Vote run_vote,
- uint32_t frame_idx
+ uint32_t frame_idx,
+ LazyBool step_out_avoids_code_without_debug_info
) :
ThreadPlan (ThreadPlan::eKindStepOut, "Step out", thread, stop_vote, run_vote),
- m_step_from_context (context),
+ ThreadPlanShouldStopHere (this),
m_step_from_insn (LLDB_INVALID_ADDRESS),
m_return_bp_id (LLDB_INVALID_BREAK_ID),
m_return_addr (LLDB_INVALID_ADDRESS),
- m_first_insn (first_insn),
m_stop_others (stop_others),
- m_step_through_inline_plan_sp(),
- m_step_out_plan_sp (),
m_immediate_step_from_function(NULL)
{
+ 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));
@@ -77,13 +81,15 @@ ThreadPlanStepOut::ThreadPlanStepOut
{
// 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_plan_sp.reset (new ThreadPlanStepOut(m_thread,
+ m_step_out_to_inline_plan_sp.reset (new ThreadPlanStepOut(m_thread,
NULL,
false,
stop_others,
eVoteNoOpinion,
eVoteNoOpinion,
- frame_idx - 1));
+ frame_idx - 1,
+ eLazyBoolNo));
+ static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);
}
else
{
@@ -123,10 +129,32 @@ ThreadPlanStepOut::ThreadPlanStepOut
}
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);
+}
+
+void
ThreadPlanStepOut::DidPush()
{
- if (m_step_out_plan_sp)
- m_thread.QueueThreadPlan(m_step_out_plan_sp, false);
+ 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);
}
@@ -144,7 +172,7 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
s->Printf ("step out");
else
{
- if (m_step_out_plan_sp)
+ 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.");
@@ -159,8 +187,8 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
bool
ThreadPlanStepOut::ValidatePlan (Stream *error)
{
- if (m_step_out_plan_sp)
- return m_step_out_plan_sp->ValidatePlan (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)
@@ -176,12 +204,18 @@ ThreadPlanStepOut::ValidatePlan (Stream *error)
bool
ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
{
- // If one of our child plans just finished, then we do explain the stop.
- if (m_step_out_plan_sp)
+ // 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)
{
- if (m_step_out_plan_sp->MischiefManaged())
+ if (m_step_out_to_inline_plan_sp->MischiefManaged())
+ return true;
+ else
+ return false;
+ }
+ else if (m_step_through_inline_plan_sp)
+ {
+ if (m_step_through_inline_plan_sp->MischiefManaged())
{
- // If this one is done, then we are all done.
CalculateReturnValue();
SetPlanComplete();
return true;
@@ -189,9 +223,9 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
else
return false;
}
- else if (m_step_through_inline_plan_sp)
+ else if (m_step_out_further_plan_sp)
{
- if (m_step_through_inline_plan_sp->MischiefManaged())
+ if (m_step_out_further_plan_sp->MischiefManaged())
return true;
else
return false;
@@ -234,8 +268,11 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
if (done)
{
- CalculateReturnValue();
- SetPlanComplete();
+ if (InvokeShouldStopHereCallback (eFrameCompareOlder))
+ {
+ CalculateReturnValue();
+ SetPlanComplete();
+ }
}
// If there was only one owner, then we're done. But if we also hit some
@@ -266,61 +303,70 @@ ThreadPlanStepOut::DoPlanExplainsStop (Event *event_ptr)
bool
ThreadPlanStepOut::ShouldStop (Event *event_ptr)
{
- if (IsPlanComplete())
- return true;
-
- bool done;
-
+ 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);
+ }
+
+ if (!done)
+ {
StackID frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
if (frame_zero_id < m_step_out_to_id)
done = false;
else
done = true;
-
- if (done)
+ }
+
+ // 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();
- return true;
}
else
{
- if (m_step_out_plan_sp)
- {
- if (m_step_out_plan_sp->MischiefManaged())
- {
- // Now step through the inlined stack we are in:
- if (QueueInlinedStepPlan(true))
- {
- return false;
- }
- else
- {
- CalculateReturnValue();
- SetPlanComplete ();
- return true;
- }
- }
- else
- return m_step_out_plan_sp->ShouldStop(event_ptr);
- }
- else if (m_step_through_inline_plan_sp)
- {
- if (m_step_through_inline_plan_sp->MischiefManaged())
- {
- // We don't calculate the return value here because we don't know how to.
- // But in case we had a return value sitting around from our process in
- // getting here, let's clear it out.
- m_return_valobj_sp.reset();
- SetPlanComplete();
- return true;
- }
- else
- return m_step_through_inline_plan_sp->ShouldStop(event_ptr);
- }
- else
- return false;
+ m_step_out_further_plan_sp = QueueStepOutFromHerePlan(m_flags, eFrameCompareOlder);
+ done = false;
}
+ }
+
+ return done;
}
bool
@@ -338,7 +384,7 @@ ThreadPlanStepOut::GetPlanRunState ()
bool
ThreadPlanStepOut::DoWillResume (StateType resume_state, bool current_plan)
{
- if (m_step_out_plan_sp || m_step_through_inline_plan_sp)
+ 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)
@@ -427,10 +473,12 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
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;
ThreadPlanStepOverRange *step_through_inline_plan_ptr = new ThreadPlanStepOverRange(m_thread,
inline_range,
inlined_sc,
- run_mode);
+ run_mode,
+ avoid_no_debug);
step_through_inline_plan_ptr->SetOkayToDiscard(true);
StreamString errors;
if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
@@ -486,4 +534,3 @@ ThreadPlanStepOut::IsPlanStale()
else
return true;
}
-
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index 2d8108bf9b77..a4f3743346e2 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -31,6 +31,7 @@
using namespace lldb_private;
using namespace lldb;
+uint32_t ThreadPlanStepOverRange::s_default_flag_values = 0;
//----------------------------------------------------------------------
// ThreadPlanStepOverRange: Step through a stack range, either stepping over or into
@@ -42,11 +43,15 @@ ThreadPlanStepOverRange::ThreadPlanStepOverRange
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others
+ 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 ()
@@ -65,6 +70,32 @@ ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level
}
}
+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)
{
@@ -146,18 +177,21 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
const SymbolContext &older_context = older_frame_sp->GetSymbolContext(eSymbolContextEverything);
if (IsEquivalentContext(older_context))
{
- new_plan_sp = m_thread.QueueThreadPlanForStepOut (false,
- NULL,
- true,
- stop_others,
- eVoteNo,
- eVoteNoOpinion,
- 0);
+ new_plan_sp = m_thread.QueueThreadPlanForStepOutNoShouldStop (false,
+ NULL,
+ true,
+ stop_others,
+ eVoteNo,
+ eVoteNoOpinion,
+ 0);
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;
}
}
}
@@ -277,6 +311,13 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
// 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 (!new_plan_sp)
m_no_more_plans = true;
else
@@ -390,3 +431,4 @@ ThreadPlanStepOverRange::DoWillResume (lldb::StateType resume_state, bool curren
return true;
}
+
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
index 309f773c505b..82ca59fbca39 100644
--- a/source/Target/ThreadPlanStepRange.cpp
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -50,6 +50,7 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
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)
@@ -57,6 +58,9 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
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 ()
@@ -270,7 +274,16 @@ ThreadPlanStepRange::CompareCurrentFrameToStartFrame()
}
else
{
- frame_order = eFrameCompareOlder;
+ 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;
}
@@ -443,8 +456,8 @@ ThreadPlanStepRange::NextRangeBreakpointExplainsStop (lldb::StopInfoSP stop_info
}
}
if (log)
- log->Printf ("ThreadPlanStepRange::NextRangeBreakpointExplainsStop - Hit next range breakpoint which has %zu owners - explains stop: %u.",
- num_owners,
+ 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;
diff --git a/source/Target/ThreadPlanStepUntil.cpp b/source/Target/ThreadPlanStepUntil.cpp
index 62e05c7fe342..fa5ab8c5d491 100644
--- a/source/Target/ThreadPlanStepUntil.cpp
+++ b/source/Target/ThreadPlanStepUntil.cpp
@@ -77,7 +77,7 @@ ThreadPlanStepUntil::ThreadPlanStepUntil
}
}
- m_stack_id = m_thread.GetStackFrameAtIndex(frame_idx)->GetStackID();
+ m_stack_id = frame_sp->GetStackID();
// Now set breakpoints on all our return addresses:
for (size_t i = 0; i < num_addresses; i++)
diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp
index d191170fcc08..5188df6d9193 100644
--- a/source/Target/ThreadPlanTracer.cpp
+++ b/source/Target/ThreadPlanTracer.cpp
@@ -166,17 +166,6 @@ ThreadPlanAssemblyTracer::TracingEnded ()
m_register_values.clear();
}
-static void
-PadOutTo (StreamString &stream, int target)
-{
- stream.Flush();
-
- int length = stream.GetString().length();
-
- if (length + 1 < target)
- stream.Printf("%*s", target - (length + 1) + 1, "");
-}
-
void
ThreadPlanAssemblyTracer::Log ()
{