summaryrefslogtreecommitdiff
path: root/source/Target
diff options
context:
space:
mode:
Diffstat (limited to 'source/Target')
-rw-r--r--source/Target/CPPLanguageRuntime.cpp78
-rw-r--r--source/Target/FileAction.cpp32
-rw-r--r--source/Target/InstrumentationRuntime.cpp48
-rw-r--r--source/Target/InstrumentationRuntimeStopInfo.cpp36
-rw-r--r--source/Target/LanguageRuntime.cpp56
-rw-r--r--source/Target/Memory.cpp19
-rw-r--r--source/Target/MemoryHistory.cpp30
-rw-r--r--source/Target/ObjCLanguageRuntime.cpp8
-rw-r--r--source/Target/Platform.cpp281
-rw-r--r--source/Target/Process.cpp518
-rw-r--r--source/Target/ProcessLaunchInfo.cpp180
-rw-r--r--source/Target/StackFrame.cpp55
-rw-r--r--source/Target/StackFrameList.cpp15
-rw-r--r--source/Target/StopInfo.cpp24
-rw-r--r--source/Target/Target.cpp218
-rw-r--r--source/Target/TargetList.cpp134
-rw-r--r--source/Target/Thread.cpp259
-rw-r--r--source/Target/ThreadCollection.cpp62
-rw-r--r--source/Target/ThreadList.cpp23
-rw-r--r--source/Target/ThreadPlanPython.cpp192
-rw-r--r--source/Target/ThreadPlanStepInRange.cpp30
-rw-r--r--source/Target/ThreadPlanStepInstruction.cpp29
-rw-r--r--source/Target/ThreadPlanStepOut.cpp51
-rw-r--r--source/Target/ThreadPlanStepOverBreakpoint.cpp35
-rw-r--r--source/Target/ThreadPlanStepOverRange.cpp26
-rw-r--r--source/Target/ThreadPlanStepRange.cpp8
-rw-r--r--source/Target/ThreadPlanStepThrough.cpp5
-rw-r--r--source/Target/ThreadPlanTracer.cpp6
28 files changed, 1947 insertions, 511 deletions
diff --git a/source/Target/CPPLanguageRuntime.cpp b/source/Target/CPPLanguageRuntime.cpp
index f5b7f7fc41a63..f048c6706a9b8 100644
--- a/source/Target/CPPLanguageRuntime.cpp
+++ b/source/Target/CPPLanguageRuntime.cpp
@@ -11,6 +11,8 @@
#include <string.h>
+#include "llvm/ADT/StringRef.h"
+
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/UniqueCStringMap.h"
#include "lldb/Target/ExecutionContext.h"
@@ -190,30 +192,17 @@ CPPLanguageRuntime::IsCPPMangledName (const char *name)
}
bool
-CPPLanguageRuntime::StripNamespacesFromVariableName (const char *name, const char *&base_name_start, const char *&base_name_end)
+CPPLanguageRuntime::ExtractContextAndIdentifier (const char *name, llvm::StringRef &context, llvm::StringRef &identifier)
{
- if (base_name_end == NULL)
- base_name_end = name + strlen (name);
-
- const char *last_colon = strrchr (name, ':');
-
- if (last_colon == NULL)
- {
- base_name_start = name;
- return true;
- }
-
- // Can't have a C++ name that begins with a single ':', nor contains an internal single ':'
- if (last_colon == name)
- return false;
- else if (last_colon[-1] != ':')
- return false;
- else
+ static RegularExpression g_basename_regex("^(([A-Za-z_][A-Za-z_0-9]*::)*)([A-Za-z_][A-Za-z_0-9]*)$");
+ RegularExpression::Match match(4);
+ if (g_basename_regex.Execute (name, &match))
{
- // FIXME: should check if there is
- base_name_start = last_colon + 1;
+ match.GetMatchAtIndex(name, 1, context);
+ match.GetMatchAtIndex(name, 3, identifier);
return true;
}
+ return false;
}
uint32_t
@@ -282,6 +271,7 @@ ReverseFindMatchingChars (const llvm::StringRef &s,
return false;
}
+
void
CPPLanguageRuntime::MethodName::Parse()
{
@@ -306,6 +296,7 @@ CPPLanguageRuntime::MethodName::Parse()
if (arg_start > 0)
{
size_t basename_end = arg_start;
+ size_t context_start = 0;
size_t context_end = llvm::StringRef::npos;
if (basename_end > 0 && full[basename_end-1] == '>')
{
@@ -314,16 +305,35 @@ CPPLanguageRuntime::MethodName::Parse()
size_t template_start, template_end;
llvm::StringRef lt_gt("<>", 2);
if (ReverseFindMatchingChars (full, lt_gt, template_start, template_end, basename_end))
+ {
context_end = full.rfind(':', template_start);
+ if (context_end == llvm::StringRef::npos)
+ {
+ // Check for templated functions that include return type like:
+ // 'void foo<Int>()'
+ context_end = full.rfind(' ', template_start);
+ if (context_end != llvm::StringRef::npos)
+ {
+ context_start = context_end;
+ }
+ }
+ }
+ else
+ {
+ context_end = full.rfind(':', basename_end);
+ }
}
- if (context_end == llvm::StringRef::npos)
+ else if (context_end == llvm::StringRef::npos)
+ {
context_end = full.rfind(':', basename_end);
+ }
if (context_end == llvm::StringRef::npos)
m_basename = full.substr(0, basename_end);
else
{
- m_context = full.substr(0, context_end - 1);
+ if (context_start < context_end)
+ m_context = full.substr(context_start, context_end - 1);
const size_t basename_begin = context_end + 1;
m_basename = full.substr(basename_begin, basename_end - basename_begin);
}
@@ -343,6 +353,30 @@ CPPLanguageRuntime::MethodName::Parse()
// printf (" arguments = '%s'\n", m_arguments.str().c_str());
// if (!m_qualifiers.empty())
// printf ("qualifiers = '%s'\n", m_qualifiers.str().c_str());
+
+ // Make sure we have a valid C++ basename with optional template args
+ static RegularExpression g_identifier_regex("^~?([A-Za-z_][A-Za-z_0-9]*)(<.*>)?$");
+ std::string basename_str(m_basename.str());
+ bool basename_is_valid = g_identifier_regex.Execute (basename_str.c_str(), NULL);
+ if (!basename_is_valid)
+ {
+ // Check for C++ operators
+ if (m_basename.startswith("operator"))
+ {
+ static RegularExpression g_operator_regex("^(operator)( ?)([A-Za-z_][A-Za-z_0-9]*|\\(\\)|\\[\\]|[\\^<>=!\\/*+-]+)(<.*>)?(\\[\\])?$");
+ basename_is_valid = g_operator_regex.Execute(basename_str.c_str(), NULL);
+ }
+ }
+ if (!basename_is_valid)
+ {
+ // The C++ basename doesn't match our regular expressions so this can't
+ // be a valid C++ method, clear everything out and indicate an error
+ m_context = llvm::StringRef();
+ m_basename = llvm::StringRef();
+ m_arguments = llvm::StringRef();
+ m_qualifiers = llvm::StringRef();
+ m_parse_error = true;
+ }
}
else
{
diff --git a/source/Target/FileAction.cpp b/source/Target/FileAction.cpp
index 18b039998bc70..8611ff5f2d2cc 100644
--- a/source/Target/FileAction.cpp
+++ b/source/Target/FileAction.cpp
@@ -13,6 +13,7 @@
#include "lldb/Host/Windows/win32.h" // For O_NOCTTY
#endif
+#include "lldb/Core/Stream.h"
#include "lldb/Target/FileAction.h"
using namespace lldb_private;
@@ -21,11 +22,11 @@ using namespace lldb_private;
// FileAction member functions
//----------------------------------------------------------------------------
-FileAction::FileAction()
- : m_action(eFileActionNone)
- , m_fd(-1)
- , m_arg(-1)
- , m_path()
+FileAction::FileAction() :
+ m_action(eFileActionNone),
+ m_fd(-1),
+ m_arg(-1),
+ m_path()
{
}
@@ -93,3 +94,24 @@ FileAction::Duplicate(int fd, int dup_fd)
}
return m_fd >= 0;
}
+
+void
+FileAction::Dump(Stream &stream) const
+{
+ stream.PutCString("file action: ");
+ switch (m_action)
+ {
+ case eFileActionClose:
+ stream.Printf("close fd %d", m_fd);
+ break;
+ case eFileActionDuplicate:
+ stream.Printf("duplicate fd %d to %d", m_fd, m_arg);
+ break;
+ case eFileActionNone:
+ stream.PutCString("no action");
+ break;
+ case eFileActionOpen:
+ stream.Printf("open fd %d with '%s', OFLAGS = 0x%x", m_fd, m_path.c_str(), m_arg);
+ break;
+ }
+}
diff --git a/source/Target/InstrumentationRuntime.cpp b/source/Target/InstrumentationRuntime.cpp
new file mode 100644
index 0000000000000..b3b2393b02346
--- /dev/null
+++ b/source/Target/InstrumentationRuntime.cpp
@@ -0,0 +1,48 @@
+//===-- InstrumentationRuntime.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/Process.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+void
+InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list, lldb_private::Process *process, InstrumentationRuntimeCollection &runtimes)
+{
+ InstrumentationRuntimeCreateInstance create_callback = NULL;
+ InstrumentationRuntimeGetType get_type_callback;
+ for (uint32_t idx = 0; ; ++idx)
+ {
+ create_callback = PluginManager::GetInstrumentationRuntimeCreateCallbackAtIndex(idx);
+ if (create_callback == NULL)
+ break;
+ get_type_callback = PluginManager::GetInstrumentationRuntimeGetTypeCallbackAtIndex(idx);
+ InstrumentationRuntimeType type = get_type_callback();
+
+ InstrumentationRuntimeCollection::iterator pos;
+ pos = runtimes.find (type);
+ if (pos == runtimes.end()) {
+ runtimes[type] = create_callback(process->shared_from_this());
+ }
+ }
+}
+
+void
+InstrumentationRuntime::ModulesDidLoad(lldb_private::ModuleList &module_list)
+{
+}
+
+bool
+InstrumentationRuntime::IsActive()
+{
+ return false;
+}
diff --git a/source/Target/InstrumentationRuntimeStopInfo.cpp b/source/Target/InstrumentationRuntimeStopInfo.cpp
new file mode 100644
index 0000000000000..cdbf93b5f7209
--- /dev/null
+++ b/source/Target/InstrumentationRuntimeStopInfo.cpp
@@ -0,0 +1,36 @@
+//===-- InstrumentationRuntimeStopInfo.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/InstrumentationRuntimeStopInfo.h"
+
+#include "lldb/lldb-private.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/InstrumentationRuntime.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+InstrumentationRuntimeStopInfo::InstrumentationRuntimeStopInfo(Thread &thread, std::string description, StructuredData::ObjectSP additional_data) :
+ StopInfo(thread, 0)
+{
+ m_extended_info = additional_data;
+ m_description = description;
+}
+
+const char *
+InstrumentationRuntimeStopInfo::GetDescription ()
+{
+ return m_description.c_str();
+}
+
+StopInfoSP
+InstrumentationRuntimeStopInfo::CreateStopReasonWithInstrumentationData (Thread &thread, std::string description, StructuredData::ObjectSP additionalData)
+{
+ return StopInfoSP(new InstrumentationRuntimeStopInfo(thread, description, additionalData));
+}
diff --git a/source/Target/LanguageRuntime.cpp b/source/Target/LanguageRuntime.cpp
index 9d48d8b2de7f4..358bffee3a4d4 100644
--- a/source/Target/LanguageRuntime.cpp
+++ b/source/Target/LanguageRuntime.cpp
@@ -10,6 +10,7 @@
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/Target.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Core/SearchFilter.h"
using namespace lldb;
using namespace lldb_private;
@@ -19,17 +20,22 @@ class ExceptionSearchFilter : public SearchFilter
{
public:
ExceptionSearchFilter (const lldb::TargetSP &target_sp,
- lldb::LanguageType language) :
+ lldb::LanguageType language,
+ bool update_module_list = true) :
SearchFilter (target_sp),
m_language (language),
m_language_runtime (NULL),
m_filter_sp ()
{
- UpdateModuleListIfNeeded ();
+ if (update_module_list)
+ UpdateModuleListIfNeeded ();
}
-
- virtual bool
- ModulePasses (const lldb::ModuleSP &module_sp)
+
+ virtual
+ ~ExceptionSearchFilter() {};
+
+ bool
+ ModulePasses (const lldb::ModuleSP &module_sp) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
@@ -37,8 +43,8 @@ public:
return false;
}
- virtual bool
- ModulePasses (const FileSpec &spec)
+ bool
+ ModulePasses (const FileSpec &spec) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
@@ -47,16 +53,16 @@ public:
}
- virtual void
- Search (Searcher &searcher)
+ void
+ Search (Searcher &searcher) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
m_filter_sp->Search (searcher);
}
- virtual void
- GetDescription (Stream *s)
+ void
+ GetDescription (Stream *s) override
{
UpdateModuleListIfNeeded ();
if (m_filter_sp)
@@ -68,6 +74,12 @@ protected:
LanguageRuntime *m_language_runtime;
SearchFilterSP m_filter_sp;
+ SearchFilterSP
+ DoCopyForBreakpoint(Breakpoint &breakpoint) override
+ {
+ return SearchFilterSP(new ExceptionSearchFilter(TargetSP(), m_language, false));
+ }
+
void
UpdateModuleListIfNeeded ()
{
@@ -124,11 +136,11 @@ public:
{
}
- virtual Searcher::CallbackReturn
+ Searcher::CallbackReturn
SearchCallback (SearchFilter &filter,
SymbolContext &context,
Address *addr,
- bool containing)
+ bool containing) override
{
if (SetActualResolver())
@@ -137,8 +149,8 @@ public:
return eCallbackReturnStop;
}
- virtual Searcher::Depth
- GetDepth ()
+ Searcher::Depth
+ GetDepth () override
{
if (SetActualResolver())
return m_actual_resolver_sp->GetDepth();
@@ -146,8 +158,8 @@ public:
return eDepthTarget;
}
- virtual void
- GetDescription (Stream *s)
+ void
+ GetDescription (Stream *s) override
{
s->Printf ("Exception breakpoint (catch: %s throw: %s)",
m_catch_bp ? "on" : "off",
@@ -163,8 +175,8 @@ public:
s->Printf (" the correct runtime exception handler will be determined when you run");
}
- virtual void
- Dump (Stream *s) const
+ void
+ Dump (Stream *s) const override
{
}
@@ -174,6 +186,12 @@ public:
return V->getResolverID() == BreakpointResolver::ExceptionResolver;
}
protected:
+ BreakpointResolverSP
+ CopyForBreakpoint (Breakpoint &breakpoint) override
+ {
+ return BreakpointResolverSP(new ExceptionBreakpointResolver(m_language, m_catch_bp, m_throw_bp));
+ }
+
bool
SetActualResolver()
{
diff --git a/source/Target/Memory.cpp b/source/Target/Memory.cpp
index b212fcd23a453..934bc967b68b6 100644
--- a/source/Target/Memory.cpp
+++ b/source/Target/Memory.cpp
@@ -26,7 +26,7 @@ using namespace lldb_private;
//----------------------------------------------------------------------
MemoryCache::MemoryCache(Process &process) :
m_process (process),
- m_cache_line_byte_size (512),
+ m_cache_line_byte_size (process.GetMemoryCacheLineSize()),
m_mutex (Mutex::eMutexTypeRecursive),
m_cache (),
m_invalid_ranges ()
@@ -47,6 +47,7 @@ MemoryCache::Clear(bool clear_invalid_ranges)
m_cache.clear();
if (clear_invalid_ranges)
m_invalid_ranges.Clear();
+ m_cache_line_byte_size = m_process.GetMemoryCacheLineSize();
}
void
@@ -250,7 +251,8 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[0] = needed_chunks;
if (log)
- log->Printf ("[1] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks", this, 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", (void *)this,
+ size, size, 0, needed_chunks, m_chunk_size);
addr = m_addr;
}
else
@@ -268,7 +270,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
+ log->Printf("[2] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - "
+ "num_chunks %lu",
+ (void *)this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -284,7 +288,9 @@ AllocatedBlock::ReserveBlock (uint32_t size)
{
m_offset_to_chunk_size[last_offset] = needed_chunks;
if (log)
- log->Printf ("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - num_chunks %lu", this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
+ log->Printf("[3] AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => offset = 0x%x, %u %u bit chunks - "
+ "num_chunks %lu",
+ (void *)this, size, size, last_offset, needed_chunks, m_chunk_size, m_offset_to_chunk_size.size());
addr = m_addr + last_offset;
break;
}
@@ -345,7 +351,7 @@ AllocatedBlock::ReserveBlock (uint32_t size)
}
if (log)
- log->Printf ("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, this, size, size, (uint64_t)addr);
+ log->Printf("AllocatedBlock::ReserveBlock(%p) (size = %u (0x%x)) => 0x%16.16" PRIx64, (void *)this, size, size, (uint64_t)addr);
return addr;
}
@@ -362,7 +368,8 @@ AllocatedBlock::FreeBlock (addr_t addr)
}
Log *log (GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_VERBOSE));
if (log)
- log->Printf ("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", this, (uint64_t)addr, success, m_offset_to_chunk_size.size());
+ log->Printf("AllocatedBlock::FreeBlock(%p) (addr = 0x%16.16" PRIx64 ") => %i, num_chunks: %lu", (void *)this, (uint64_t)addr,
+ success, m_offset_to_chunk_size.size());
return success;
}
diff --git a/source/Target/MemoryHistory.cpp b/source/Target/MemoryHistory.cpp
new file mode 100644
index 0000000000000..b97096b06d762
--- /dev/null
+++ b/source/Target/MemoryHistory.cpp
@@ -0,0 +1,30 @@
+//===-- MemoryHistory.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/MemoryHistory.h"
+
+#include "lldb/Core/PluginManager.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+lldb::MemoryHistorySP
+MemoryHistory::FindPlugin (const ProcessSP process)
+{
+ MemoryHistoryCreateInstance create_callback = NULL;
+
+ for (uint32_t idx = 0; (create_callback = PluginManager::GetMemoryHistoryCreateCallbackAtIndex(idx)) != NULL; ++idx)
+ {
+ MemoryHistorySP memory_history_sp (create_callback (process));
+ if (memory_history_sp.get())
+ return memory_history_sp;
+ }
+
+ return MemoryHistorySP();
+}
diff --git a/source/Target/ObjCLanguageRuntime.cpp b/source/Target/ObjCLanguageRuntime.cpp
index 1f2abd876c840..b182407bf68ec 100644
--- a/source/Target/ObjCLanguageRuntime.cpp
+++ b/source/Target/ObjCLanguageRuntime.cpp
@@ -603,20 +603,20 @@ ObjCLanguageRuntime::GetNonKVOClassDescriptor (ObjCISA isa)
ClangASTType
-ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool allow_unknownanytype)
+ObjCLanguageRuntime::EncodingToType::RealizeType (const char* name, bool for_expression)
{
if (m_scratch_ast_ctx_ap)
- return RealizeType(*m_scratch_ast_ctx_ap, name, allow_unknownanytype);
+ return RealizeType(*m_scratch_ast_ctx_ap, name, for_expression);
return ClangASTType();
}
ClangASTType
-ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool allow_unknownanytype)
+ObjCLanguageRuntime::EncodingToType::RealizeType (ClangASTContext& ast_ctx, const char* name, bool for_expression)
{
clang::ASTContext *clang_ast = ast_ctx.getASTContext();
if (!clang_ast)
return ClangASTType();
- return RealizeType(*clang_ast, name, allow_unknownanytype);
+ return RealizeType(*clang_ast, name, for_expression);
}
ObjCLanguageRuntime::EncodingToType::~EncodingToType() {}
diff --git a/source/Target/Platform.cpp b/source/Target/Platform.cpp
index fe73be2d05b91..4ebd18b8bfd09 100644
--- a/source/Target/Platform.cpp
+++ b/source/Target/Platform.cpp
@@ -32,26 +32,12 @@ using namespace lldb_private;
// Use a singleton function for g_local_platform_sp to avoid init
// constructors since LLDB is often part of a shared library
static PlatformSP&
-GetDefaultPlatformSP ()
+GetHostPlatformSP ()
{
- static PlatformSP g_default_platform_sp;
- return g_default_platform_sp;
+ static PlatformSP g_platform_sp;
+ return g_platform_sp;
}
-static Mutex &
-GetConnectedPlatformListMutex ()
-{
- static Mutex g_remote_connected_platforms_mutex (Mutex::eMutexTypeRecursive);
- return g_remote_connected_platforms_mutex;
-}
-static std::vector<PlatformSP> &
-GetConnectedPlatformList ()
-{
- static std::vector<PlatformSP> g_remote_connected_platforms;
- return g_remote_connected_platforms;
-}
-
-
const char *
Platform::GetHostPlatformName ()
{
@@ -69,17 +55,37 @@ Platform::GetHostPlatformName ()
/// or attaching to processes unless another platform is specified.
//------------------------------------------------------------------
PlatformSP
-Platform::GetDefaultPlatform ()
+Platform::GetHostPlatform ()
{
- return GetDefaultPlatformSP ();
+ return GetHostPlatformSP ();
+}
+
+static std::vector<PlatformSP> &
+GetPlatformList()
+{
+ static std::vector<PlatformSP> g_platform_list;
+ return g_platform_list;
+}
+
+static Mutex &
+GetPlatformListMutex ()
+{
+ static Mutex g_mutex(Mutex::eMutexTypeRecursive);
+ return g_mutex;
}
void
-Platform::SetDefaultPlatform (const lldb::PlatformSP &platform_sp)
+Platform::SetHostPlatform (const lldb::PlatformSP &platform_sp)
{
// The native platform should use its static void Platform::Initialize()
// function to register itself as the native platform.
- GetDefaultPlatformSP () = platform_sp;
+ GetHostPlatformSP () = platform_sp;
+
+ if (platform_sp)
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
+ }
}
Error
@@ -98,36 +104,36 @@ Platform::LocateExecutableScriptingResources (Target *target, Module &module, St
return FileSpecList();
}
-Platform*
-Platform::FindPlugin (Process *process, const ConstString &plugin_name)
-{
- PlatformCreateInstance create_callback = NULL;
- if (plugin_name)
- {
- create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name);
- if (create_callback)
- {
- ArchSpec arch;
- if (process)
- {
- arch = process->GetTarget().GetArchitecture();
- }
- std::unique_ptr<Platform> instance_ap(create_callback(process, &arch));
- if (instance_ap.get())
- return instance_ap.release();
- }
- }
- else
- {
- for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx)
- {
- std::unique_ptr<Platform> instance_ap(create_callback(process, nullptr));
- if (instance_ap.get())
- return instance_ap.release();
- }
- }
- return NULL;
-}
+//PlatformSP
+//Platform::FindPlugin (Process *process, const ConstString &plugin_name)
+//{
+// PlatformCreateInstance create_callback = NULL;
+// if (plugin_name)
+// {
+// create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (plugin_name);
+// if (create_callback)
+// {
+// ArchSpec arch;
+// if (process)
+// {
+// arch = process->GetTarget().GetArchitecture();
+// }
+// PlatformSP platform_sp(create_callback(process, &arch));
+// if (platform_sp)
+// return platform_sp;
+// }
+// }
+// else
+// {
+// for (uint32_t idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex(idx)) != NULL; ++idx)
+// {
+// PlatformSP platform_sp(create_callback(process, nullptr));
+// if (platform_sp)
+// return platform_sp;
+// }
+// }
+// return PlatformSP();
+//}
Error
Platform::GetSharedModule (const ModuleSpec &module_spec,
@@ -153,21 +159,50 @@ Platform::GetSharedModule (const ModuleSpec &module_spec,
}
PlatformSP
-Platform::Create (const char *platform_name, Error &error)
+Platform::Find (const ConstString &name)
+{
+ if (name)
+ {
+ static ConstString g_host_platform_name ("host");
+ if (name == g_host_platform_name)
+ return GetHostPlatform();
+
+ Mutex::Locker locker(GetPlatformListMutex ());
+ for (const auto &platform_sp : GetPlatformList())
+ {
+ if (platform_sp->GetName() == name)
+ return platform_sp;
+ }
+ }
+ return PlatformSP();
+}
+
+PlatformSP
+Platform::Create (const ConstString &name, Error &error)
{
PlatformCreateInstance create_callback = NULL;
lldb::PlatformSP platform_sp;
- if (platform_name && platform_name[0])
+ if (name)
{
- ConstString const_platform_name (platform_name);
- create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (const_platform_name);
+ static ConstString g_host_platform_name ("host");
+ if (name == g_host_platform_name)
+ return GetHostPlatform();
+
+ create_callback = PluginManager::GetPlatformCreateCallbackForPluginName (name);
if (create_callback)
- platform_sp.reset(create_callback(true, NULL));
+ platform_sp = create_callback(true, NULL);
else
- error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", platform_name);
+ error.SetErrorStringWithFormat ("unable to find a plug-in for the platform named \"%s\"", name.GetCString());
}
else
error.SetErrorString ("invalid platform name");
+
+ if (platform_sp)
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
+ }
+
return platform_sp;
}
@@ -178,28 +213,52 @@ Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &erro
lldb::PlatformSP platform_sp;
if (arch.IsValid())
{
- uint32_t idx;
+ // Scope for locker
+ {
+ // First try exact arch matches across all platforms already created
+ Mutex::Locker locker(GetPlatformListMutex ());
+ for (const auto &platform_sp : GetPlatformList())
+ {
+ if (platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr))
+ return platform_sp;
+ }
+
+ // Next try compatible arch matches across all platforms already created
+ for (const auto &platform_sp : GetPlatformList())
+ {
+ if (platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr))
+ return platform_sp;
+ }
+ }
+
PlatformCreateInstance create_callback;
// First try exact arch matches across all platform plug-ins
- bool exact = true;
+ uint32_t idx;
for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx)
{
if (create_callback)
{
- platform_sp.reset(create_callback(false, &arch));
- if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr))
+ platform_sp = create_callback(false, &arch);
+ if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, true, platform_arch_ptr))
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
return platform_sp;
+ }
}
}
// Next try compatible arch matches across all platform plug-ins
- exact = false;
for (idx = 0; (create_callback = PluginManager::GetPlatformCreateCallbackAtIndex (idx)); ++idx)
{
if (create_callback)
{
- platform_sp.reset(create_callback(false, &arch));
- if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, exact, platform_arch_ptr))
+ platform_sp = create_callback(false, &arch);
+ if (platform_sp && platform_sp->IsCompatibleArchitecture(arch, false, platform_arch_ptr))
+ {
+ Mutex::Locker locker(GetPlatformListMutex ());
+ GetPlatformList().push_back(platform_sp);
return platform_sp;
+ }
}
}
}
@@ -211,25 +270,6 @@ Platform::Create (const ArchSpec &arch, ArchSpec *platform_arch_ptr, Error &erro
return platform_sp;
}
-uint32_t
-Platform::GetNumConnectedRemotePlatforms ()
-{
- Mutex::Locker locker (GetConnectedPlatformListMutex ());
- return GetConnectedPlatformList().size();
-}
-
-PlatformSP
-Platform::GetConnectedRemotePlatformAtIndex (uint32_t idx)
-{
- PlatformSP platform_sp;
- {
- Mutex::Locker locker (GetConnectedPlatformListMutex ());
- if (idx < GetConnectedPlatformList().size())
- platform_sp = GetConnectedPlatformList ()[idx];
- }
- return platform_sp;
-}
-
//------------------------------------------------------------------
/// Default Constructor
//------------------------------------------------------------------
@@ -422,6 +462,20 @@ Platform::GetOSKernelDescription (std::string &s)
return GetRemoteOSKernelDescription (s);
}
+void
+Platform::AddClangModuleCompilationOptions (std::vector<std::string> &options)
+{
+ std::vector<std::string> default_compilation_options =
+ {
+ "-x", "c++", "-Xclang", "-nostdsysteminc", "-Xclang", "-nostdsysteminc"
+ };
+
+ options.insert(options.end(),
+ default_compilation_options.begin(),
+ default_compilation_options.end());
+}
+
+
ConstString
Platform::GetWorkingDirectory ()
{
@@ -537,11 +591,11 @@ 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;
}
+ llvm_unreachable("Unhandled FileSpec::FileType!");
}
Error
@@ -842,15 +896,13 @@ Platform::SetOSVersion (uint32_t major,
Error
-Platform::ResolveExecutable (const FileSpec &exe_file,
- const ArchSpec &exe_arch,
+Platform::ResolveExecutable (const ModuleSpec &module_spec,
lldb::ModuleSP &exe_module_sp,
const FileSpecList *module_search_paths_ptr)
{
Error error;
- if (exe_file.Exists())
+ if (module_spec.GetFileSpec().Exists())
{
- ModuleSpec module_spec (exe_file, exe_arch);
if (module_spec.GetArchitecture().IsValid())
{
error = ModuleList::GetSharedModule (module_spec,
@@ -864,9 +916,10 @@ Platform::ResolveExecutable (const FileSpec &exe_file,
// No valid architecture was specified, ask the platform for
// the architectures that we should be using (in the correct order)
// and see if we can find a match that way
- for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, module_spec.GetArchitecture()); ++idx)
+ ModuleSpec arch_module_spec(module_spec);
+ for (uint32_t idx = 0; GetSupportedArchitectureAtIndex (idx, arch_module_spec.GetArchitecture()); ++idx)
{
- error = ModuleList::GetSharedModule (module_spec,
+ error = ModuleList::GetSharedModule (arch_module_spec,
exe_module_sp,
module_search_paths_ptr,
NULL,
@@ -880,7 +933,7 @@ Platform::ResolveExecutable (const FileSpec &exe_file,
else
{
error.SetErrorStringWithFormat ("'%s' does not exist",
- exe_file.GetPath().c_str());
+ module_spec.GetFileSpec().GetPath().c_str());
}
return error;
}
@@ -1005,7 +1058,11 @@ Error
Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
{
Error error;
- // Take care of the host case so that each subclass can just
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("Platform::%s()", __FUNCTION__);
+
+ // Take care of the host case so that each subclass can just
// call this function to get the host functionality.
if (IsHost())
{
@@ -1018,6 +1075,16 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
const bool will_debug = launch_info.GetFlags().Test(eLaunchFlagDebug);
const bool first_arg_is_full_shell_command = false;
uint32_t num_resumes = GetResumeCountForLaunchInfo (launch_info);
+ if (log)
+ {
+ const FileSpec &shell = launch_info.GetShell();
+ const char *shell_str = (shell) ? shell.GetPath().c_str() : "<null>";
+ log->Printf ("Platform::%s GetResumeCountForLaunchInfo() returned %" PRIu32 ", shell is '%s'",
+ __FUNCTION__,
+ num_resumes,
+ shell_str);
+ }
+
if (!launch_info.ConvertArgumentsForLaunchingInShell (error,
is_localhost,
will_debug,
@@ -1026,6 +1093,9 @@ Platform::LaunchProcess (ProcessLaunchInfo &launch_info)
return error;
}
+ if (log)
+ log->Printf ("Platform::%s final launch_info resume count: %" PRIu32, __FUNCTION__, launch_info.GetResumeCount ());
+
error = Host::LaunchProcess (launch_info);
}
else
@@ -1037,9 +1107,12 @@ lldb::ProcessSP
Platform::DebugProcess (ProcessLaunchInfo &launch_info,
Debugger &debugger,
Target *target, // Can be NULL, if NULL create a new target, else use existing one
- Listener &listener,
Error &error)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PLATFORM));
+ if (log)
+ log->Printf ("Platform::%s entered (target %p)", __FUNCTION__, static_cast<void*>(target));
+
ProcessSP process_sp;
// Make sure we stop at the entry point
launch_info.GetFlags ().Set (eLaunchFlagDebug);
@@ -1051,12 +1124,16 @@ Platform::DebugProcess (ProcessLaunchInfo &launch_info,
error = LaunchProcess (launch_info);
if (error.Success())
{
+ if (log)
+ log->Printf ("Platform::%s LaunchProcess() call succeeded (pid=%" PRIu64 ")", __FUNCTION__, launch_info.GetProcessID ());
if (launch_info.GetProcessID() != LLDB_INVALID_PROCESS_ID)
{
ProcessAttachInfo attach_info (launch_info);
- process_sp = Attach (attach_info, debugger, target, listener, error);
+ process_sp = Attach (attach_info, debugger, target, error);
if (process_sp)
{
+ if (log)
+ log->Printf ("Platform::%s Attach() succeeded, Process plugin: %s", __FUNCTION__, process_sp->GetPluginName ().AsCString ());
launch_info.SetHijackListener(attach_info.GetHijackListener());
// Since we attached to the process, it will think it needs to detach
@@ -1075,8 +1152,24 @@ Platform::DebugProcess (ProcessLaunchInfo &launch_info,
process_sp->SetSTDIOFileDescriptor(pty_fd);
}
}
+ else
+ {
+ if (log)
+ log->Printf ("Platform::%s Attach() failed: %s", __FUNCTION__, error.AsCString ());
+ }
}
+ else
+ {
+ if (log)
+ log->Printf ("Platform::%s LaunchProcess() returned launch_info with invalid process id", __FUNCTION__);
+ }
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Platform::%s LaunchProcess() failed: %s", __FUNCTION__, error.AsCString ());
}
+
return process_sp;
}
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index a1049787d8210..106678da2684e 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -16,22 +16,25 @@
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Event.h"
-#include "lldb/Core/ConnectionFileDescriptor.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
-#include "lldb/Symbol/Symbol.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangUserExpression.h"
-#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Host/Pipe.h"
#include "lldb/Host/Terminal.h"
+#include "lldb/Host/ThreadLauncher.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/MemoryHistory.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -45,6 +48,7 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/InstrumentationRuntime.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
using namespace lldb;
@@ -108,6 +112,7 @@ g_properties[] =
{ "python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, NULL, NULL, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." },
{ "stop-on-sharedlibrary-events" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, stop when a shared library is loaded or unloaded." },
{ "detach-keeps-stopped" , OptionValue::eTypeBoolean, true, false, NULL, NULL, "If true, detach will attempt to keep the process stopped." },
+ { "memory-cache-line-size" , OptionValue::eTypeUInt64, false, 512, NULL, NULL, "The memory cache line size" },
{ NULL , OptionValue::eTypeInvalid, false, 0, NULL, NULL, NULL }
};
@@ -118,14 +123,17 @@ enum {
ePropertyUnwindOnErrorInExpressions,
ePropertyPythonOSPluginPath,
ePropertyStopOnSharedLibraryEvents,
- ePropertyDetachKeepsStopped
+ ePropertyDetachKeepsStopped,
+ ePropertyMemCacheLineSize
};
-ProcessProperties::ProcessProperties (bool is_global) :
- Properties ()
+ProcessProperties::ProcessProperties (lldb_private::Process *process) :
+ Properties (),
+ m_process (process) // Can be NULL for global ProcessProperties
{
- if (is_global)
+ if (process == NULL)
{
+ // Global process properties, set them up one time
m_collection_sp.reset (new ProcessOptionValueProperties(ConstString("process")));
m_collection_sp->Initialize(g_properties);
m_collection_sp->AppendProperty(ConstString("thread"),
@@ -134,13 +142,24 @@ ProcessProperties::ProcessProperties (bool is_global) :
Thread::GetGlobalProperties()->GetValueProperties());
}
else
+ {
m_collection_sp.reset (new ProcessOptionValueProperties(Process::GetGlobalProperties().get()));
+ m_collection_sp->SetValueChangedCallback(ePropertyPythonOSPluginPath, ProcessProperties::OptionValueChangedCallback, this);
+ }
}
ProcessProperties::~ProcessProperties()
{
}
+void
+ProcessProperties::OptionValueChangedCallback (void *baton, OptionValue *option_value)
+{
+ ProcessProperties *properties = (ProcessProperties *)baton;
+ if (properties->m_process)
+ properties->m_process->LoadOperatingSystemPlugin(true);
+}
+
bool
ProcessProperties::GetDisableMemoryCache() const
{
@@ -148,6 +167,13 @@ ProcessProperties::GetDisableMemoryCache() const
return m_collection_sp->GetPropertyAtIndexAsBoolean (NULL, idx, g_properties[idx].default_uint_value != 0);
}
+uint64_t
+ProcessProperties::GetMemoryCacheLineSize() const
+{
+ const uint32_t idx = ePropertyMemCacheLineSize;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64 (NULL, idx, g_properties[idx].default_uint_value);
+}
+
Args
ProcessProperties::GetExtraStartupCommands () const
{
@@ -467,9 +493,9 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'c':
if (option_arg && option_arg[0])
- launch_info.SetShell (option_arg);
+ launch_info.SetShell (FileSpec(option_arg, false));
else
- launch_info.SetShell (LLDB_DEFAULT_SHELL);
+ launch_info.SetShell (HostInfo::GetDefaultShell());
break;
case 'v':
@@ -660,7 +686,7 @@ Process::Process(Target &target, Listener &listener) :
}
Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :
- ProcessProperties (false),
+ ProcessProperties (this),
UserID (LLDB_INVALID_PROCESS_ID),
Broadcaster (&(target.GetDebugger()), "lldb.process"),
m_target (target),
@@ -670,13 +696,13 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_private_state_control_broadcaster (NULL, "lldb.process.internal_state_control_broadcaster"),
m_private_state_listener ("lldb.process.internal_state_listener"),
m_private_state_control_wait(),
- m_private_state_thread (LLDB_INVALID_HOST_THREAD),
m_mod_id (),
m_process_unique_id(0),
m_thread_index_id (0),
m_thread_id_to_index_id_map (),
m_exit_status (-1),
m_exit_string (),
+ m_exit_status_mutex(),
m_thread_mutex (Mutex::eMutexTypeRecursive),
m_thread_list_real (this),
m_thread_list (this),
@@ -706,6 +732,7 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_public_run_lock (),
m_private_run_lock (),
m_currently_handling_event(false),
+ m_stop_info_override_callback (NULL),
m_finalize_called(false),
m_clear_thread_plans_on_stop (false),
m_force_next_event_delivery(false),
@@ -760,6 +787,11 @@ Process::~Process()
if (log)
log->Printf ("%p Process::~Process()", static_cast<void*>(this));
StopPrivateStateThread();
+
+ // ThreadList::Clear() will try to acquire this process's mutex, so
+ // explicitly clear the thread list here to ensure that the mutex
+ // is not destroyed before the thread list.
+ m_thread_list.Clear();
}
const ProcessPropertiesSP &
@@ -767,7 +799,7 @@ Process::GetGlobalProperties()
{
static ProcessPropertiesSP g_settings_sp;
if (!g_settings_sp)
- g_settings_sp.reset (new ProcessProperties (true));
+ g_settings_sp.reset (new ProcessProperties (NULL));
return g_settings_sp;
}
@@ -826,7 +858,9 @@ Process::Finalize()
m_memory_cache.Clear();
m_allocated_memory_cache.Clear();
m_language_runtimes.clear();
+ m_instrumentation_runtimes.clear();
m_next_event_action_ap.reset();
+ m_stop_info_override_callback = NULL;
//#ifdef LLDB_CONFIGURATION_DEBUG
// StreamFile s(stdout, false);
// EventSP event_sp;
@@ -924,7 +958,7 @@ Process::SyncIOHandler (uint64_t timeout_msec)
log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
}
- // reset sync one-shot so it will be ready for next time
+ // reset sync one-shot so it will be ready for next launch
m_iohandler_sync.SetValue(false, eBroadcastNever);
}
@@ -932,7 +966,11 @@ Process::SyncIOHandler (uint64_t timeout_msec)
}
StateType
-Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp_ptr, bool wait_always, Listener *hijack_listener)
+Process::WaitForProcessToStop (const TimeValue *timeout,
+ EventSP *event_sp_ptr,
+ bool wait_always,
+ Listener *hijack_listener,
+ Stream *stream)
{
// We can't just wait for a "stopped" event, because the stopped event may have restarted the target.
// We have to actually check each event, and in the case of a stopped event check the restarted flag
@@ -966,6 +1004,9 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp
if (event_sp_ptr && event_sp)
*event_sp_ptr = event_sp;
+ bool pop_process_io_handler = hijack_listener != NULL;
+ Process::HandleProcessStateChangedEvent (event_sp, stream, pop_process_io_handler);
+
switch (state)
{
case eStateCrashed:
@@ -995,6 +1036,195 @@ Process::WaitForProcessToStop (const TimeValue *timeout, lldb::EventSP *event_sp
return state;
}
+bool
+Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
+ Stream *stream,
+ bool &pop_process_io_handler)
+{
+ const bool handle_pop = pop_process_io_handler == true;
+
+ pop_process_io_handler = false;
+ ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
+
+ if (!process_sp)
+ return false;
+
+ StateType event_state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+ if (event_state == eStateInvalid)
+ return false;
+
+ switch (event_state)
+ {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStepping:
+ case eStateDetached:
+ {
+ if (stream)
+ stream->Printf ("Process %" PRIu64 " %s\n",
+ process_sp->GetID(),
+ StateAsCString (event_state));
+
+ if (event_state == eStateDetached)
+ pop_process_io_handler = true;
+ }
+ break;
+
+ case eStateConnected:
+ case eStateRunning:
+ // Don't be chatty when we run...
+ break;
+
+ case eStateExited:
+ if (stream)
+ process_sp->GetStatus(*stream);
+ pop_process_io_handler = true;
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ // Make sure the program hasn't been auto-restarted:
+ if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
+ {
+ if (stream)
+ {
+ size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
+ if (num_reasons > 0)
+ {
+ // FIXME: Do we want to report this, or would that just be annoyingly chatty?
+ if (num_reasons == 1)
+ {
+ const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
+ stream->Printf ("Process %" PRIu64 " stopped and restarted: %s\n",
+ process_sp->GetID(),
+ reason ? reason : "<UNKNOWN REASON>");
+ }
+ else
+ {
+ stream->Printf ("Process %" PRIu64 " stopped and restarted, reasons:\n",
+ process_sp->GetID());
+
+
+ for (size_t i = 0; i < num_reasons; i++)
+ {
+ const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
+ stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
+ }
+ }
+ }
+ }
+ }
+ else
+ {
+ // Lock the thread list so it doesn't change on us, this is the scope for the locker:
+ {
+ ThreadList &thread_list = process_sp->GetThreadList();
+ Mutex::Locker locker (thread_list.GetMutex());
+
+ ThreadSP curr_thread (thread_list.GetSelectedThread());
+ ThreadSP thread;
+ StopReason curr_thread_stop_reason = eStopReasonInvalid;
+ if (curr_thread)
+ curr_thread_stop_reason = curr_thread->GetStopReason();
+ if (!curr_thread ||
+ !curr_thread->IsValid() ||
+ curr_thread_stop_reason == eStopReasonInvalid ||
+ curr_thread_stop_reason == eStopReasonNone)
+ {
+ // Prefer a thread that has just completed its plan over another thread as current thread.
+ ThreadSP plan_thread;
+ ThreadSP other_thread;
+ const size_t num_threads = thread_list.GetSize();
+ size_t i;
+ for (i = 0; i < num_threads; ++i)
+ {
+ thread = thread_list.GetThreadAtIndex(i);
+ StopReason thread_stop_reason = thread->GetStopReason();
+ switch (thread_stop_reason)
+ {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ break;
+
+ case eStopReasonTrace:
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonSignal:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ case eStopReasonInstrumentation:
+ if (!other_thread)
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (!plan_thread)
+ plan_thread = thread;
+ break;
+ }
+ }
+ if (plan_thread)
+ thread_list.SetSelectedThreadByID (plan_thread->GetID());
+ else if (other_thread)
+ thread_list.SetSelectedThreadByID (other_thread->GetID());
+ else
+ {
+ if (curr_thread && curr_thread->IsValid())
+ thread = curr_thread;
+ else
+ thread = thread_list.GetThreadAtIndex(0);
+
+ if (thread)
+ thread_list.SetSelectedThreadByID (thread->GetID());
+ }
+ }
+ }
+ // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
+ // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
+ // have a hard time restarting the process.
+ if (stream)
+ {
+ Debugger &debugger = process_sp->GetTarget().GetDebugger();
+ if (debugger.GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
+ {
+ const bool only_threads_with_stop_reason = true;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 1;
+ const uint32_t num_frames_with_source = 1;
+ process_sp->GetStatus(*stream);
+ process_sp->GetThreadStatus (*stream,
+ only_threads_with_stop_reason,
+ start_frame,
+ num_frames,
+ num_frames_with_source);
+ }
+ else
+ {
+ uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
+ if (target_idx != UINT32_MAX)
+ stream->Printf ("Target %d: (", target_idx);
+ else
+ stream->Printf ("Target <unknown index>: (");
+ process_sp->GetTarget().Dump (stream, eDescriptionLevelBrief);
+ stream->Printf (") stopped.\n");
+ }
+ }
+
+ // Pop the process IO handler
+ pop_process_io_handler = true;
+ }
+ break;
+ }
+
+ if (handle_pop && pop_process_io_handler)
+ process_sp->PopProcessIOHandler();
+
+ return true;
+}
+
StateType
Process::WaitForState
@@ -1170,6 +1400,8 @@ Process::IsRunning () const
int
Process::GetExitStatus ()
{
+ Mutex::Locker locker (m_exit_status_mutex);
+
if (m_public_state.GetValue() == eStateExited)
return m_exit_status;
return -1;
@@ -1179,6 +1411,8 @@ Process::GetExitStatus ()
const char *
Process::GetExitDescription ()
{
+ Mutex::Locker locker (m_exit_status_mutex);
+
if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty())
return m_exit_string.c_str();
return NULL;
@@ -1203,11 +1437,16 @@ Process::SetExitStatus (int status, const char *cstr)
return false;
}
- m_exit_status = status;
- if (cstr)
- m_exit_string = cstr;
- else
- m_exit_string.clear();
+ // use a mutex to protect the status and string during updating
+ {
+ Mutex::Locker locker (m_exit_status_mutex);
+
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+ }
DidExit ();
@@ -1392,6 +1631,17 @@ Process::GetState()
return m_public_state.GetValue ();
}
+bool
+Process::StateChangedIsExternallyHijacked()
+{
+ if (IsHijackedForEvent(eBroadcastBitStateChanged))
+ {
+ if (strcmp(m_hijacking_listeners.back()->GetName(), "lldb.Process.ResumeSynchronous.hijack"))
+ return true;
+ }
+ return false;
+}
+
void
Process::SetPublicState (StateType new_state, bool restarted)
{
@@ -1404,7 +1654,7 @@ Process::SetPublicState (StateType new_state, bool restarted)
// On the transition from Run to Stopped, we unlock the writer end of the
// run lock. The lock gets locked in Resume, which is the public API
// to tell the program to run.
- if (!IsHijackedForEvent(eBroadcastBitStateChanged))
+ if (!StateChangedIsExternallyHijacked())
{
if (new_state == eStateDetached)
{
@@ -1445,6 +1695,36 @@ Process::Resume ()
return PrivateResume();
}
+Error
+Process::ResumeSynchronous (Stream *stream)
+{
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::ResumeSynchronous -- locking run lock");
+ if (!m_public_run_lock.TrySetRunning())
+ {
+ Error error("Resume request failed - process still running.");
+ if (log)
+ log->Printf ("Process::Resume: -- TrySetRunning failed, not resuming.");
+ return error;
+ }
+
+ ListenerSP listener_sp (new Listener("lldb.Process.ResumeSynchronous.hijack"));
+ HijackProcessEvents(listener_sp.get());
+
+ Error error = PrivateResume();
+
+ StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), stream);
+
+ // Undo the hijacking of process events...
+ RestoreProcessEvents();
+
+ if (error.Success() && !StateIsStoppedState(state, false))
+ error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state));
+
+ return error;
+}
+
StateType
Process::GetPrivateState ()
{
@@ -1617,12 +1897,17 @@ Process::LoadImage (const FileSpec &image_spec, Error &error)
{
if (error_str_sp->IsCStringContainer(true))
{
- StreamString s;
- size_t num_chars = error_str_sp->ReadPointedString (s, error);
+ DataBufferSP buffer_sp(new DataBufferHeap(10240,0));
+ size_t num_chars = error_str_sp->ReadPointedString (buffer_sp, error, 10240);
if (error.Success() && num_chars > 0)
{
error.Clear();
- error.SetErrorStringWithFormat("dlopen error: %s", s.GetData());
+ error.SetErrorStringWithFormat("dlopen error: %s", buffer_sp->GetBytes());
+ }
+ else
+ {
+ error.Clear();
+ error.SetErrorStringWithFormat("dlopen failed for unknown reasons.");
}
}
}
@@ -2507,10 +2792,10 @@ Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
});
if (bytes_written < size)
- bytes_written += WriteMemoryPrivate (addr + bytes_written,
- ubuf + bytes_written,
- size - bytes_written,
- error);
+ WriteMemoryPrivate (addr + bytes_written,
+ ubuf + bytes_written,
+ size - bytes_written,
+ error);
}
}
else
@@ -2722,6 +3007,16 @@ Process::WaitForProcessStopPrivate (const TimeValue *timeout, EventSP &event_sp)
return state;
}
+void
+Process::LoadOperatingSystemPlugin(bool flush)
+{
+ if (flush)
+ m_thread_list.Clear();
+ m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
+ if (flush)
+ Flush();
+}
+
Error
Process::Launch (ProcessLaunchInfo &launch_info)
{
@@ -2732,6 +3027,7 @@ Process::Launch (ProcessLaunchInfo &launch_info)
m_system_runtime_ap.reset();
m_os_ap.reset();
m_process_input_reader.reset();
+ m_stop_info_override_callback = NULL;
Module *exe_module = m_target.GetExecutableModulePointer();
if (exe_module)
@@ -2811,15 +3107,20 @@ Process::Launch (ProcessLaunchInfo &launch_info)
if (system_runtime)
system_runtime->DidLaunch();
- m_os_ap.reset (OperatingSystem::FindPlugin (this, NULL));
- // This delays passing the stopped event to listeners till DidLaunch gets
- // a chance to complete...
- HandlePrivateEvent (event_sp);
+ LoadOperatingSystemPlugin(false);
+
+ // Note, the stop event was consumed above, but not handled. This was done
+ // to give DidLaunch a chance to run. The target is either stopped or crashed.
+ // Directly set the state. This is done to prevent a stop message with a bunch
+ // of spurious output on thread status, as well as not pop a ProcessIOHandler.
+ SetPublicState(state, false);
if (PrivateStateThreadIsValid ())
ResumePrivateStateThread ();
else
StartPrivateStateThread ();
+
+ m_stop_info_override_callback = GetTarget().GetArchitecture().GetStopInfoOverrideCallback();
}
else if (state == eStateExited)
{
@@ -2979,6 +3280,15 @@ Process::AttachCompletionHandler::GetExitString ()
return m_exit_string.c_str();
}
+Listener &
+ProcessAttachInfo::GetListenerForProcess (Debugger &debugger)
+{
+ if (m_listener_sp)
+ return *m_listener_sp;
+ else
+ return debugger.GetListener();
+}
+
Error
Process::Attach (ProcessAttachInfo &attach_info)
{
@@ -2988,6 +3298,7 @@ Process::Attach (ProcessAttachInfo &attach_info)
m_jit_loaders_ap.reset();
m_system_runtime_ap.reset();
m_os_ap.reset();
+ m_stop_info_override_callback = NULL;
lldb::pid_t attach_pid = attach_info.GetProcessID();
Error error;
@@ -3115,14 +3426,13 @@ Process::Attach (ProcessAttachInfo &attach_info)
else
{
if (GetID() != LLDB_INVALID_PROCESS_ID)
- {
SetID (LLDB_INVALID_PROCESS_ID);
- const char *error_string = error.AsCString();
- if (error_string == NULL)
- error_string = "attach failed";
- SetExitStatus(-1, error_string);
- }
+ const char *error_string = error.AsCString();
+ if (error_string == NULL)
+ error_string = "attach failed";
+
+ SetExitStatus(-1, error_string);
}
}
}
@@ -3246,6 +3556,8 @@ Process::CompleteAttach ()
exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>");
}
}
+
+ m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback();
}
Error
@@ -3823,26 +4135,25 @@ Process::StartPrivateStateThread (bool force)
// events make it to clients (into the DCProcess event queue).
char thread_name[1024];
- if (Host::MAX_THREAD_NAME_LENGTH <= 16)
+ if (HostInfo::GetMaxThreadNameLength() <= 30)
{
- // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
- if (already_running)
- snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
- else
- snprintf(thread_name, sizeof(thread_name), "intern-state");
+ // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
+ else
+ snprintf(thread_name, sizeof(thread_name), "intern-state");
}
else
{
if (already_running)
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
+ 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());
+ 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);
- if (success)
+ m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, this, NULL);
+ if (m_private_state_thread.IsJoinable())
{
ResumePrivateStateThread();
return true;
@@ -3891,8 +4202,8 @@ Process::ControlPrivateStateThread (uint32_t signal)
// Signal the private state thread. First we should copy this is case the
// thread starts exiting since the private state thread will NULL this out
// when it exits
- const lldb::thread_t private_state_thread = m_private_state_thread;
- if (IS_VALID_LLDB_HOST_THREAD(private_state_thread))
+ HostThread private_state_thread(m_private_state_thread);
+ if (private_state_thread.IsJoinable())
{
TimeValue timeout_time;
bool timed_out;
@@ -3910,8 +4221,7 @@ Process::ControlPrivateStateThread (uint32_t signal)
{
if (timed_out)
{
- Error error;
- Host::ThreadCancel (private_state_thread, &error);
+ Error error = private_state_thread.Cancel();
if (log)
log->Printf ("Timed out responding to the control event, cancel got error: \"%s\".", error.AsCString());
}
@@ -3922,8 +4232,8 @@ Process::ControlPrivateStateThread (uint32_t signal)
}
thread_result_t result = NULL;
- Host::ThreadJoin (private_state_thread, &result, NULL);
- m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ private_state_thread.Join(&result);
+ m_private_state_thread.Reset();
}
}
else
@@ -4005,7 +4315,8 @@ Process::HandlePrivateEvent (EventSP &event_sp)
{
// Only push the input handler if we aren't fowarding events,
// as this means the curses GUI is in use...
- if (!GetTarget().GetDebugger().IsForwardingEvents())
+ // Or don't push it if we are launching since it will come up stopped.
+ if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching)
PushProcessIOHandler ();
m_iohandler_sync.SetValue(true, eBroadcastAlways);
}
@@ -4167,7 +4478,7 @@ Process::RunPrivateStateThread ()
m_public_run_lock.SetStopped();
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
- m_private_state_thread = LLDB_INVALID_HOST_THREAD;
+ m_private_state_thread.Reset();
return NULL;
}
@@ -4621,7 +4932,7 @@ class IOHandlerProcessSTDIO :
public:
IOHandlerProcessSTDIO (Process *process,
int write_fd) :
- IOHandler(process->GetTarget().GetDebugger()),
+ IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO),
m_process (process),
m_read_file (),
m_write_file (write_fd, false),
@@ -4639,9 +4950,10 @@ public:
bool
OpenPipes ()
{
- if (m_pipe.IsValid())
+ if (m_pipe.CanRead() && m_pipe.CanWrite())
return true;
- return m_pipe.Open();
+ Error result = m_pipe.CreateNew(false);
+ return result.Success();
}
void
@@ -4702,8 +5014,10 @@ public:
}
if (FD_ISSET (pipe_read_fd, &read_fdset))
{
+ size_t bytes_read;
// Consume the interrupt byte
- if (m_pipe.Read (&ch, 1) == 1)
+ Error error = m_pipe.Read(&ch, 1, bytes_read);
+ if (error.Success())
{
switch (ch)
{
@@ -4751,7 +5065,8 @@ public:
Cancel ()
{
char ch = 'q'; // Send 'q' for quit
- m_pipe.Write (&ch, 1);
+ size_t bytes_written = 0;
+ m_pipe.Write(&ch, 1, bytes_written);
}
virtual bool
@@ -4765,7 +5080,9 @@ public:
if (m_active)
{
char ch = 'i'; // Send 'i' for interrupt
- return m_pipe.Write (&ch, 1) == 1;
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write(&ch, 1, bytes_written);
+ return result.Success();
}
else
{
@@ -4944,12 +5261,12 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
selected_tid = LLDB_INVALID_THREAD_ID;
}
- lldb::thread_t backup_private_state_thread = LLDB_INVALID_HOST_THREAD;
- lldb::StateType old_state;
+ HostThread backup_private_state_thread;
+ lldb::StateType old_state = eStateInvalid;
lldb::ThreadPlanSP stopper_base_plan_sp;
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
- if (Host::GetCurrentThread() == m_private_state_thread)
+ if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
{
// Yikes, we are running on the private state thread! So we can't wait for public events on this thread, since
// we are the thread that is generating public events.
@@ -5554,7 +5871,7 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
} // 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))
+ if (backup_private_state_thread.IsJoinable())
{
StopPrivateStateThread();
Error error;
@@ -5563,8 +5880,8 @@ Process::RunThreadPlan (ExecutionContext &exe_ctx,
{
thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp);
}
- m_public_state.SetValueNoLock(old_state);
-
+ if (old_state != eStateInvalid)
+ 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
@@ -5848,21 +6165,21 @@ Process::GetThreadStatus (Stream &strm,
// ID's, and look them up one by one:
uint32_t num_threads;
- std::vector<uint32_t> thread_index_array;
+ std::vector<lldb::tid_t> thread_id_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);
+ thread_id_array.resize(num_threads);
for (idx = 0; idx < num_threads; ++idx)
- thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
+ thread_id_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
}
for (uint32_t i = 0; i < num_threads; i++)
{
- ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_index_array[i]));
+ ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_id_array[i]));
if (thread_sp)
{
if (only_threads_with_stop_reason)
@@ -5915,7 +6232,8 @@ Process::RunPreResumeActions ()
struct PreResumeCallbackAndBaton action = m_pre_resume_actions.back();
m_pre_resume_actions.pop_back();
bool this_result = action.callback (action.baton);
- if (result == true) result = this_result;
+ if (result == true)
+ result = this_result;
}
return result;
}
@@ -5955,8 +6273,10 @@ Process::DidExec ()
m_image_tokens.clear();
m_allocated_memory_cache.Clear();
m_language_runtimes.clear();
+ m_instrumentation_runtimes.clear();
m_thread_list.DiscardThreadPlans();
m_memory_cache.Clear(true);
+ m_stop_info_override_callback = NULL;
DoDidExec();
CompleteAttach ();
// Flush the process (threads and all stack frames) after running CompleteAttach()
@@ -6005,11 +6325,51 @@ Process::ResolveIndirectFunction(const Address *address, Error &error)
void
Process::ModulesDidLoad (ModuleList &module_list)
{
- SystemRuntime *sys_runtime = GetSystemRuntime();
- if (sys_runtime)
- {
- sys_runtime->ModulesDidLoad (module_list);
- }
+ SystemRuntime *sys_runtime = GetSystemRuntime();
+ if (sys_runtime)
+ {
+ sys_runtime->ModulesDidLoad (module_list);
+ }
+
+ GetJITLoaders().ModulesDidLoad (module_list);
+
+ // Give runtimes a chance to be created.
+ InstrumentationRuntime::ModulesDidLoad(module_list, this, m_instrumentation_runtimes);
+
+ // Tell runtimes about new modules.
+ for (auto pos = m_instrumentation_runtimes.begin(); pos != m_instrumentation_runtimes.end(); ++pos)
+ {
+ InstrumentationRuntimeSP runtime = pos->second;
+ runtime->ModulesDidLoad(module_list);
+ }
+
+}
+
+ThreadCollectionSP
+Process::GetHistoryThreads(lldb::addr_t addr)
+{
+ ThreadCollectionSP threads;
+
+ const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(shared_from_this());
+
+ if (! memory_history.get()) {
+ return threads;
+ }
+
+ threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr)));
+
+ return threads;
+}
- GetJITLoaders().ModulesDidLoad (module_list);
+InstrumentationRuntimeSP
+Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type)
+{
+ InstrumentationRuntimeCollection::iterator pos;
+ pos = m_instrumentation_runtimes.find (type);
+ if (pos == m_instrumentation_runtimes.end())
+ {
+ return InstrumentationRuntimeSP();
+ }
+ else
+ return (*pos).second;
}
diff --git a/source/Target/ProcessLaunchInfo.cpp b/source/Target/ProcessLaunchInfo.cpp
index 830f1470ed98f..451c42d18bfa3 100644
--- a/source/Target/ProcessLaunchInfo.cpp
+++ b/source/Target/ProcessLaunchInfo.cpp
@@ -9,10 +9,8 @@
#include "lldb/Host/Config.h"
-#ifndef LLDB_DISABLE_POSIX
-#include <spawn.h>
-#endif
-
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
#include "lldb/Target/ProcessLaunchInfo.h"
#include "lldb/Target/FileAction.h"
#include "lldb/Target/Target.h"
@@ -28,32 +26,32 @@ ProcessLaunchInfo::ProcessLaunchInfo () :
ProcessInfo(),
m_working_dir (),
m_plugin_name (),
- m_shell (),
m_flags (0),
m_file_actions (),
- m_pty (),
+ m_pty (new lldb_utility::PseudoTerminal),
m_resume_count (0),
m_monitor_callback (NULL),
m_monitor_callback_baton (NULL),
m_monitor_signals (false),
+ m_listener_sp (),
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()
+ const char *working_directory, uint32_t launch_flags) :
+ ProcessInfo(),
+ m_working_dir(),
+ m_plugin_name(),
+ m_flags(launch_flags),
+ m_file_actions(),
+ m_pty(new lldb_utility::PseudoTerminal),
+ m_resume_count(0),
+ m_monitor_callback(NULL),
+ m_monitor_callback_baton(NULL),
+ m_monitor_signals(false),
+ m_listener_sp (),
+ m_hijack_listener_sp()
{
if (stdin_path)
{
@@ -184,27 +182,23 @@ ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
m_plugin_name.clear();
}
-const char *
+const FileSpec &
ProcessLaunchInfo::GetShell () const
{
- if (m_shell.empty())
- return NULL;
- return m_shell.c_str();
+ return m_shell;
}
void
-ProcessLaunchInfo::SetShell (const char * path)
+ProcessLaunchInfo::SetShell (const FileSpec &shell)
{
- if (path && path[0])
+ m_shell = shell;
+ if (m_shell)
{
- m_shell.assign (path);
+ m_shell.ResolveExecutableLocation();
m_flags.Set (lldb::eLaunchFlagLaunchInShell);
}
else
- {
- m_shell.clear();
m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
- }
}
void
@@ -223,10 +217,11 @@ ProcessLaunchInfo::Clear ()
ProcessInfo::Clear();
m_working_dir.clear();
m_plugin_name.clear();
- m_shell.clear();
+ m_shell.Clear();
m_flags.Clear();
m_file_actions.clear();
m_resume_count = 0;
+ m_listener_sp.reset();
m_hijack_listener_sp.reset();
}
@@ -266,13 +261,23 @@ ProcessLaunchInfo::SetDetachOnError (bool enable)
void
ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+
// If nothing for stdin or stdout or stderr was specified, then check the process for any default
// settings that were set with "settings set"
- if (GetFileActionForFD(STDIN_FILENO) == NULL || GetFileActionForFD(STDOUT_FILENO) == NULL ||
+ if (GetFileActionForFD(STDIN_FILENO) == NULL ||
+ GetFileActionForFD(STDOUT_FILENO) == NULL ||
GetFileActionForFD(STDERR_FILENO) == NULL)
{
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
+ __FUNCTION__);
+
if (m_flags.Test(eLaunchFlagDisableSTDIO))
{
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
+ __FUNCTION__);
AppendSuppressFileAction (STDIN_FILENO , true, false);
AppendSuppressFileAction (STDOUT_FILENO, false, true);
AppendSuppressFileAction (STDERR_FILENO, false, true);
@@ -288,34 +293,79 @@ ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
FileSpec err_path;
if (target)
{
- in_path = target->GetStandardInputPath();
- out_path = target->GetStandardOutputPath();
- err_path = target->GetStandardErrorPath();
+ // Only override with the target settings if we don't already have
+ // an action for in, out or error
+ if (GetFileActionForFD(STDIN_FILENO) == NULL)
+ in_path = target->GetStandardInputPath();
+ if (GetFileActionForFD(STDOUT_FILENO) == NULL)
+ out_path = target->GetStandardOutputPath();
+ if (GetFileActionForFD(STDERR_FILENO) == NULL)
+ err_path = target->GetStandardErrorPath();
}
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
+ __FUNCTION__,
+ in_path ? in_path.GetPath().c_str () : "<null>",
+ out_path ? out_path.GetPath().c_str () : "<null>",
+ err_path ? err_path.GetPath().c_str () : "<null>");
+
char path[PATH_MAX];
if (in_path && in_path.GetPath(path, sizeof(path)))
+ {
AppendOpenFileAction(STDIN_FILENO, path, true, false);
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
+ __FUNCTION__,
+ in_path.GetPath().c_str ());
+ }
if (out_path && out_path.GetPath(path, sizeof(path)))
+ {
AppendOpenFileAction(STDOUT_FILENO, path, false, true);
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
+ __FUNCTION__,
+ out_path.GetPath().c_str ());
+ }
if (err_path && err_path.GetPath(path, sizeof(path)))
+ {
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
+ __FUNCTION__,
+ err_path.GetPath().c_str ());
AppendOpenFileAction(STDERR_FILENO, path, false, true);
+ }
+
+ if (default_to_use_pty && (!in_path || !out_path || !err_path))
+ {
+ if (log)
+ log->Printf ("ProcessLaunchInfo::%s default_to_use_pty is set, and at least one stdin/stderr/stdout is unset, so generating a pty to use for it",
+ __FUNCTION__);
- 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 (m_pty->OpenFirstAvailableMaster(O_RDWR| O_NOCTTY, NULL, 0))
+ {
+ const char *slave_path = m_pty->GetSlaveName(NULL, 0);
- if (!in_path) {
+ // Only use the slave tty if we don't have anything specified for
+ // input and don't have an action for stdin
+ if (!in_path && GetFileActionForFD(STDIN_FILENO) == NULL)
+ {
AppendOpenFileAction(STDIN_FILENO, slave_path, true, false);
}
- if (!out_path) {
+ // Only use the slave tty if we don't have anything specified for
+ // output and don't have an action for stdout
+ if (!out_path && GetFileActionForFD(STDOUT_FILENO) == NULL)
+ {
AppendOpenFileAction(STDOUT_FILENO, slave_path, false, true);
}
- if (!err_path) {
+ // Only use the slave tty if we don't have anything specified for
+ // error and don't have an action for stderr
+ if (!err_path && GetFileActionForFD(STDERR_FILENO) == NULL)
+ {
AppendOpenFileAction(STDERR_FILENO, slave_path, false, true);
}
}
@@ -336,42 +386,30 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
if (GetFlags().Test (eLaunchFlagLaunchInShell))
{
- const char *shell_executable = GetShell();
- if (shell_executable)
+ if (m_shell)
{
- 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;
- }
+ std::string shell_executable = m_shell.GetPath();
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");
+ shell_arguments.AppendArgument (shell_executable.c_str());
+ const llvm::Triple &triple = GetArchitecture().GetTriple();
+ if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment())
+ shell_arguments.AppendArgument("/C");
+ else
+ shell_arguments.AppendArgument("-c");
+
StreamString shell_command;
if (will_debug)
{
// Add a modified PATH environment variable in case argv[0]
- // is a relative path
+ // is a relative path.
const char *argv0 = argv[0];
- if (argv0 && (argv0[0] != '/' && argv0[0] != '~'))
+ FileSpec arg_spec(argv0, false);
+ if (arg_spec.IsRelativeToCurrentWorkingDirectory())
{
// 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")
@@ -402,7 +440,8 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
shell_command.PutCString(new_path.c_str());
}
- shell_command.PutCString ("exec");
+ if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
+ shell_command.PutCString("exec");
// Only Apple supports /usr/bin/arch being able to specify the architecture
if (GetArchitecture().IsValid() && // Valid architecture
@@ -442,7 +481,7 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
}
}
shell_arguments.AppendArgument (shell_command.GetString().c_str());
- m_executable.SetFile(shell_executable, false);
+ m_executable = m_shell;
m_arguments = shell_arguments;
return true;
}
@@ -457,3 +496,12 @@ ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
}
return false;
}
+
+Listener &
+ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
+{
+ if (m_listener_sp)
+ return *m_listener_sp;
+ else
+ return debugger.GetListener();
+}
diff --git a/source/Target/StackFrame.cpp b/source/Target/StackFrame.cpp
index e497b176ccfe2..c46db4cfadf9b 100644
--- a/source/Target/StackFrame.cpp
+++ b/source/Target/StackFrame.cpp
@@ -70,7 +70,8 @@ StackFrame::StackFrame (const ThreadSP &thread_sp,
m_is_history_frame (is_history_frame),
m_variable_list_sp (),
m_variable_list_value_objects (),
- m_disassembly ()
+ m_disassembly (),
+ m_mutex (Mutex::eMutexTypeRecursive)
{
// If we don't have a CFA value, use the frame index for our StackID so that recursive
// functions properly aren't confused with one another on a history stack.
@@ -109,7 +110,8 @@ StackFrame::StackFrame (const ThreadSP &thread_sp,
m_is_history_frame (false),
m_variable_list_sp (),
m_variable_list_value_objects (),
- m_disassembly ()
+ m_disassembly (),
+ m_mutex (Mutex::eMutexTypeRecursive)
{
if (sc_ptr != NULL)
{
@@ -148,7 +150,8 @@ StackFrame::StackFrame (const ThreadSP &thread_sp,
m_is_history_frame (false),
m_variable_list_sp (),
m_variable_list_value_objects (),
- m_disassembly ()
+ m_disassembly (),
+ m_mutex (Mutex::eMutexTypeRecursive)
{
if (sc_ptr != NULL)
{
@@ -189,6 +192,7 @@ StackFrame::~StackFrame()
StackID&
StackFrame::GetStackID()
{
+ Mutex::Locker locker(m_mutex);
// Make sure we have resolved the StackID object's symbol context scope if
// we already haven't looked it up.
@@ -235,6 +239,7 @@ StackFrame::GetFrameIndex () const
void
StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope)
{
+ Mutex::Locker locker(m_mutex);
m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE);
m_id.SetSymbolContextScope (symbol_scope);
}
@@ -242,6 +247,7 @@ StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope)
const Address&
StackFrame::GetFrameCodeAddress()
{
+ Mutex::Locker locker(m_mutex);
if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset())
{
m_flags.Set (RESOLVED_FRAME_CODE_ADDR);
@@ -272,6 +278,7 @@ StackFrame::GetFrameCodeAddress()
bool
StackFrame::ChangePC (addr_t pc)
{
+ Mutex::Locker locker(m_mutex);
// We can't change the pc value of a history stack frame - it is immutable.
if (m_is_history_frame)
return false;
@@ -287,6 +294,7 @@ StackFrame::ChangePC (addr_t pc)
const char *
StackFrame::Disassemble ()
{
+ Mutex::Locker locker(m_mutex);
if (m_disassembly.GetSize() == 0)
{
ExecutionContext exe_ctx (shared_from_this());
@@ -346,6 +354,7 @@ StackFrame::GetFrameBlock ()
const SymbolContext&
StackFrame::GetSymbolContext (uint32_t resolve_scope)
{
+ Mutex::Locker locker(m_mutex);
// Copy our internal symbol context into "sc".
if ((m_flags.Get() & resolve_scope) != resolve_scope)
{
@@ -375,7 +384,31 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)
{
addr_t offset = lookup_addr.GetOffset();
if (offset > 0)
+ {
lookup_addr.SetOffset(offset - 1);
+
+ }
+ else
+ {
+ // lookup_addr is the start of a section. We need
+ // do the math on the actual load address and re-compute
+ // the section. We're working with a 'noreturn' function
+ // at the end of a section.
+ ThreadSP thread_sp (GetThread());
+ if (thread_sp)
+ {
+ TargetSP target_sp (thread_sp->CalculateTarget());
+ if (target_sp)
+ {
+ addr_t addr_minus_one = lookup_addr.GetLoadAddress(target_sp.get()) - 1;
+ lookup_addr.SetLoadAddress (addr_minus_one, target_sp.get());
+ }
+ else
+ {
+ lookup_addr.SetOffset(offset - 1);
+ }
+ }
+ }
}
@@ -504,6 +537,7 @@ StackFrame::GetSymbolContext (uint32_t resolve_scope)
VariableList *
StackFrame::GetVariableList (bool get_file_globals)
{
+ Mutex::Locker locker(m_mutex);
if (m_flags.IsClear(RESOLVED_VARIABLES))
{
m_flags.Set(RESOLVED_VARIABLES);
@@ -544,6 +578,7 @@ StackFrame::GetVariableList (bool get_file_globals)
VariableListSP
StackFrame::GetInScopeVariableList (bool get_file_globals)
{
+ Mutex::Locker locker(m_mutex);
// We can't fetch variable information for a history stack frame.
if (m_is_history_frame)
return VariableListSP();
@@ -680,8 +715,8 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
// Make sure we aren't trying to deref an objective
// C ivar if this is not allowed
const uint32_t pointer_type_flags = valobj_sp->GetClangType().GetTypeInfo (NULL);
- if ((pointer_type_flags & ClangASTType::eTypeIsObjC) &&
- (pointer_type_flags & ClangASTType::eTypeIsPointer))
+ if ((pointer_type_flags & eTypeIsObjC) &&
+ (pointer_type_flags & eTypeIsPointer))
{
// This was an objective C object pointer and
// it was requested we skip any fragile ivars
@@ -1142,6 +1177,7 @@ StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
bool
StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
{
+ Mutex::Locker locker(m_mutex);
if (m_cfa_is_valid == false)
{
m_frame_base_error.SetErrorString("No frame base available for this historical stack frame.");
@@ -1191,6 +1227,7 @@ StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
RegisterContextSP
StackFrame::GetRegisterContext ()
{
+ Mutex::Locker locker(m_mutex);
if (!m_reg_context_sp)
{
ThreadSP thread_sp (GetThread());
@@ -1211,6 +1248,7 @@ StackFrame::HasDebugInformation ()
ValueObjectSP
StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
{
+ Mutex::Locker locker(m_mutex);
ValueObjectSP valobj_sp;
if (m_is_history_frame)
{
@@ -1246,6 +1284,7 @@ StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, Dynam
ValueObjectSP
StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
{
+ Mutex::Locker locker(m_mutex);
if (m_is_history_frame)
return ValueObjectSP();
@@ -1365,17 +1404,20 @@ StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths)
GetSymbolContext(eSymbolContextEverything);
const bool show_module = true;
const bool show_inline = true;
+ const bool show_function_arguments = true;
m_sc.DumpStopContext (strm,
exe_ctx.GetBestExecutionContextScope(),
GetFrameCodeAddress(),
show_fullpaths,
show_module,
- show_inline);
+ show_inline,
+ show_function_arguments);
}
void
StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame)
{
+ Mutex::Locker locker(m_mutex);
assert (GetStackID() == prev_frame.GetStackID()); // TODO: remove this after some testing
m_variable_list_sp = prev_frame.m_variable_list_sp;
m_variable_list_value_objects.Swap (prev_frame.m_variable_list_value_objects);
@@ -1387,6 +1429,7 @@ StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame)
void
StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame)
{
+ Mutex::Locker locker(m_mutex);
assert (GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing
m_id.SetPC (curr_frame.m_id.GetPC()); // Update the Stack ID PC value
assert (GetThread() == curr_frame.GetThread());
diff --git a/source/Target/StackFrameList.cpp b/source/Target/StackFrameList.cpp
index 99234dc61f1d9..9a132618288dc 100644
--- a/source/Target/StackFrameList.cpp
+++ b/source/Target/StackFrameList.cpp
@@ -288,8 +288,8 @@ StackFrameList::GetFramesUpTo(uint32_t end_idx)
do
{
uint32_t idx = m_concrete_frames_fetched++;
- lldb::addr_t pc;
- lldb::addr_t cfa;
+ lldb::addr_t pc = LLDB_INVALID_ADDRESS;
+ lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
if (idx == 0)
{
// We might have already created frame zero, only create it
@@ -625,11 +625,14 @@ StackFrameList::GetFrameWithStackID (const StackID &stack_id)
if (begin != end)
{
collection::const_iterator pos = std::lower_bound (begin, end, stack_id, CompareStackID);
- if (pos != end && (*pos)->GetStackID() == stack_id)
- return *pos;
+ if (pos != end)
+ {
+ if ((*pos)->GetStackID() == stack_id)
+ return *pos;
+ }
- if (m_frames.back()->GetStackID() < stack_id)
- frame_idx = m_frames.size();
+// if (m_frames.back()->GetStackID() < stack_id)
+// frame_idx = m_frames.size();
}
do
{
diff --git a/source/Target/StopInfo.cpp b/source/Target/StopInfo.cpp
index a37a4079ff116..4b57ca65a2dff 100644
--- a/source/Target/StopInfo.cpp
+++ b/source/Target/StopInfo.cpp
@@ -40,7 +40,8 @@ StopInfo::StopInfo (Thread &thread, uint64_t value) :
m_resume_id (thread.GetProcess()->GetResumeID()),
m_value (value),
m_override_should_notify (eLazyBoolCalculate),
- m_override_should_stop (eLazyBoolCalculate)
+ m_override_should_stop (eLazyBoolCalculate),
+ m_extended_info()
{
}
@@ -181,6 +182,7 @@ public:
{
ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
StoppointCallbackContext context (event_ptr, exe_ctx, true);
+ bp_site_sp->BumpHitCounts();
m_should_stop = bp_site_sp->ShouldStop (&context);
}
else
@@ -402,10 +404,21 @@ protected:
// 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.
+ // For safety's sake let's also grab an extra reference to the breakpoint owners of the locations we're
+ // going to examine, since the locations are going to have to get back to their breakpoints, and the
+ // locations don't keep their owners alive. I'm just sticking the BreakpointSP's in a vector since
+ // I'm only really using it to locally increment their retain counts.
BreakpointLocationCollection site_locations;
+ std::vector<lldb::BreakpointSP> location_owners;
+
for (size_t j = 0; j < num_owners; j++)
- site_locations.Add(bp_site_sp->GetOwnerAtIndex(j));
+ {
+ BreakpointLocationSP loc(bp_site_sp->GetOwnerAtIndex(j));
+ site_locations.Add(loc);
+ location_owners.push_back(loc->GetBreakpoint().shared_from_this());
+
+ }
for (size_t j = 0; j < num_owners; j++)
{
@@ -689,14 +702,13 @@ protected:
assert (stored_stop_info_sp.get() == this);
ThreadPlanSP new_plan_sp(thread_sp->QueueThreadPlanForStepSingleInstruction(false, // step-over
- false, // abort_other_plans
- true)); // stop_other_threads
+ false, // abort_other_plans
+ true)); // stop_other_threads
new_plan_sp->SetIsMasterPlan (true);
new_plan_sp->SetOkayToDiscard (false);
new_plan_sp->SetPrivate (true);
process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
- process->Resume ();
- process->WaitForProcessToStop (NULL);
+ process->ResumeSynchronous(NULL);
process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
thread_sp->SetStopInfo(stored_stop_info_sp);
}
diff --git a/source/Target/Target.cpp b/source/Target/Target.cpp
index d2d0b50985550..e9393d1be0b41 100644
--- a/source/Target/Target.cpp
+++ b/source/Target/Target.cpp
@@ -35,6 +35,7 @@
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/ClangASTSource.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Host/FileSpec.h"
#include "lldb/Host/Host.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/CommandReturnObject.h"
@@ -63,7 +64,7 @@ Target::GetStaticBroadcasterClass ()
//----------------------------------------------------------------------
// Target constructor
//----------------------------------------------------------------------
-Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp) :
+Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::PlatformSP &platform_sp, bool is_dummy_target) :
TargetProperties (this),
Broadcaster (&debugger, Target::GetStaticBroadcasterClass().AsCString()),
ExecutionContextScope (),
@@ -87,7 +88,9 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
m_stop_hooks (),
m_stop_hook_next_id (0),
m_valid (true),
- m_suppress_stop_hooks (false)
+ m_suppress_stop_hooks (false),
+ m_is_dummy_target(is_dummy_target)
+
{
SetEventName (eBroadcastBitBreakpointChanged, "breakpoint-changed");
SetEventName (eBroadcastBitModulesLoaded, "modules-loaded");
@@ -106,6 +109,24 @@ Target::Target(Debugger &debugger, const ArchSpec &target_arch, const lldb::Plat
}
}
+void
+Target::PrimeFromDummyTarget(Target *target)
+{
+ if (!target)
+ return;
+
+ m_stop_hooks = target->m_stop_hooks;
+
+ for (BreakpointSP breakpoint_sp : target->m_breakpoint_list.Breakpoints())
+ {
+ if (breakpoint_sp->IsInternal())
+ continue;
+
+ BreakpointSP new_bp (new Breakpoint (*this, *breakpoint_sp.get()));
+ AddBreakpoint (new_bp, false);
+ }
+}
+
//----------------------------------------------------------------------
// Destructor
//----------------------------------------------------------------------
@@ -330,7 +351,7 @@ Target::CreateBreakpoint (lldb::addr_t addr, bool internal, bool hardware)
BreakpointSP
Target::CreateBreakpoint (Address &addr, bool internal, bool hardware)
{
- SearchFilterSP filter_sp(new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ SearchFilterSP filter_sp(new SearchFilterForUnconstrainedSearches (shared_from_this()));
BreakpointResolverSP resolver_sp (new BreakpointResolverAddress (NULL, addr));
return CreateBreakpoint (filter_sp, resolver_sp, internal, hardware, false);
}
@@ -430,7 +451,7 @@ Target::GetSearchFilterForModule (const FileSpec *containingModule)
else
{
if (m_search_filter_sp.get() == NULL)
- m_search_filter_sp.reset (new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ m_search_filter_sp.reset (new SearchFilterForUnconstrainedSearches (shared_from_this()));
filter_sp = m_search_filter_sp;
}
return filter_sp;
@@ -449,7 +470,7 @@ Target::GetSearchFilterForModuleList (const FileSpecList *containingModules)
else
{
if (m_search_filter_sp.get() == NULL)
- m_search_filter_sp.reset (new SearchFilterForNonModuleSpecificSearches (shared_from_this()));
+ m_search_filter_sp.reset (new SearchFilterForUnconstrainedSearches (shared_from_this()));
filter_sp = m_search_filter_sp;
}
return filter_sp;
@@ -510,29 +531,35 @@ Target::CreateBreakpoint (SearchFilterSP &filter_sp, BreakpointResolverSP &resol
{
bp_sp.reset(new Breakpoint (*this, filter_sp, resolver_sp, request_hardware, resolve_indirect_symbols));
resolver_sp->SetBreakpoint (bp_sp.get());
+ AddBreakpoint (bp_sp, internal);
+ }
+ return bp_sp;
+}
- if (internal)
- m_internal_breakpoint_list.Add (bp_sp, false);
- else
- m_breakpoint_list.Add (bp_sp, true);
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
- if (log)
- {
- StreamString s;
- bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
- log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, internal ? "yes" : "no", s.GetData());
- }
+void
+Target::AddBreakpoint (lldb::BreakpointSP bp_sp, bool internal)
+{
+ if (!bp_sp)
+ return;
+ if (internal)
+ m_internal_breakpoint_list.Add (bp_sp, false);
+ else
+ m_breakpoint_list.Add (bp_sp, true);
- bp_sp->ResolveBreakpoint();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
+ if (log)
+ {
+ StreamString s;
+ bp_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf ("Target::%s (internal = %s) => break_id = %s\n", __FUNCTION__, bp_sp->IsInternal() ? "yes" : "no", s.GetData());
}
-
- if (!internal && bp_sp)
+
+ bp_sp->ResolveBreakpoint();
+
+ if (!internal)
{
m_last_created_breakpoint = bp_sp;
}
-
- return bp_sp;
}
bool
@@ -1214,6 +1241,7 @@ Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
{
if (m_valid && module_list.GetSize())
{
+ UnloadModuleSections (module_list);
m_breakpoint_list.UpdateBreakpoints (module_list, false, delete_locations);
// TODO: make event data that packages up the module_list
BroadcastEvent (eBroadcastBitModulesUnloaded, NULL);
@@ -1221,7 +1249,7 @@ Target::ModulesDidUnload (ModuleList &module_list, bool delete_locations)
}
bool
-Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_file_spec)
+Target::ModuleIsExcludedForUnconstrainedSearches (const FileSpec &module_file_spec)
{
if (GetBreakpointsConsultPlatformAvoidList())
{
@@ -1235,7 +1263,7 @@ Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_fil
{
for (size_t i = 0; i < num_modules; i++)
{
- if (!ModuleIsExcludedForNonModuleSpecificSearches (matchingModules.GetModuleAtIndex(i)))
+ if (!ModuleIsExcludedForUnconstrainedSearches (matchingModules.GetModuleAtIndex(i)))
return false;
}
return true;
@@ -1245,12 +1273,12 @@ Target::ModuleIsExcludedForNonModuleSpecificSearches (const FileSpec &module_fil
}
bool
-Target::ModuleIsExcludedForNonModuleSpecificSearches (const lldb::ModuleSP &module_sp)
+Target::ModuleIsExcludedForUnconstrainedSearches (const lldb::ModuleSP &module_sp)
{
if (GetBreakpointsConsultPlatformAvoidList())
{
if (m_platform_sp)
- return m_platform_sp->ModuleIsExcludedForNonModuleSpecificSearches (*this, module_sp);
+ return m_platform_sp->ModuleIsExcludedForUnconstrainedSearches (*this, module_sp);
}
return false;
}
@@ -1355,9 +1383,9 @@ Target::ReadMemory (const Address& addr,
ModuleSP addr_module_sp (resolved_addr.GetModule());
if (addr_module_sp && addr_module_sp->GetFileSpec())
error.SetErrorStringWithFormat("%s[0x%" PRIx64 "] can't be resolved, %s in not currently loaded",
- addr_module_sp->GetFileSpec().GetFilename().AsCString(),
+ addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknown>"),
resolved_addr.GetFileAddress(),
- addr_module_sp->GetFileSpec().GetFilename().AsCString());
+ addr_module_sp->GetFileSpec().GetFilename().AsCString("<Unknonw>"));
else
error.SetErrorStringWithFormat("0x%" PRIx64 " can't be resolved", resolved_addr.GetFileAddress());
}
@@ -1436,7 +1464,12 @@ Target::ReadCStringFromMemory (const Address& addr, char *dst, size_t dst_max_le
Error error;
addr_t curr_addr = addr.GetLoadAddress(this);
Address address(addr);
+
+ // We could call m_process_sp->GetMemoryCacheLineSize() but I don't
+ // think this really needs to be tied to the memory cache subsystem's
+ // cache line size, so leave this as a fixed constant.
const size_t cache_line_size = 512;
+
size_t bytes_left = dst_max_len - 1;
char *curr_dst = dst;
@@ -2006,6 +2039,22 @@ Target::GetSourceManager ()
return *m_source_manager_ap;
}
+ClangModulesDeclVendor *
+Target::GetClangModulesDeclVendor ()
+{
+ static Mutex s_clang_modules_decl_vendor_mutex; // If this is contended we can make it per-target
+
+ {
+ Mutex::Locker clang_modules_decl_vendor_locker(s_clang_modules_decl_vendor_mutex);
+
+ if (!m_clang_modules_decl_vendor_ap)
+ {
+ m_clang_modules_decl_vendor_ap.reset(ClangModulesDeclVendor::Create(*this));
+ }
+ }
+
+ return m_clang_modules_decl_vendor_ap.get();
+}
Target::StopHookSP
Target::CreateStopHook ()
@@ -2173,18 +2222,17 @@ Target::RunStopHooks ()
if (print_thread_header)
result.AppendMessageWithFormat("-- Thread %d\n", exc_ctx_with_reasons[i].GetThreadPtr()->GetIndexID());
-
- bool stop_on_continue = true;
- bool stop_on_error = true;
- bool echo_commands = false;
- bool print_results = true;
- GetDebugger().GetCommandInterpreter().HandleCommands (cur_hook_sp->GetCommands(),
- &exc_ctx_with_reasons[i],
- stop_on_continue,
- stop_on_error,
- echo_commands,
- print_results,
- eLazyBoolNo,
+
+ CommandInterpreterRunOptions options;
+ options.SetStopOnContinue (true);
+ options.SetStopOnError (true);
+ options.SetEchoCommands (false);
+ options.SetPrintResults (true);
+ options.SetAddToHistory (false);
+
+ GetDebugger().GetCommandInterpreter().HandleCommands (cur_hook_sp->GetCommands(),
+ &exc_ctx_with_reasons[i],
+ options,
result);
// If the command started the target going again, we should bag out of
@@ -2279,6 +2327,12 @@ Target::ResolveLoadAddress (addr_t load_addr, Address &so_addr, uint32_t stop_id
}
bool
+Target::ResolveFileAddress (lldb::addr_t file_addr, Address &resolved_addr)
+{
+ return m_images.ResolveFileAddress(file_addr, resolved_addr);
+}
+
+bool
Target::SetSectionLoadAddress (const SectionSP &section_sp, addr_t new_section_load_addr, bool warn_multiple)
{
const addr_t old_section_load_addr = m_section_load_history.GetSectionLoadAddress (SectionLoadHistory::eStopIDNow, section_sp);
@@ -2297,6 +2351,40 @@ Target::SetSectionLoadAddress (const SectionSP &section_sp, addr_t new_section_l
}
+size_t
+Target::UnloadModuleSections (const ModuleList &module_list)
+{
+ size_t section_unload_count = 0;
+ size_t num_modules = module_list.GetSize();
+ for (size_t i=0; i<num_modules; ++i)
+ {
+ section_unload_count += UnloadModuleSections (module_list.GetModuleAtIndex(i));
+ }
+ return section_unload_count;
+}
+
+size_t
+Target::UnloadModuleSections (const lldb::ModuleSP &module_sp)
+{
+ uint32_t stop_id = 0;
+ ProcessSP process_sp(GetProcessSP());
+ if (process_sp)
+ stop_id = process_sp->GetStopID();
+ else
+ stop_id = m_section_load_history.GetLastStopID();
+ SectionList *sections = module_sp->GetSectionList();
+ size_t section_unload_count = 0;
+ if (sections)
+ {
+ const uint32_t num_sections = sections->GetNumSections(0);
+ for (uint32_t i = 0; i < num_sections; ++i)
+ {
+ section_unload_count += m_section_load_history.SetSectionUnloaded(stop_id, sections->GetSectionAtIndex(i));
+ }
+ }
+ return section_unload_count;
+}
+
bool
Target::SetSectionUnloaded (const lldb::SectionSP &section_sp)
{
@@ -2329,10 +2417,14 @@ Target::ClearAllLoadedSections ()
Error
-Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
+Target::Launch (ProcessLaunchInfo &launch_info, Stream *stream)
{
Error error;
-
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_TARGET));
+
+ if (log)
+ log->Printf ("Target::%s() called for %s", __FUNCTION__, launch_info.GetExecutableFile().GetPath().c_str ());
+
StateType state = eStateInvalid;
// Scope to temporarily get the process state in case someone has manually
@@ -2342,7 +2434,16 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
ProcessSP process_sp (GetProcessSP());
if (process_sp)
+ {
state = process_sp->GetState();
+ if (log)
+ log->Printf ("Target::%s the process exists, and its current state is %s", __FUNCTION__, StateAsCString (state));
+ }
+ else
+ {
+ if (log)
+ log->Printf ("Target::%s the process instance doesn't currently exist.", __FUNCTION__);
+ }
}
launch_info.GetFlags().Set (eLaunchFlagDebug);
@@ -2358,6 +2459,13 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
// Finalize the file actions, and if none were given, default to opening
// up a pseudo terminal
const bool default_to_use_pty = platform_sp ? platform_sp->IsHost() : false;
+ if (log)
+ log->Printf ("Target::%s have platform=%s, platform_sp->IsHost()=%s, default_to_use_pty=%s",
+ __FUNCTION__,
+ platform_sp ? "true" : "false",
+ platform_sp ? (platform_sp->IsHost () ? "true" : "false") : "n/a",
+ default_to_use_pty ? "true" : "false");
+
launch_info.FinalizeFileActions (this, default_to_use_pty);
if (state == eStateConnected)
@@ -2375,14 +2483,19 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
// If we're not already connected to the process, and if we have a platform that can launch a process for debugging, go ahead and do that here.
if (state != eStateConnected && platform_sp && platform_sp->CanDebugProcess ())
{
+ if (log)
+ log->Printf ("Target::%s asking the platform to debug the process", __FUNCTION__);
+
m_process_sp = GetPlatform()->DebugProcess (launch_info,
debugger,
this,
- listener,
error);
}
else
{
+ if (log)
+ log->Printf ("Target::%s the platform doesn't know how to debug a process, getting a process plugin to do this for us.", __FUNCTION__);
+
if (state == eStateConnected)
{
assert(m_process_sp);
@@ -2391,7 +2504,7 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
{
// Use a Process plugin to construct the process.
const char *plugin_name = launch_info.GetProcessPluginName();
- CreateProcess (listener, plugin_name, NULL);
+ CreateProcess (launch_info.GetListenerForProcess(debugger), plugin_name, NULL);
}
// Since we didn't have a platform launch the process, launch it here.
@@ -2411,8 +2524,8 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == false)
{
ListenerSP hijack_listener_sp (launch_info.GetHijackListener());
-
- StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get());
+
+ StateType state = m_process_sp->WaitForProcessToStop (NULL, NULL, false, hijack_listener_sp.get(), NULL);
if (state == eStateStopped)
{
@@ -2430,7 +2543,7 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
if (synchronous_execution)
{
- state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get());
+ state = m_process_sp->WaitForProcessToStop (NULL, NULL, true, hijack_listener_sp.get(), stream);
const bool must_be_alive = false; // eStateExited is ok, so this must be false
if (!StateIsStoppedState(state, must_be_alive))
{
@@ -2447,7 +2560,7 @@ Target::Launch (Listener &listener, ProcessLaunchInfo &launch_info)
}
else if (state == eStateExited)
{
- bool with_shell = launch_info.GetShell();
+ 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'."
@@ -2632,7 +2745,7 @@ g_properties[] =
{
{ "default-arch" , OptionValue::eTypeArch , true , 0 , NULL, NULL, "Default architecture to choose, when there's a choice." },
{ "expr-prefix" , OptionValue::eTypeFileSpec , false, 0 , NULL, NULL, "Path to a file containing expressions to be prepended to all expressions." },
- { "prefer-dynamic-value" , OptionValue::eTypeEnum , false, eNoDynamicValues , NULL, g_dynamic_value_types, "Should printed values be shown as their dynamic value." },
+ { "prefer-dynamic-value" , OptionValue::eTypeEnum , false, eDynamicDontRunTarget , NULL, g_dynamic_value_types, "Should printed values be shown as their dynamic value." },
{ "enable-synthetic-value" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Should synthetic values be used by default whenever available." },
{ "skip-prologue" , OptionValue::eTypeBoolean , false, true , NULL, NULL, "Skip function prologues when setting breakpoints by name." },
{ "source-map" , OptionValue::eTypePathMap , false, 0 , NULL, NULL, "Source path remappings used to track the change of location between a source file when built, and "
@@ -2656,12 +2769,13 @@ g_properties[] =
{ "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. "
+ { "inline-breakpoint-strategy" , OptionValue::eTypeEnum , false, eInlineBreakpointsAlways , NULL, g_inline_breakpoint_enums, "The strategy to use when settings breakpoints by file and line. "
"Breakpoint locations can end up being inlined by the compiler, so that a compile unit 'a.c' might contain an inlined function from another source file. "
"Usually this is limitted to breakpoint locations from inlined functions from header or other include files, or more accurately non-implementation source files. "
"Sometimes code might #include implementation files and cause inlined breakpoint locations in inlined implementation files. "
- "Always checking for inlined breakpoint locations can be expensive (memory and time), so we try to minimize the "
- "times we look for inlined locations. This setting allows you to control exactly which strategy is used when settings "
+ "Always checking for inlined breakpoint locations can be expensive (memory and time), so if you have a project with many headers "
+ "and find that setting breakpoints is slow, then you can change this setting to headers. "
+ "This setting allows you to control exactly which strategy is used when setting "
"file and line breakpoints." },
// FIXME: This is the wrong way to do per-architecture settings, but we don't have a general per architecture settings system in place yet.
{ "x86-disassembly-flavor" , OptionValue::eTypeEnum , false, eX86DisFlavorDefault, NULL, g_x86_dis_flavor_value_types, "The default disassembly flavor to use for x86 or x86-64 targets." },
diff --git a/source/Target/TargetList.cpp b/source/Target/TargetList.cpp
index 5ee75ff744493..28ad47e3d81d7 100644
--- a/source/Target/TargetList.cpp
+++ b/source/Target/TargetList.cpp
@@ -21,6 +21,7 @@
#include "lldb/Core/State.h"
#include "lldb/Core/Timer.h"
#include "lldb/Host/Host.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Interpreter/CommandInterpreter.h"
#include "lldb/Interpreter/OptionGroupPlatform.h"
#include "lldb/Symbol/ObjectFile.h"
@@ -69,6 +70,41 @@ TargetList::CreateTarget (Debugger &debugger,
const OptionGroupPlatform *platform_options,
TargetSP &target_sp)
{
+ return CreateTargetInternal (debugger,
+ user_exe_path,
+ triple_cstr,
+ get_dependent_files,
+ platform_options,
+ target_sp,
+ false);
+}
+
+Error
+TargetList::CreateTarget (Debugger &debugger,
+ const char *user_exe_path,
+ const ArchSpec& specified_arch,
+ bool get_dependent_files,
+ PlatformSP &platform_sp,
+ TargetSP &target_sp)
+{
+ return CreateTargetInternal (debugger,
+ user_exe_path,
+ specified_arch,
+ get_dependent_files,
+ platform_sp,
+ target_sp,
+ false);
+}
+
+Error
+TargetList::CreateTargetInternal (Debugger &debugger,
+ const char *user_exe_path,
+ const char *triple_cstr,
+ bool get_dependent_files,
+ const OptionGroupPlatform *platform_options,
+ TargetSP &target_sp,
+ bool is_dummy_target)
+{
Error error;
PlatformSP platform_sp;
@@ -170,7 +206,7 @@ TargetList::CreateTarget (Debugger &debugger,
typedef std::vector<PlatformSP> PlatformList;
PlatformList platforms;
- PlatformSP host_platform_sp = Platform::GetDefaultPlatform();
+ PlatformSP host_platform_sp = Platform::GetHostPlatform();
for (size_t i=0; i<num_specs; ++i)
{
ModuleSpec module_spec;
@@ -258,7 +294,11 @@ TargetList::CreateTarget (Debugger &debugger,
if (!prefer_platform_arch && arch.IsValid())
{
if (!platform_sp->IsCompatibleArchitecture(arch, false, &platform_arch))
+ {
platform_sp = Platform::GetPlatformForArchitecture(arch, &platform_arch);
+ if (platform_sp)
+ debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
+ }
}
else if (platform_arch.IsValid())
{
@@ -266,30 +306,69 @@ TargetList::CreateTarget (Debugger &debugger,
// a single architecture which should be used
ArchSpec fixed_platform_arch;
if (!platform_sp->IsCompatibleArchitecture(platform_arch, false, &fixed_platform_arch))
+ {
platform_sp = Platform::GetPlatformForArchitecture(platform_arch, &fixed_platform_arch);
+ if (platform_sp)
+ debugger.GetPlatformList().SetSelectedPlatform(platform_sp);
+ }
}
}
if (!platform_arch.IsValid())
platform_arch = arch;
- error = TargetList::CreateTarget (debugger,
- user_exe_path,
- platform_arch,
- get_dependent_files,
- platform_sp,
- target_sp);
+ error = TargetList::CreateTargetInternal (debugger,
+ user_exe_path,
+ platform_arch,
+ get_dependent_files,
+ platform_sp,
+ target_sp,
+ is_dummy_target);
return error;
}
+lldb::TargetSP
+TargetList::GetDummyTarget (lldb_private::Debugger &debugger)
+{
+ // FIXME: Maybe the dummy target should be per-Debugger
+ if (!m_dummy_target_sp || !m_dummy_target_sp->IsValid())
+ {
+ ArchSpec arch(Target::GetDefaultArchitecture());
+ if (!arch.IsValid())
+ arch = HostInfo::GetArchitecture();
+ Error err = CreateDummyTarget(debugger,
+ arch.GetTriple().getTriple().c_str(),
+ m_dummy_target_sp);
+ }
+
+ return m_dummy_target_sp;
+}
+
Error
-TargetList::CreateTarget (Debugger &debugger,
- const char *user_exe_path,
- const ArchSpec& specified_arch,
- bool get_dependent_files,
- PlatformSP &platform_sp,
- TargetSP &target_sp)
+TargetList::CreateDummyTarget (Debugger &debugger,
+ const char *specified_arch_name,
+ lldb::TargetSP &target_sp)
{
+ PlatformSP host_platform_sp(Platform::GetHostPlatform());
+ return CreateTargetInternal (debugger,
+ (const char *) nullptr,
+ specified_arch_name,
+ false,
+ (const OptionGroupPlatform *) nullptr,
+ target_sp,
+ true);
+}
+
+Error
+TargetList::CreateTargetInternal (Debugger &debugger,
+ const char *user_exe_path,
+ const ArchSpec& specified_arch,
+ bool get_dependent_files,
+ lldb::PlatformSP &platform_sp,
+ lldb::TargetSP &target_sp,
+ bool is_dummy_target)
+{
+
Timer scoped_timer (__PRETTY_FUNCTION__,
"TargetList::CreateTarget (file = '%s', arch = '%s')",
user_exe_path,
@@ -332,7 +411,7 @@ TargetList::CreateTarget (Debugger &debugger,
if (file.GetFileType() == FileSpec::eFileTypeDirectory)
user_exe_path_is_bundle = true;
- if (file.IsRelativeToCurrentWorkingDirectory())
+ if (file.IsRelativeToCurrentWorkingDirectory() && user_exe_path)
{
// Ignore paths that start with "./" and "../"
if (!((user_exe_path[0] == '.' && user_exe_path[1] == '/') ||
@@ -355,8 +434,8 @@ TargetList::CreateTarget (Debugger &debugger,
if (platform_sp)
{
FileSpecList executable_search_paths (Target::GetDefaultExecutableSearchPaths());
- error = platform_sp->ResolveExecutable (file,
- arch,
+ ModuleSpec module_spec(file, arch);
+ error = platform_sp->ResolveExecutable (module_spec,
exe_module_sp,
executable_search_paths.GetSize() ? &executable_search_paths : NULL);
}
@@ -378,7 +457,7 @@ TargetList::CreateTarget (Debugger &debugger,
}
return error;
}
- target_sp.reset(new Target(debugger, arch, platform_sp));
+ target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
target_sp->SetExecutableModule (exe_module_sp, get_dependent_files);
if (user_exe_path_is_bundle)
exe_module_sp->GetFileSpec().GetPath(resolved_bundle_exe_path, sizeof(resolved_bundle_exe_path));
@@ -388,7 +467,7 @@ TargetList::CreateTarget (Debugger &debugger,
{
// No file was specified, just create an empty target with any arch
// if a valid arch was specified
- target_sp.reset(new Target(debugger, arch, platform_sp));
+ target_sp.reset(new Target(debugger, arch, platform_sp, is_dummy_target));
}
if (target_sp)
@@ -415,11 +494,20 @@ TargetList::CreateTarget (Debugger &debugger,
file_dir.GetDirectory() = file.GetDirectory();
target_sp->GetExecutableSearchPaths ().Append (file_dir);
}
- Mutex::Locker locker(m_target_list_mutex);
- m_selected_target_idx = m_target_list.size();
- m_target_list.push_back(target_sp);
-
-
+
+ // Don't put the dummy target in the target list, it's held separately.
+ if (!is_dummy_target)
+ {
+ Mutex::Locker locker(m_target_list_mutex);
+ m_selected_target_idx = m_target_list.size();
+ m_target_list.push_back(target_sp);
+ // Now prime this from the dummy target:
+ target_sp->PrimeFromDummyTarget(debugger.GetDummyTarget());
+ }
+ else
+ {
+ m_dummy_target_sp = target_sp;
+ }
}
return error;
diff --git a/source/Target/Thread.cpp b/source/Target/Thread.cpp
index a445517da6a8e..b532d8d71c8f8 100644
--- a/source/Target/Thread.cpp
+++ b/source/Target/Thread.cpp
@@ -32,6 +32,7 @@
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanCallFunction.h"
#include "lldb/Target/ThreadPlanBase.h"
+#include "lldb/Target/ThreadPlanPython.h"
#include "lldb/Target/ThreadPlanStepInstruction.h"
#include "lldb/Target/ThreadPlanStepOut.h"
#include "lldb/Target/ThreadPlanStepOverBreakpoint.h"
@@ -43,7 +44,7 @@
#include "lldb/Target/ThreadSpec.h"
#include "lldb/Target/Unwind.h"
#include "Plugins/Process/Utility/UnwindLLDB.h"
-#include "UnwindMacOSXFrameBackchain.h"
+#include "Plugins/Process/Utility/UnwindMacOSXFrameBackchain.h"
using namespace lldb;
@@ -278,6 +279,7 @@ Thread::Thread (Process &process, lldb::tid_t tid, bool use_invalid_index_id) :
m_process_wp (process.shared_from_this()),
m_stop_info_sp (),
m_stop_info_stop_id (0),
+ m_stop_info_override_stop_id (0),
m_index_id (use_invalid_index_id ? LLDB_INVALID_INDEX32 : process.GetNextThreadIndexID(tid)),
m_reg_context_sp (),
m_state (eStateUnloaded),
@@ -465,6 +467,24 @@ Thread::GetPrivateStopInfo ()
SetStopInfo (StopInfoSP());
}
}
+
+ // The stop info can be manually set by calling Thread::SetStopInfo()
+ // prior to this function ever getting called, so we can't rely on
+ // "m_stop_info_stop_id != process_stop_id" as the condition for
+ // the if statement below, we must also check the stop info to see
+ // if we need to override it. See the header documentation in
+ // Process::GetStopInfoOverrideCallback() for more information on
+ // the stop info override callback.
+ if (m_stop_info_override_stop_id != process_stop_id)
+ {
+ m_stop_info_override_stop_id = process_stop_id;
+ if (m_stop_info_sp)
+ {
+ ArchSpec::StopInfoOverrideCallbackType callback = GetProcess()->GetStopInfoOverrideCallback();
+ if (callback)
+ callback(*this);
+ }
+ }
}
return m_stop_info_sp;
}
@@ -642,7 +662,8 @@ Thread::SetupForResume ()
lldb::RegisterContextSP reg_ctx_sp (GetRegisterContext());
if (reg_ctx_sp)
{
- BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(reg_ctx_sp->GetPC());
+ const addr_t thread_pc = reg_ctx_sp->GetPC();
+ BreakpointSiteSP bp_site_sp = GetProcess()->GetBreakpointSiteList().FindByAddress(thread_pc);
if (bp_site_sp)
{
// Note, don't assume there's a ThreadPlanStepOverBreakpoint, the target may not require anything
@@ -650,19 +671,30 @@ Thread::SetupForResume ()
ThreadPlan *cur_plan = GetCurrentPlan();
- if (cur_plan->GetKind() != ThreadPlan::eKindStepOverBreakpoint)
+ bool push_step_over_bp_plan = false;
+ if (cur_plan->GetKind() == ThreadPlan::eKindStepOverBreakpoint)
{
- ThreadPlanStepOverBreakpoint *step_bp_plan = new ThreadPlanStepOverBreakpoint (*this);
- if (step_bp_plan)
+ ThreadPlanStepOverBreakpoint *bp_plan = (ThreadPlanStepOverBreakpoint *)cur_plan;
+ if (bp_plan->GetBreakpointLoadAddress() != thread_pc)
+ push_step_over_bp_plan = true;
+ }
+ else
+ push_step_over_bp_plan = true;
+
+ if (push_step_over_bp_plan)
+ {
+ ThreadPlanSP step_bp_plan_sp (new ThreadPlanStepOverBreakpoint (*this));
+ if (step_bp_plan_sp)
{
- ThreadPlanSP step_bp_plan_sp;
- step_bp_plan->SetPrivate (true);
+ ;
+ step_bp_plan_sp->SetPrivate (true);
if (GetCurrentPlan()->RunState() != eStateStepping)
{
+ ThreadPlanStepOverBreakpoint *step_bp_plan
+ = static_cast<ThreadPlanStepOverBreakpoint *>(step_bp_plan_sp.get());
step_bp_plan->SetAutoContinue(true);
}
- step_bp_plan_sp.reset (step_bp_plan);
QueueThreadPlan (step_bp_plan_sp, false);
}
}
@@ -941,30 +973,30 @@ Thread::ShouldStop (Event* event_ptr)
if (over_ride_stop)
should_stop = false;
- // One other potential problem is that we set up a master plan, then stop in before it is complete - for instance
- // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up
- // past the end point condition of the initial plan. We don't want to strand the original plan on the stack,
- // This code clears stale plans off the stack.
+ }
+
+ // One other potential problem is that we set up a master plan, then stop in before it is complete - for instance
+ // by hitting a breakpoint during a step-over - then do some step/finish/etc operations that wind up
+ // past the end point condition of the initial plan. We don't want to strand the original plan on the stack,
+ // This code clears stale plans off the stack.
- if (should_stop)
+ if (should_stop)
+ {
+ ThreadPlan *plan_ptr = GetCurrentPlan();
+ while (!PlanIsBasePlan(plan_ptr))
{
- ThreadPlan *plan_ptr = GetCurrentPlan();
- while (!PlanIsBasePlan(plan_ptr))
- {
- bool stale = plan_ptr->IsPlanStale ();
- ThreadPlan *examined_plan = plan_ptr;
- plan_ptr = GetPreviousPlan (examined_plan);
+ bool stale = plan_ptr->IsPlanStale ();
+ ThreadPlan *examined_plan = plan_ptr;
+ plan_ptr = GetPreviousPlan (examined_plan);
- if (stale)
- {
- if (log)
- log->Printf("Plan %s being discarded in cleanup, it says it is already done.",
- examined_plan->GetName());
- DiscardThreadPlansUpToPlan(examined_plan);
- }
+ if (stale)
+ {
+ if (log)
+ log->Printf("Plan %s being discarded in cleanup, it says it is already done.",
+ examined_plan->GetName());
+ DiscardThreadPlansUpToPlan(examined_plan);
}
}
-
}
if (log)
@@ -1290,6 +1322,36 @@ Thread::SetTracer (lldb::ThreadPlanTracerSP &tracer_sp)
m_plan_stack[i]->SetThreadPlanTracer(tracer_sp);
}
+bool
+Thread::DiscardUserThreadPlansUpToIndex (uint32_t thread_index)
+{
+ // Count the user thread plans from the back end to get the number of the one we want
+ // to discard:
+
+ uint32_t idx = 0;
+ ThreadPlan *up_to_plan_ptr = nullptr;
+
+ for (ThreadPlanSP plan_sp : m_plan_stack)
+ {
+ if (plan_sp->GetPrivate())
+ continue;
+ if (idx == thread_index)
+ {
+ up_to_plan_ptr = plan_sp.get();
+ break;
+ }
+ else
+ idx++;
+ }
+
+ if (up_to_plan_ptr == nullptr)
+ return false;
+
+ DiscardThreadPlansUpToPlan(up_to_plan_ptr);
+ return true;
+}
+
+
void
Thread::DiscardThreadPlansUpToPlan (lldb::ThreadPlanSP &up_to_plan_sp)
{
@@ -1483,18 +1545,16 @@ Thread::QueueThreadPlanForStepInRange
LazyBool step_out_avoids_code_without_debug_info
)
{
- ThreadPlanSP thread_plan_sp;
- ThreadPlanStepInRange *plan = new ThreadPlanStepInRange (*this,
+ ThreadPlanSP thread_plan_sp (new ThreadPlanStepInRange (*this,
range,
addr_context,
stop_other_threads,
step_in_avoids_code_without_debug_info,
- step_out_avoids_code_without_debug_info);
+ step_out_avoids_code_without_debug_info));
+ ThreadPlanStepInRange *plan = static_cast<ThreadPlanStepInRange *>(thread_plan_sp.get());
if (step_in_target)
plan->SetStepInTarget(step_in_target);
-
- thread_plan_sp.reset (plan);
QueueThreadPlan (thread_plan_sp, abort_other_plans);
return thread_plan_sp;
@@ -1546,17 +1606,18 @@ Thread::QueueThreadPlanForStepOutNoShouldStop
uint32_t frame_idx
)
{
- ThreadPlanStepOut *new_plan = new ThreadPlanStepOut (*this,
+ ThreadPlanSP thread_plan_sp(new ThreadPlanStepOut (*this,
addr_context,
first_insn,
stop_other_threads,
stop_vote,
run_vote,
frame_idx,
- eLazyBoolNo);
+ eLazyBoolNo));
+
+ ThreadPlanStepOut *new_plan = static_cast<ThreadPlanStepOut *>(thread_plan_sp.get());
new_plan->ClearShouldStopHereCallbacks();
- ThreadPlanSP thread_plan_sp(new_plan);
-
+
if (thread_plan_sp->ValidatePlan(NULL))
{
QueueThreadPlan (thread_plan_sp, abort_other_plans);
@@ -1602,61 +1663,105 @@ Thread::QueueThreadPlanForStepUntil (bool abort_other_plans,
}
+lldb::ThreadPlanSP
+Thread::QueueThreadPlanForStepScripted (bool abort_other_plans,
+ const char *class_name,
+ bool stop_other_threads)
+{
+ ThreadPlanSP thread_plan_sp (new ThreadPlanPython (*this, class_name));
+ QueueThreadPlan (thread_plan_sp, abort_other_plans);
+ // This seems a little funny, but I don't want to have to split up the constructor and the
+ // DidPush in the scripted plan, that seems annoying.
+ // That means the constructor has to be in DidPush.
+ // So I have to validate the plan AFTER pushing it, and then take it off again...
+ if (!thread_plan_sp->ValidatePlan(nullptr))
+ {
+ DiscardThreadPlansUpToPlan(thread_plan_sp);
+ return ThreadPlanSP();
+ }
+ else
+ return thread_plan_sp;
+
+}
+
uint32_t
Thread::GetIndexID () const
{
return m_index_id;
}
-void
-Thread::DumpThreadPlans (lldb_private::Stream *s) const
+static void
+PrintPlanElement (Stream *s, const ThreadPlanSP &plan, lldb::DescriptionLevel desc_level, int32_t elem_idx)
{
- uint32_t stack_size = m_plan_stack.size();
- int i;
- s->Indent();
- s->Printf ("Plan Stack for thread #%u: tid = 0x%4.4" PRIx64 ", stack_size = %d\n", GetIndexID(), GetID(), stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
s->IndentMore();
s->Indent();
- s->Printf ("Element %d: ", i);
- m_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
+ s->Printf ("Element %d: ", elem_idx);
+ plan->GetDescription (s, desc_level);
s->EOL();
s->IndentLess();
+}
+
+static void
+PrintPlanStack (Stream *s, const std::vector<lldb::ThreadPlanSP> &plan_stack, lldb::DescriptionLevel desc_level, bool include_internal)
+{
+ int32_t print_idx = 0;
+ for (ThreadPlanSP plan_sp : plan_stack)
+ {
+ if (include_internal || !plan_sp->GetPrivate())
+ {
+ PrintPlanElement (s, plan_sp, desc_level, print_idx++);
+ }
}
+}
- stack_size = m_completed_plan_stack.size();
- if (stack_size > 0)
+void
+Thread::DumpThreadPlans (Stream *s,
+ lldb::DescriptionLevel desc_level,
+ bool include_internal,
+ bool ignore_boring_threads) const
+{
+ uint32_t stack_size;
+
+ if (ignore_boring_threads)
{
- s->Indent();
- s->Printf ("Completed Plan Stack: %d elements.\n", stack_size);
- for (i = stack_size - 1; i >= 0; i--)
+ uint32_t stack_size = m_plan_stack.size();
+ uint32_t completed_stack_size = m_completed_plan_stack.size();
+ uint32_t discarded_stack_size = m_discarded_plan_stack.size();
+ if (stack_size == 1 && completed_stack_size == 0 && discarded_stack_size == 0)
{
+ s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 "\n", GetIndexID(), GetID());
s->IndentMore();
s->Indent();
- s->Printf ("Element %d: ", i);
- m_completed_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
- s->EOL();
+ s->Printf("No active thread plans\n");
s->IndentLess();
+ return;
}
}
+ s->Indent();
+ s->Printf ("thread #%u: tid = 0x%4.4" PRIx64 ":\n", GetIndexID(), GetID());
+ s->IndentMore();
+ s->Indent();
+ s->Printf ("Active plan stack:\n");
+ PrintPlanStack (s, m_plan_stack, desc_level, include_internal);
+
+ stack_size = m_completed_plan_stack.size();
+ if (stack_size > 0)
+ {
+ s->Indent();
+ s->Printf ("Completed Plan Stack:\n");
+ PrintPlanStack (s, m_completed_plan_stack, desc_level, include_internal);
+ }
+
stack_size = m_discarded_plan_stack.size();
if (stack_size > 0)
{
s->Indent();
- s->Printf ("Discarded Plan Stack: %d elements.\n", stack_size);
- for (i = stack_size - 1; i >= 0; i--)
- {
- s->IndentMore();
- s->Indent();
- s->Printf ("Element %d: ", i);
- m_discarded_plan_stack[i]->GetDescription (s, eDescriptionLevelFull);
- s->EOL();
- s->IndentLess();
- }
+ s->Printf ("Discarded Plan Stack:\n");
+ PrintPlanStack (s, m_discarded_plan_stack, desc_level, include_internal);
}
+ s->IndentLess();
}
TargetSP
@@ -1785,7 +1890,7 @@ Thread::ReturnFromFrame (lldb::StackFrameSP frame_sp, lldb::ValueObjectSP return
// FIXME: ValueObject::Cast doesn't currently work correctly, at least not for scalars.
// Turn that back on when that works.
- if (0 && sc.function != NULL)
+ if (/* DISABLES CODE */ (0) && sc.function != NULL)
{
Type *function_type = sc.function->GetType();
if (function_type)
@@ -2011,6 +2116,7 @@ Thread::StopReasonAsCString (lldb::StopReason reason)
case eStopReasonExec: return "exec";
case eStopReasonPlanComplete: return "plan complete";
case eStopReasonThreadExiting: return "thread exiting";
+ case eStopReasonInstrumentation: return "instrumentation break";
}
@@ -2090,17 +2196,28 @@ Thread::GetStatus (Stream &strm, uint32_t start_frame, uint32_t num_frames, uint
}
bool
-Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json)
+Thread::GetDescription (Stream &strm, lldb::DescriptionLevel level, bool print_json_thread, bool print_json_stopinfo)
{
DumpUsingSettingsFormat (strm, 0);
strm.Printf("\n");
StructuredData::ObjectSP thread_info = GetExtendedInfo();
-
- if (thread_info && print_json)
+ StructuredData::ObjectSP stop_info = m_stop_info_sp->GetExtendedInfo();
+
+ if (print_json_thread || print_json_stopinfo)
{
- thread_info->Dump (strm);
- strm.Printf("\n");
+ if (thread_info && print_json_thread)
+ {
+ thread_info->Dump (strm);
+ strm.Printf("\n");
+ }
+
+ if (stop_info && print_json_stopinfo)
+ {
+ stop_info->Dump (strm);
+ strm.Printf("\n");
+ }
+
return true;
}
@@ -2194,6 +2311,8 @@ Thread::GetUnwinder ()
case llvm::Triple::aarch64:
case llvm::Triple::thumb:
case llvm::Triple::mips64:
+ case llvm::Triple::ppc:
+ case llvm::Triple::ppc64:
case llvm::Triple::hexagon:
m_unwinder_ap.reset (new UnwindLLDB (*this));
break;
diff --git a/source/Target/ThreadCollection.cpp b/source/Target/ThreadCollection.cpp
new file mode 100644
index 0000000000000..dc1e38e02420e
--- /dev/null
+++ b/source/Target/ThreadCollection.cpp
@@ -0,0 +1,62 @@
+//===-- ThreadCollection.cpp ------------------------------------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+#include <stdlib.h>
+
+#include <algorithm>
+
+#include "lldb/Target/ThreadCollection.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+ThreadCollection::ThreadCollection() :
+ m_threads(),
+ m_mutex()
+{
+}
+
+ThreadCollection::ThreadCollection(collection threads) :
+ m_threads(threads),
+ m_mutex()
+{
+}
+
+void
+ThreadCollection::AddThread (const ThreadSP &thread_sp)
+{
+ Mutex::Locker locker(GetMutex());
+ m_threads.push_back (thread_sp);
+}
+
+void
+ThreadCollection::InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx)
+{
+ Mutex::Locker locker(GetMutex());
+ if (idx < m_threads.size())
+ m_threads.insert(m_threads.begin() + idx, thread_sp);
+ else
+ m_threads.push_back (thread_sp);
+}
+
+uint32_t
+ThreadCollection::GetSize ()
+{
+ Mutex::Locker locker(GetMutex());
+ return m_threads.size();
+}
+
+ThreadSP
+ThreadCollection::GetThreadAtIndex (uint32_t idx)
+{
+ Mutex::Locker locker(GetMutex());
+ ThreadSP thread_sp;
+ if (idx < m_threads.size())
+ thread_sp = m_threads[idx];
+ return thread_sp;
+}
diff --git a/source/Target/ThreadList.cpp b/source/Target/ThreadList.cpp
index 7fb16fdac5c03..db4407b4b5791 100644
--- a/source/Target/ThreadList.cpp
+++ b/source/Target/ThreadList.cpp
@@ -22,17 +22,17 @@ using namespace lldb;
using namespace lldb_private;
ThreadList::ThreadList (Process *process) :
+ ThreadCollection(),
m_process (process),
m_stop_id (0),
- m_threads(),
m_selected_tid (LLDB_INVALID_THREAD_ID)
{
}
ThreadList::ThreadList (const ThreadList &rhs) :
+ ThreadCollection(),
m_process (rhs.m_process),
m_stop_id (rhs.m_stop_id),
- m_threads (),
m_selected_tid ()
{
// Use the assignment operator since it uses the mutex
@@ -77,25 +77,6 @@ ThreadList::SetStopID (uint32_t stop_id)
m_stop_id = stop_id;
}
-
-void
-ThreadList::AddThread (const ThreadSP &thread_sp)
-{
- Mutex::Locker locker(GetMutex());
- m_threads.push_back(thread_sp);
-}
-
-void
-ThreadList::InsertThread (const lldb::ThreadSP &thread_sp, uint32_t idx)
-{
- Mutex::Locker locker(GetMutex());
- if (idx < m_threads.size())
- m_threads.insert(m_threads.begin() + idx, thread_sp);
- else
- m_threads.push_back (thread_sp);
-}
-
-
uint32_t
ThreadList::GetSize (bool can_update)
{
diff --git a/source/Target/ThreadPlanPython.cpp b/source/Target/ThreadPlanPython.cpp
new file mode 100644
index 0000000000000..e196d81c897a1
--- /dev/null
+++ b/source/Target/ThreadPlanPython.cpp
@@ -0,0 +1,192 @@
+//===-- ThreadPlan.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-python.h"
+
+#include "lldb/Target/ThreadPlan.h"
+
+// C Includes
+// C++ Includes
+// Other libraries and framework includes
+// Project includes
+#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
+#include "lldb/Core/State.h"
+#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreter.h"
+#include "lldb/Interpreter/ScriptInterpreterPython.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Thread.h"
+#include "lldb/Target/ThreadPlan.h"
+#include "lldb/Target/ThreadPlanPython.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/Target.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+//----------------------------------------------------------------------
+// ThreadPlanPython
+//----------------------------------------------------------------------
+
+ThreadPlanPython::ThreadPlanPython (Thread &thread, const char *class_name) :
+ ThreadPlan (ThreadPlan::eKindPython,
+ "Python based Thread Plan",
+ thread,
+ eVoteNoOpinion,
+ eVoteNoOpinion),
+ m_class_name (class_name)
+{
+ SetIsMasterPlan (true);
+ SetOkayToDiscard (true);
+ SetPrivate (false);
+}
+
+ThreadPlanPython::~ThreadPlanPython ()
+{
+ // FIXME, do I need to decrement the ref count on this implementation object to make it go away?
+}
+
+bool
+ThreadPlanPython::ValidatePlan (Stream *error)
+{
+ // I have to postpone setting up the implementation till after the constructor because I need to call
+ // shared_from_this, which you can't do in the constructor. So I'll do it here.
+ if (m_implementation_sp)
+ return true;
+ else
+ return false;
+}
+
+void
+ThreadPlanPython::DidPush()
+{
+ // We set up the script side in DidPush, so that it can push other plans in the constructor,
+ // and doesn't have to care about the details of DidPush.
+
+ if (!m_class_name.empty())
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ m_implementation_sp = script_interp->CreateScriptedThreadPlan (m_class_name.c_str(), this->shared_from_this());
+ }
+ }
+}
+
+bool
+ThreadPlanPython::ShouldStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+
+ bool should_stop = true;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ should_stop = script_interp->ScriptedThreadPlanShouldStop (m_implementation_sp, event_ptr, script_error);
+ if (script_error)
+ SetPlanComplete(false);
+ }
+ }
+ return should_stop;
+}
+
+bool
+ThreadPlanPython::DoPlanExplainsStop (Event *event_ptr)
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+
+ bool explains_stop = true;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ explains_stop = script_interp->ScriptedThreadPlanExplainsStop (m_implementation_sp, event_ptr, script_error);
+ if (script_error)
+ SetPlanComplete(false);
+ }
+ }
+ return explains_stop;
+}
+
+bool
+ThreadPlanPython::MischiefManaged ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+ bool mischief_managed = true;
+ if (m_implementation_sp)
+ {
+ // I don't really need mischief_managed, since it's simpler to just call SetPlanComplete in should_stop.
+ mischief_managed = IsPlanComplete();
+ if (mischief_managed)
+ m_implementation_sp.reset();
+ }
+ return mischief_managed;
+}
+
+lldb::StateType
+ThreadPlanPython::GetPlanRunState ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__,
+ m_class_name.c_str());
+ lldb::StateType run_state = eStateRunning;
+ if (m_implementation_sp)
+ {
+ ScriptInterpreter *script_interp = m_thread.GetProcess()->GetTarget().GetDebugger().GetCommandInterpreter().GetScriptInterpreter();
+ if (script_interp)
+ {
+ bool script_error;
+ run_state = script_interp->ScriptedThreadPlanGetRunState (m_implementation_sp, script_error);
+ }
+ }
+ return run_state;
+}
+
+// The ones below are not currently exported to Python.
+
+bool
+ThreadPlanPython::StopOthers ()
+{
+ // For now Python plans run all threads, but we should add some controls for this.
+ return false;
+}
+
+void
+ThreadPlanPython::GetDescription (Stream *s,
+ lldb::DescriptionLevel level)
+{
+ s->Printf ("Python thread plan implemented by class %s.", m_class_name.c_str());
+}
+
+bool
+ThreadPlanPython::WillStop ()
+{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_THREAD));
+ if (log)
+ log->Printf ("%s called on Python Thread Plan: %s )",
+ __PRETTY_FUNCTION__, m_class_name.c_str());
+ return true;
+}
diff --git a/source/Target/ThreadPlanStepInRange.cpp b/source/Target/ThreadPlanStepInRange.cpp
index 3e9abef65573d..e5f057c183fbe 100644
--- a/source/Target/ThreadPlanStepInRange.cpp
+++ b/source/Target/ThreadPlanStepInRange.cpp
@@ -105,7 +105,6 @@ ThreadPlanStepInRange::SetupAvoidNoDebug(LazyBool step_in_avoids_code_without_de
else
GetFlags().Clear (ThreadPlanShouldStopHere::eStepInAvoidNoDebug);
- avoid_nodebug = true;
switch (step_out_avoids_code_without_debug_info)
{
case eLazyBoolYes:
@@ -128,17 +127,31 @@ void
ThreadPlanStepInRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
+ {
s->Printf("step in");
- else
+ return;
+ }
+
+ s->Printf ("Stepping in");
+ bool printed_line_info = false;
+ if (m_addr_context.line_entry.IsValid())
+ {
+ s->Printf (" through line ");
+ m_addr_context.line_entry.DumpStopContext (s, false);
+ printed_line_info = true;
+ }
+
+ const char *step_into_target = m_step_into_target.AsCString();
+ if (step_into_target && step_into_target[0] != '\0')
+ s->Printf (" targeting %s", m_step_into_target.AsCString());
+
+ if (!printed_line_info || level == eDescriptionLevelVerbose)
{
- s->Printf ("Stepping through range (stepping into functions): ");
+ s->Printf (" using ranges:");
DumpRanges(s);
- const char *step_into_target = m_step_into_target.AsCString();
- if (step_into_target && step_into_target[0] != '\0')
- s->Printf (" targeting %s.", m_step_into_target.AsCString());
- else
- s->PutChar('.');
}
+
+ s->PutChar('.');
}
bool
@@ -303,6 +316,7 @@ ThreadPlanStepInRange::ShouldStop (Event *event_ptr)
else
{
m_no_more_plans = false;
+ m_sub_plan_sp->SetPrivate(true);
return false;
}
}
diff --git a/source/Target/ThreadPlanStepInstruction.cpp b/source/Target/ThreadPlanStepInstruction.cpp
index fabf63b1e9d64..0f6d7b78a9cee 100644
--- a/source/Target/ThreadPlanStepInstruction.cpp
+++ b/source/Target/ThreadPlanStepInstruction.cpp
@@ -150,7 +150,16 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- StackID cur_frame_zero_id = m_thread.GetStackFrameAtIndex(0)->GetStackID();
+ StackFrameSP cur_frame_sp = m_thread.GetStackFrameAtIndex(0);
+ if (!cur_frame_sp)
+ {
+ if (log)
+ log->Printf ("ThreadPlanStepInstruction couldn't get the 0th frame, stopping.");
+ SetPlanComplete();
+ return true;
+ }
+
+ StackID cur_frame_zero_id = cur_frame_sp->GetStackID();
if (cur_frame_zero_id == m_stack_id || m_stack_id < cur_frame_zero_id)
{
@@ -180,6 +189,24 @@ ThreadPlanStepInstruction::ShouldStop (Event *event_ptr)
{
if (return_frame->GetStackID() != m_parent_frame_id || m_start_has_symbol)
{
+ // next-instruction shouldn't step out of inlined functions. But we may have stepped into a
+ // real function that starts with an inlined function, and we do want to step out of that...
+
+ if (cur_frame_sp->IsInlined())
+ {
+ StackFrameSP parent_frame_sp = m_thread.GetFrameWithStackID(m_stack_id);
+
+ if(parent_frame_sp && parent_frame_sp->GetConcreteFrameIndex() == cur_frame_sp->GetConcreteFrameIndex())
+ {
+ SetPlanComplete();
+ if (log)
+ {
+ log->Printf("Frame we stepped into is inlined into the frame we were stepping from, stopping.");
+ }
+ return true;
+ }
+ }
+
if (log)
{
StreamString s;
diff --git a/source/Target/ThreadPlanStepOut.cpp b/source/Target/ThreadPlanStepOut.cpp
index b62f557319a81..0ded99b3091d5 100644
--- a/source/Target/ThreadPlanStepOut.cpp
+++ b/source/Target/ThreadPlanStepOut.cpp
@@ -54,7 +54,6 @@ ThreadPlanStepOut::ThreadPlanStepOut
m_return_addr (LLDB_INVALID_ADDRESS),
m_stop_others (stop_others),
m_immediate_step_from_function(NULL)
-
{
SetFlagsToDefault();
SetupAvoidNoDebug(step_out_avoids_code_without_debug_info);
@@ -90,6 +89,7 @@ ThreadPlanStepOut::ThreadPlanStepOut
frame_idx - 1,
eLazyBoolNo));
static_cast<ThreadPlanStepOut *>(m_step_out_to_inline_plan_sp.get())->SetShouldStopHereCallbacks(nullptr, nullptr);
+ m_step_out_to_inline_plan_sp->SetPrivate(true);
}
else
{
@@ -177,10 +177,34 @@ ThreadPlanStepOut::GetDescription (Stream *s, lldb::DescriptionLevel level)
else if (m_step_through_inline_plan_sp)
s->Printf ("Stepping out by stepping through inlined function.");
else
- s->Printf ("Stepping out from address 0x%" PRIx64 " to return address 0x%" PRIx64 " using breakpoint site %d",
- (uint64_t)m_step_from_insn,
- (uint64_t)m_return_addr,
- m_return_bp_id);
+ {
+ s->Printf ("Stepping out from ");
+ Address tmp_address;
+ if (tmp_address.SetLoadAddress (m_step_from_insn, &GetTarget()))
+ {
+ tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_step_from_insn);
+ }
+
+ // FIXME: find some useful way to present the m_return_id, since there may be multiple copies of the
+ // same function on the stack.
+
+ s->Printf ("returning to frame at ");
+ if (tmp_address.SetLoadAddress (m_return_addr, &GetTarget()))
+ {
+ tmp_address.Dump(s, &GetThread(), Address::DumpStyleResolvedDescription, Address::DumpStyleLoadAddress);
+ }
+ else
+ {
+ s->Printf ("address 0x%" PRIx64 "", (uint64_t)m_return_addr);
+ }
+
+ if (level == eDescriptionLevelVerbose)
+ s->Printf(" using breakpoint site %d", m_return_bp_id);
+ }
}
}
@@ -474,11 +498,16 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
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,
- avoid_no_debug);
+
+ m_step_through_inline_plan_sp.reset (new ThreadPlanStepOverRange(m_thread,
+ inline_range,
+ inlined_sc,
+ run_mode,
+ avoid_no_debug));
+ ThreadPlanStepOverRange *step_through_inline_plan_ptr
+ = static_cast<ThreadPlanStepOverRange *>(m_step_through_inline_plan_sp.get());
+ m_step_through_inline_plan_sp->SetPrivate(true);
+
step_through_inline_plan_ptr->SetOkayToDiscard(true);
StreamString errors;
if (!step_through_inline_plan_ptr->ValidatePlan(&errors))
@@ -493,7 +522,7 @@ ThreadPlanStepOut::QueueInlinedStepPlan (bool queue_now)
if (inlined_block->GetRangeAtIndex (i, inline_range))
step_through_inline_plan_ptr->AddRange (inline_range);
}
- m_step_through_inline_plan_sp.reset (step_through_inline_plan_ptr);
+
if (queue_now)
m_thread.QueueThreadPlan (m_step_through_inline_plan_sp, false);
return true;
diff --git a/source/Target/ThreadPlanStepOverBreakpoint.cpp b/source/Target/ThreadPlanStepOverBreakpoint.cpp
index dc011e5454023..6f285e25fd0b6 100644
--- a/source/Target/ThreadPlanStepOverBreakpoint.cpp
+++ b/source/Target/ThreadPlanStepOverBreakpoint.cpp
@@ -64,11 +64,33 @@ ThreadPlanStepOverBreakpoint::DoPlanExplainsStop (Event *event_ptr)
StopInfoSP stop_info_sp = GetPrivateStopInfo ();
if (stop_info_sp)
{
+ // It's a little surprising that we stop here for a breakpoint hit. However, when you single step ONTO a breakpoint
+ // we still want to call that a breakpoint hit, and trigger the actions, etc. Otherwise you would see the
+ // PC at the breakpoint without having triggered the actions, then you'd continue, the PC wouldn't change,
+ // and you'd see the breakpoint hit, which would be odd.
+ // So the lower levels fake "step onto breakpoint address" and return that as a breakpoint. So our trace
+ // step COULD appear as a breakpoint hit if the next instruction also contained a breakpoint.
StopReason reason = stop_info_sp->GetStopReason();
- if (reason == eStopReasonTrace || reason == eStopReasonNone)
+
+ switch (reason)
+ {
+ case eStopReasonTrace:
+ case eStopReasonNone:
return true;
- else
+ case eStopReasonBreakpoint:
+ // It's a little surprising that we stop here for a breakpoint hit. However, when you single step ONTO a
+ // breakpoint we still want to call that a breakpoint hit, and trigger the actions, etc. Otherwise you
+ // would see the PC at the breakpoint without having triggered the actions, then you'd continue, the PC
+ // wouldn't change, and you'd see the breakpoint hit, which would be odd.
+ // So the lower levels fake "step onto breakpoint address" and return that as a breakpoint hit. So our trace
+ // step COULD appear as a breakpoint hit if the next instruction also contained a breakpoint. We don't want
+ // to handle that, since we really don't know what to do with breakpoint hits. But make sure we don't set
+ // ourselves to auto-continue or we'll wrench control away from the plans that can deal with this.
+ SetAutoContinue(false);
+ return false;
+ default:
return false;
+ }
}
return false;
}
@@ -76,7 +98,7 @@ ThreadPlanStepOverBreakpoint::DoPlanExplainsStop (Event *event_ptr)
bool
ThreadPlanStepOverBreakpoint::ShouldStop (Event *event_ptr)
{
- return false;
+ return !ShouldAutoContinue(event_ptr);
}
bool
@@ -163,3 +185,10 @@ ThreadPlanStepOverBreakpoint::ShouldAutoContinue (Event *event_ptr)
{
return m_auto_continue;
}
+
+bool
+ThreadPlanStepOverBreakpoint::IsPlanStale()
+{
+ return m_thread.GetRegisterContext()->GetPC() != m_breakpoint_addr;
+}
+
diff --git a/source/Target/ThreadPlanStepOverRange.cpp b/source/Target/ThreadPlanStepOverRange.cpp
index a4f3743346e21..a6d65e4d81164 100644
--- a/source/Target/ThreadPlanStepOverRange.cpp
+++ b/source/Target/ThreadPlanStepOverRange.cpp
@@ -62,12 +62,26 @@ void
ThreadPlanStepOverRange::GetDescription (Stream *s, lldb::DescriptionLevel level)
{
if (level == lldb::eDescriptionLevelBrief)
+ {
s->Printf("step over");
- else
+ return;
+ }
+ s->Printf ("Stepping over");
+ bool printed_line_info = false;
+ if (m_addr_context.line_entry.IsValid())
+ {
+ s->Printf (" line ");
+ m_addr_context.line_entry.DumpStopContext (s, false);
+ printed_line_info = true;
+ }
+
+ if (!printed_line_info || level == eDescriptionLevelVerbose)
{
- s->Printf ("stepping through range (stepping over functions): ");
- DumpRanges(s);
+ s->Printf (" using ranges: ");
+ DumpRanges(s);
}
+
+ s->PutChar('.');
}
void
@@ -317,11 +331,15 @@ ThreadPlanStepOverRange::ShouldStop (Event *event_ptr)
{
new_plan_sp = CheckShouldStopHereAndQueueStepOut (frame_order);
}
-
+
if (!new_plan_sp)
m_no_more_plans = true;
else
+ {
+ // Any new plan will be an implementation plan, so mark it private:
+ new_plan_sp->SetPrivate(true);
m_no_more_plans = false;
+ }
if (!new_plan_sp)
{
diff --git a/source/Target/ThreadPlanStepRange.cpp b/source/Target/ThreadPlanStepRange.cpp
index 82ca59fbca39f..adc515cebc08e 100644
--- a/source/Target/ThreadPlanStepRange.cpp
+++ b/source/Target/ThreadPlanStepRange.cpp
@@ -44,7 +44,8 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
Thread &thread,
const AddressRange &range,
const SymbolContext &addr_context,
- lldb::RunMode stop_others) :
+ lldb::RunMode stop_others,
+ bool given_ranges_only) :
ThreadPlan (kind, name, thread, eVoteNoOpinion, eVoteNoOpinion),
m_addr_context (addr_context),
m_address_ranges (),
@@ -53,7 +54,8 @@ ThreadPlanStepRange::ThreadPlanStepRange (ThreadPlanKind kind,
m_parent_stack_id(),
m_no_more_plans (false),
m_first_run_event (true),
- m_use_fast_step(false)
+ m_use_fast_step(false),
+ m_given_ranges_only (given_ranges_only)
{
m_use_fast_step = GetTarget().GetUseFastStepping();
AddRange(range);
@@ -149,7 +151,7 @@ ThreadPlanStepRange::InRange ()
break;
}
- if (!ret_value)
+ if (!ret_value && !m_given_ranges_only)
{
// See if we've just stepped to another part of the same line number...
StackFrame *frame = m_thread.GetStackFrameAtIndex(0).get();
diff --git a/source/Target/ThreadPlanStepThrough.cpp b/source/Target/ThreadPlanStepThrough.cpp
index 18da6cdbd59cf..5b50a41a6398d 100644
--- a/source/Target/ThreadPlanStepThrough.cpp
+++ b/source/Target/ThreadPlanStepThrough.cpp
@@ -87,7 +87,10 @@ ThreadPlanStepThrough::DidPush ()
void
ThreadPlanStepThrough::LookForPlanToStepThroughFromCurrentPC()
{
- m_sub_plan_sp = m_thread.GetProcess()->GetDynamicLoader()->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
+ DynamicLoader *loader = m_thread.GetProcess()->GetDynamicLoader();
+ if (loader)
+ m_sub_plan_sp = loader->GetStepThroughTrampolinePlan (m_thread, m_stop_others);
+
// If that didn't come up with anything, try the ObjC runtime plugin:
if (!m_sub_plan_sp.get())
{
diff --git a/source/Target/ThreadPlanTracer.cpp b/source/Target/ThreadPlanTracer.cpp
index 5188df6d91936..d2b039d69f673 100644
--- a/source/Target/ThreadPlanTracer.cpp
+++ b/source/Target/ThreadPlanTracer.cpp
@@ -212,11 +212,15 @@ ThreadPlanAssemblyTracer::Log ()
const bool show_bytes = true;
const bool show_address = true;
Instruction *instruction = instruction_list.GetInstructionAtIndex(0).get();
+ const char *disassemble_format = "${addr-file-or-load}: ";
instruction->Dump (stream,
max_opcode_byte_size,
show_address,
show_bytes,
- NULL);
+ NULL,
+ NULL,
+ NULL,
+ disassemble_format);
}
}
}