[Lldb-commits] [lldb] r280751 - *** This commit represents a complete reformatting of the LLDB source code
Kate Stone via lldb-commits
lldb-commits at lists.llvm.org
Tue Sep 6 13:58:36 PDT 2016
Modified: lldb/trunk/source/Target/Process.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Process.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/Process.cpp (original)
+++ lldb/trunk/source/Target/Process.cpp Tue Sep 6 15:57:50 2016
@@ -68,7 +68,8 @@
using namespace lldb;
using namespace lldb_private;
-// Comment out line below to disable memory caching, overriding the process setting
+// Comment out line below to disable memory caching, overriding the process
+// setting
// target.process.disable-memory-cache
#define ENABLE_MEMORY_CACHING
@@ -78,6693 +79,6194 @@ using namespace lldb_private;
#define DISABLE_MEM_CACHE_DEFAULT true
#endif
-class ProcessOptionValueProperties : public OptionValueProperties
-{
+class ProcessOptionValueProperties : public OptionValueProperties {
public:
- ProcessOptionValueProperties (const ConstString &name) :
- OptionValueProperties (name)
- {
- }
-
- // This constructor is used when creating ProcessOptionValueProperties when it
- // is part of a new lldb_private::Process instance. It will copy all current
- // global property values as needed
- ProcessOptionValueProperties (ProcessProperties *global_properties) :
- OptionValueProperties(*global_properties->GetValueProperties())
- {
- }
-
- const Property *
- GetPropertyAtIndex(const ExecutionContext *exe_ctx, bool will_modify, uint32_t idx) const override
- {
- // When getting the value for a key from the process options, we will always
- // try and grab the setting from the current process if there is one. Else we just
- // use the one from this instance.
- if (exe_ctx)
- {
- Process *process = exe_ctx->GetProcessPtr();
- if (process)
- {
- ProcessOptionValueProperties *instance_properties = static_cast<ProcessOptionValueProperties *>(process->GetValueProperties().get());
- if (this != instance_properties)
- return instance_properties->ProtectedGetPropertyAtIndex (idx);
- }
- }
- return ProtectedGetPropertyAtIndex (idx);
+ ProcessOptionValueProperties(const ConstString &name)
+ : OptionValueProperties(name) {}
+
+ // This constructor is used when creating ProcessOptionValueProperties when it
+ // is part of a new lldb_private::Process instance. It will copy all current
+ // global property values as needed
+ ProcessOptionValueProperties(ProcessProperties *global_properties)
+ : OptionValueProperties(*global_properties->GetValueProperties()) {}
+
+ const Property *GetPropertyAtIndex(const ExecutionContext *exe_ctx,
+ bool will_modify,
+ uint32_t idx) const override {
+ // When getting the value for a key from the process options, we will always
+ // try and grab the setting from the current process if there is one. Else
+ // we just
+ // use the one from this instance.
+ if (exe_ctx) {
+ Process *process = exe_ctx->GetProcessPtr();
+ if (process) {
+ ProcessOptionValueProperties *instance_properties =
+ static_cast<ProcessOptionValueProperties *>(
+ process->GetValueProperties().get());
+ if (this != instance_properties)
+ return instance_properties->ProtectedGetPropertyAtIndex(idx);
+ }
}
+ return ProtectedGetPropertyAtIndex(idx);
+ }
};
-static PropertyDefinition
-g_properties[] =
-{
- { "disable-memory-cache" , OptionValue::eTypeBoolean, false, DISABLE_MEM_CACHE_DEFAULT, nullptr, nullptr, "Disable reading and caching of memory in fixed-size units." },
- { "extra-startup-command", OptionValue::eTypeArray , false, OptionValue::eTypeString, nullptr, nullptr, "A list containing extra commands understood by the particular process plugin used. "
- "For instance, to turn on debugserver logging set this to \"QSetLogging:bitmask=LOG_DEFAULT;\"" },
- { "ignore-breakpoints-in-expressions", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, breakpoints will be ignored during expression evaluation." },
- { "unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, true, nullptr, nullptr, "If true, errors in expression evaluation will unwind the stack back to the state before the call." },
- { "python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, nullptr, nullptr, "A path to a python OS plug-in module file that contains a OperatingSystemPlugIn class." },
- { "stop-on-sharedlibrary-events" , OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, stop when a shared library is loaded or unloaded." },
- { "detach-keeps-stopped" , OptionValue::eTypeBoolean, true, false, nullptr, nullptr, "If true, detach will attempt to keep the process stopped." },
- { "memory-cache-line-size" , OptionValue::eTypeUInt64, false, 512, nullptr, nullptr, "The memory cache line size" },
- { "optimization-warnings" , OptionValue::eTypeBoolean, false, true, nullptr, nullptr, "If true, warn when stopped in code that is optimized where stepping and variable availability may not behave as expected." },
- { nullptr , OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr }
-};
+static PropertyDefinition g_properties[] = {
+ {"disable-memory-cache", OptionValue::eTypeBoolean, false,
+ DISABLE_MEM_CACHE_DEFAULT, nullptr, nullptr,
+ "Disable reading and caching of memory in fixed-size units."},
+ {"extra-startup-command", OptionValue::eTypeArray, false,
+ OptionValue::eTypeString, nullptr, nullptr,
+ "A list containing extra commands understood by the particular process "
+ "plugin used. "
+ "For instance, to turn on debugserver logging set this to "
+ "\"QSetLogging:bitmask=LOG_DEFAULT;\""},
+ {"ignore-breakpoints-in-expressions", OptionValue::eTypeBoolean, true, true,
+ nullptr, nullptr,
+ "If true, breakpoints will be ignored during expression evaluation."},
+ {"unwind-on-error-in-expressions", OptionValue::eTypeBoolean, true, true,
+ nullptr, nullptr, "If true, errors in expression evaluation will unwind "
+ "the stack back to the state before the call."},
+ {"python-os-plugin-path", OptionValue::eTypeFileSpec, false, true, nullptr,
+ nullptr, "A path to a python OS plug-in module file that contains a "
+ "OperatingSystemPlugIn class."},
+ {"stop-on-sharedlibrary-events", OptionValue::eTypeBoolean, true, false,
+ nullptr, nullptr,
+ "If true, stop when a shared library is loaded or unloaded."},
+ {"detach-keeps-stopped", OptionValue::eTypeBoolean, true, false, nullptr,
+ nullptr, "If true, detach will attempt to keep the process stopped."},
+ {"memory-cache-line-size", OptionValue::eTypeUInt64, false, 512, nullptr,
+ nullptr, "The memory cache line size"},
+ {"optimization-warnings", OptionValue::eTypeBoolean, false, true, nullptr,
+ nullptr, "If true, warn when stopped in code that is optimized where "
+ "stepping and variable availability may not behave as expected."},
+ {nullptr, OptionValue::eTypeInvalid, false, 0, nullptr, nullptr, nullptr}};
enum {
- ePropertyDisableMemCache,
- ePropertyExtraStartCommand,
- ePropertyIgnoreBreakpointsInExpressions,
- ePropertyUnwindOnErrorInExpressions,
- ePropertyPythonOSPluginPath,
- ePropertyStopOnSharedLibraryEvents,
- ePropertyDetachKeepsStopped,
- ePropertyMemCacheLineSize,
- ePropertyWarningOptimization
+ ePropertyDisableMemCache,
+ ePropertyExtraStartCommand,
+ ePropertyIgnoreBreakpointsInExpressions,
+ ePropertyUnwindOnErrorInExpressions,
+ ePropertyPythonOSPluginPath,
+ ePropertyStopOnSharedLibraryEvents,
+ ePropertyDetachKeepsStopped,
+ ePropertyMemCacheLineSize,
+ ePropertyWarningOptimization
};
-ProcessProperties::ProcessProperties (lldb_private::Process *process) :
- Properties(),
- m_process(process) // Can be nullptr for global ProcessProperties
-{
- if (process == nullptr)
- {
- // Global process properties, set them up one time
- m_collection_sp.reset (new ProcessOptionValueProperties(ConstString("process")));
- m_collection_sp->Initialize(g_properties);
- m_collection_sp->AppendProperty(ConstString("thread"),
- ConstString("Settings specific to threads."),
- true,
- Thread::GetGlobalProperties()->GetValueProperties());
- }
- else
- {
- m_collection_sp.reset (new ProcessOptionValueProperties(Process::GetGlobalProperties().get()));
- m_collection_sp->SetValueChangedCallback(ePropertyPythonOSPluginPath, ProcessProperties::OptionValueChangedCallback, this);
- }
+ProcessProperties::ProcessProperties(lldb_private::Process *process)
+ : Properties(),
+ m_process(process) // Can be nullptr for global ProcessProperties
+{
+ if (process == nullptr) {
+ // Global process properties, set them up one time
+ m_collection_sp.reset(
+ new ProcessOptionValueProperties(ConstString("process")));
+ m_collection_sp->Initialize(g_properties);
+ m_collection_sp->AppendProperty(
+ ConstString("thread"), ConstString("Settings specific to threads."),
+ true, Thread::GetGlobalProperties()->GetValueProperties());
+ } else {
+ m_collection_sp.reset(
+ new ProcessOptionValueProperties(Process::GetGlobalProperties().get()));
+ m_collection_sp->SetValueChangedCallback(
+ ePropertyPythonOSPluginPath,
+ ProcessProperties::OptionValueChangedCallback, this);
+ }
}
ProcessProperties::~ProcessProperties() = default;
-void
-ProcessProperties::OptionValueChangedCallback (void *baton, OptionValue *option_value)
-{
- ProcessProperties *properties = (ProcessProperties *)baton;
- if (properties->m_process)
- properties->m_process->LoadOperatingSystemPlugin(true);
+void ProcessProperties::OptionValueChangedCallback(void *baton,
+ OptionValue *option_value) {
+ ProcessProperties *properties = (ProcessProperties *)baton;
+ if (properties->m_process)
+ properties->m_process->LoadOperatingSystemPlugin(true);
}
-bool
-ProcessProperties::GetDisableMemoryCache() const
-{
- const uint32_t idx = ePropertyDisableMemCache;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);
+bool ProcessProperties::GetDisableMemoryCache() const {
+ const uint32_t idx = ePropertyDisableMemCache;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
}
-uint64_t
-ProcessProperties::GetMemoryCacheLineSize() const
-{
- const uint32_t idx = ePropertyMemCacheLineSize;
- return m_collection_sp->GetPropertyAtIndexAsUInt64(nullptr, idx, g_properties[idx].default_uint_value);
+uint64_t ProcessProperties::GetMemoryCacheLineSize() const {
+ const uint32_t idx = ePropertyMemCacheLineSize;
+ return m_collection_sp->GetPropertyAtIndexAsUInt64(
+ nullptr, idx, g_properties[idx].default_uint_value);
}
-Args
-ProcessProperties::GetExtraStartupCommands () const
-{
- Args args;
- const uint32_t idx = ePropertyExtraStartCommand;
- m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args);
- return args;
+Args ProcessProperties::GetExtraStartupCommands() const {
+ Args args;
+ const uint32_t idx = ePropertyExtraStartCommand;
+ m_collection_sp->GetPropertyAtIndexAsArgs(nullptr, idx, args);
+ return args;
}
-void
-ProcessProperties::SetExtraStartupCommands (const Args &args)
-{
- const uint32_t idx = ePropertyExtraStartCommand;
- m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args);
+void ProcessProperties::SetExtraStartupCommands(const Args &args) {
+ const uint32_t idx = ePropertyExtraStartCommand;
+ m_collection_sp->SetPropertyAtIndexFromArgs(nullptr, idx, args);
}
-FileSpec
-ProcessProperties::GetPythonOSPluginPath () const
-{
- const uint32_t idx = ePropertyPythonOSPluginPath;
- return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx);
+FileSpec ProcessProperties::GetPythonOSPluginPath() const {
+ const uint32_t idx = ePropertyPythonOSPluginPath;
+ return m_collection_sp->GetPropertyAtIndexAsFileSpec(nullptr, idx);
}
-void
-ProcessProperties::SetPythonOSPluginPath (const FileSpec &file)
-{
- const uint32_t idx = ePropertyPythonOSPluginPath;
- m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file);
+void ProcessProperties::SetPythonOSPluginPath(const FileSpec &file) {
+ const uint32_t idx = ePropertyPythonOSPluginPath;
+ m_collection_sp->SetPropertyAtIndexAsFileSpec(nullptr, idx, file);
}
-bool
-ProcessProperties::GetIgnoreBreakpointsInExpressions () const
-{
- const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);
+bool ProcessProperties::GetIgnoreBreakpointsInExpressions() const {
+ const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
}
-
-void
-ProcessProperties::SetIgnoreBreakpointsInExpressions (bool ignore)
-{
- const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
- m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore);
+
+void ProcessProperties::SetIgnoreBreakpointsInExpressions(bool ignore) {
+ const uint32_t idx = ePropertyIgnoreBreakpointsInExpressions;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore);
}
-bool
-ProcessProperties::GetUnwindOnErrorInExpressions () const
-{
- const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);
+bool ProcessProperties::GetUnwindOnErrorInExpressions() const {
+ const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
}
-
-void
-ProcessProperties::SetUnwindOnErrorInExpressions (bool ignore)
-{
- const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
- m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore);
+
+void ProcessProperties::SetUnwindOnErrorInExpressions(bool ignore) {
+ const uint32_t idx = ePropertyUnwindOnErrorInExpressions;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, ignore);
}
-bool
-ProcessProperties::GetStopOnSharedLibraryEvents () const
-{
- const uint32_t idx = ePropertyStopOnSharedLibraryEvents;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);
+bool ProcessProperties::GetStopOnSharedLibraryEvents() const {
+ const uint32_t idx = ePropertyStopOnSharedLibraryEvents;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
}
-
-void
-ProcessProperties::SetStopOnSharedLibraryEvents (bool stop)
-{
- const uint32_t idx = ePropertyStopOnSharedLibraryEvents;
- m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop);
+
+void ProcessProperties::SetStopOnSharedLibraryEvents(bool stop) {
+ const uint32_t idx = ePropertyStopOnSharedLibraryEvents;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop);
}
-bool
-ProcessProperties::GetDetachKeepsStopped () const
-{
- const uint32_t idx = ePropertyDetachKeepsStopped;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);
+bool ProcessProperties::GetDetachKeepsStopped() const {
+ const uint32_t idx = ePropertyDetachKeepsStopped;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
}
-
-void
-ProcessProperties::SetDetachKeepsStopped (bool stop)
-{
- const uint32_t idx = ePropertyDetachKeepsStopped;
- m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop);
+
+void ProcessProperties::SetDetachKeepsStopped(bool stop) {
+ const uint32_t idx = ePropertyDetachKeepsStopped;
+ m_collection_sp->SetPropertyAtIndexAsBoolean(nullptr, idx, stop);
}
-bool
-ProcessProperties::GetWarningsOptimization () const
-{
- const uint32_t idx = ePropertyWarningOptimization;
- return m_collection_sp->GetPropertyAtIndexAsBoolean(nullptr, idx, g_properties[idx].default_uint_value != 0);
+bool ProcessProperties::GetWarningsOptimization() const {
+ const uint32_t idx = ePropertyWarningOptimization;
+ return m_collection_sp->GetPropertyAtIndexAsBoolean(
+ nullptr, idx, g_properties[idx].default_uint_value != 0);
}
-void
-ProcessInstanceInfo::Dump (Stream &s, Platform *platform) const
-{
- const char *cstr;
- if (m_pid != LLDB_INVALID_PROCESS_ID)
- s.Printf (" pid = %" PRIu64 "\n", m_pid);
+void ProcessInstanceInfo::Dump(Stream &s, Platform *platform) const {
+ const char *cstr;
+ if (m_pid != LLDB_INVALID_PROCESS_ID)
+ s.Printf(" pid = %" PRIu64 "\n", m_pid);
- if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
- s.Printf (" parent = %" PRIu64 "\n", m_parent_pid);
+ if (m_parent_pid != LLDB_INVALID_PROCESS_ID)
+ s.Printf(" parent = %" PRIu64 "\n", m_parent_pid);
- if (m_executable)
- {
- s.Printf (" name = %s\n", m_executable.GetFilename().GetCString());
- s.PutCString (" file = ");
- m_executable.Dump(&s);
- s.EOL();
- }
- const uint32_t argc = m_arguments.GetArgumentCount();
- if (argc > 0)
- {
- for (uint32_t i = 0; i < argc; i++)
- {
- const char *arg = m_arguments.GetArgumentAtIndex(i);
- if (i < 10)
- s.Printf (" arg[%u] = %s\n", i, arg);
- else
- s.Printf ("arg[%u] = %s\n", i, arg);
- }
+ if (m_executable) {
+ s.Printf(" name = %s\n", m_executable.GetFilename().GetCString());
+ s.PutCString(" file = ");
+ m_executable.Dump(&s);
+ s.EOL();
+ }
+ const uint32_t argc = m_arguments.GetArgumentCount();
+ if (argc > 0) {
+ for (uint32_t i = 0; i < argc; i++) {
+ const char *arg = m_arguments.GetArgumentAtIndex(i);
+ if (i < 10)
+ s.Printf(" arg[%u] = %s\n", i, arg);
+ else
+ s.Printf("arg[%u] = %s\n", i, arg);
}
+ }
- const uint32_t envc = m_environment.GetArgumentCount();
- if (envc > 0)
- {
- for (uint32_t i = 0; i < envc; i++)
- {
- const char *env = m_environment.GetArgumentAtIndex(i);
- if (i < 10)
- s.Printf (" env[%u] = %s\n", i, env);
- else
- s.Printf ("env[%u] = %s\n", i, env);
- }
+ const uint32_t envc = m_environment.GetArgumentCount();
+ if (envc > 0) {
+ for (uint32_t i = 0; i < envc; i++) {
+ const char *env = m_environment.GetArgumentAtIndex(i);
+ if (i < 10)
+ s.Printf(" env[%u] = %s\n", i, env);
+ else
+ s.Printf("env[%u] = %s\n", i, env);
}
+ }
- if (m_arch.IsValid())
- {
- s.Printf (" arch = ");
- m_arch.DumpTriple(s);
- s.EOL();
- }
+ if (m_arch.IsValid()) {
+ s.Printf(" arch = ");
+ m_arch.DumpTriple(s);
+ s.EOL();
+ }
- if (m_uid != UINT32_MAX)
- {
- cstr = platform->GetUserName (m_uid);
- s.Printf (" uid = %-5u (%s)\n", m_uid, cstr ? cstr : "");
- }
- if (m_gid != UINT32_MAX)
- {
- cstr = platform->GetGroupName (m_gid);
- s.Printf (" gid = %-5u (%s)\n", m_gid, cstr ? cstr : "");
- }
- if (m_euid != UINT32_MAX)
- {
- cstr = platform->GetUserName (m_euid);
- s.Printf (" euid = %-5u (%s)\n", m_euid, cstr ? cstr : "");
- }
- if (m_egid != UINT32_MAX)
- {
- cstr = platform->GetGroupName (m_egid);
- s.Printf (" egid = %-5u (%s)\n", m_egid, cstr ? cstr : "");
- }
+ if (m_uid != UINT32_MAX) {
+ cstr = platform->GetUserName(m_uid);
+ s.Printf(" uid = %-5u (%s)\n", m_uid, cstr ? cstr : "");
+ }
+ if (m_gid != UINT32_MAX) {
+ cstr = platform->GetGroupName(m_gid);
+ s.Printf(" gid = %-5u (%s)\n", m_gid, cstr ? cstr : "");
+ }
+ if (m_euid != UINT32_MAX) {
+ cstr = platform->GetUserName(m_euid);
+ s.Printf(" euid = %-5u (%s)\n", m_euid, cstr ? cstr : "");
+ }
+ if (m_egid != UINT32_MAX) {
+ cstr = platform->GetGroupName(m_egid);
+ s.Printf(" egid = %-5u (%s)\n", m_egid, cstr ? cstr : "");
+ }
}
-void
-ProcessInstanceInfo::DumpTableHeader (Stream &s, Platform *platform, bool show_args, bool verbose)
-{
- const char *label;
- if (show_args || verbose)
- label = "ARGUMENTS";
- else
- label = "NAME";
+void ProcessInstanceInfo::DumpTableHeader(Stream &s, Platform *platform,
+ bool show_args, bool verbose) {
+ const char *label;
+ if (show_args || verbose)
+ label = "ARGUMENTS";
+ else
+ label = "NAME";
- if (verbose)
- {
- s.Printf ("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE %s\n", label);
- s.PutCString ("====== ====== ========== ========== ========== ========== ======================== ============================\n");
- }
- else
- {
- s.Printf ("PID PARENT USER TRIPLE %s\n", label);
- s.PutCString ("====== ====== ========== ======================== ============================\n");
- }
+ if (verbose) {
+ s.Printf("PID PARENT USER GROUP EFF USER EFF GROUP TRIPLE "
+ " %s\n",
+ label);
+ s.PutCString("====== ====== ========== ========== ========== ========== "
+ "======================== ============================\n");
+ } else {
+ s.Printf("PID PARENT USER TRIPLE %s\n", label);
+ s.PutCString("====== ====== ========== ======================== "
+ "============================\n");
+ }
}
-void
-ProcessInstanceInfo::DumpAsTableRow (Stream &s, Platform *platform, bool show_args, bool verbose) const
-{
- if (m_pid != LLDB_INVALID_PROCESS_ID)
- {
- const char *cstr;
- s.Printf ("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
-
- StreamString arch_strm;
- if (m_arch.IsValid())
- m_arch.DumpTriple(arch_strm);
-
- if (verbose)
- {
- cstr = platform->GetUserName (m_uid);
- if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
- s.Printf ("%-10s ", cstr);
- else
- s.Printf ("%-10u ", m_uid);
-
- cstr = platform->GetGroupName (m_gid);
- if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
- s.Printf ("%-10s ", cstr);
- else
- s.Printf ("%-10u ", m_gid);
+void ProcessInstanceInfo::DumpAsTableRow(Stream &s, Platform *platform,
+ bool show_args, bool verbose) const {
+ if (m_pid != LLDB_INVALID_PROCESS_ID) {
+ const char *cstr;
+ s.Printf("%-6" PRIu64 " %-6" PRIu64 " ", m_pid, m_parent_pid);
- cstr = platform->GetUserName (m_euid);
- if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
- s.Printf ("%-10s ", cstr);
- else
- s.Printf ("%-10u ", m_euid);
-
- cstr = platform->GetGroupName (m_egid);
- if (cstr && cstr[0]) // Watch for empty string that indicates lookup failed
- s.Printf ("%-10s ", cstr);
- else
- s.Printf ("%-10u ", m_egid);
+ StreamString arch_strm;
+ if (m_arch.IsValid())
+ m_arch.DumpTriple(arch_strm);
- s.Printf ("%-24s ", arch_strm.GetString().c_str());
- }
- else
- {
- s.Printf ("%-10s %-24s ",
- platform->GetUserName (m_euid),
- arch_strm.GetString().c_str());
- }
+ if (verbose) {
+ cstr = platform->GetUserName(m_uid);
+ if (cstr &&
+ cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf("%-10s ", cstr);
+ else
+ s.Printf("%-10u ", m_uid);
+
+ cstr = platform->GetGroupName(m_gid);
+ if (cstr &&
+ cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf("%-10s ", cstr);
+ else
+ s.Printf("%-10u ", m_gid);
+
+ cstr = platform->GetUserName(m_euid);
+ if (cstr &&
+ cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf("%-10s ", cstr);
+ else
+ s.Printf("%-10u ", m_euid);
+
+ cstr = platform->GetGroupName(m_egid);
+ if (cstr &&
+ cstr[0]) // Watch for empty string that indicates lookup failed
+ s.Printf("%-10s ", cstr);
+ else
+ s.Printf("%-10u ", m_egid);
+
+ s.Printf("%-24s ", arch_strm.GetString().c_str());
+ } else {
+ s.Printf("%-10s %-24s ", platform->GetUserName(m_euid),
+ arch_strm.GetString().c_str());
+ }
+
+ if (verbose || show_args) {
+ const uint32_t argc = m_arguments.GetArgumentCount();
+ if (argc > 0) {
+ for (uint32_t i = 0; i < argc; i++) {
+ if (i > 0)
+ s.PutChar(' ');
+ s.PutCString(m_arguments.GetArgumentAtIndex(i));
+ }
+ }
+ } else {
+ s.PutCString(GetName());
+ }
+
+ s.EOL();
+ }
+}
+
+Error ProcessLaunchCommandOptions::SetOptionValue(
+ uint32_t option_idx, const char *option_arg,
+ ExecutionContext *execution_context) {
+ Error error;
+ const int short_option = m_getopt_table[option_idx].val;
+
+ switch (short_option) {
+ case 's': // Stop at program entry point
+ launch_info.GetFlags().Set(eLaunchFlagStopAtEntry);
+ break;
+
+ case 'i': // STDIN for read only
+ {
+ FileAction action;
+ if (action.Open(STDIN_FILENO, FileSpec{option_arg, false}, true, false))
+ launch_info.AppendFileAction(action);
+ break;
+ }
+
+ case 'o': // Open STDOUT for write only
+ {
+ FileAction action;
+ if (action.Open(STDOUT_FILENO, FileSpec{option_arg, false}, false, true))
+ launch_info.AppendFileAction(action);
+ break;
+ }
+
+ case 'e': // STDERR for write only
+ {
+ FileAction action;
+ if (action.Open(STDERR_FILENO, FileSpec{option_arg, false}, false, true))
+ launch_info.AppendFileAction(action);
+ break;
+ }
+
+ case 'p': // Process plug-in name
+ launch_info.SetProcessPluginName(option_arg);
+ break;
+
+ case 'n': // Disable STDIO
+ {
+ FileAction action;
+ const FileSpec dev_null{FileSystem::DEV_NULL, false};
+ if (action.Open(STDIN_FILENO, dev_null, true, false))
+ launch_info.AppendFileAction(action);
+ if (action.Open(STDOUT_FILENO, dev_null, false, true))
+ launch_info.AppendFileAction(action);
+ if (action.Open(STDERR_FILENO, dev_null, false, true))
+ launch_info.AppendFileAction(action);
+ break;
+ }
+
+ case 'w':
+ launch_info.SetWorkingDirectory(FileSpec{option_arg, false});
+ break;
+
+ case 't': // Open process in new terminal window
+ launch_info.GetFlags().Set(eLaunchFlagLaunchInTTY);
+ break;
+
+ case 'a': {
+ TargetSP target_sp =
+ execution_context ? execution_context->GetTargetSP() : TargetSP();
+ PlatformSP platform_sp =
+ target_sp ? target_sp->GetPlatform() : PlatformSP();
+ if (!launch_info.GetArchitecture().SetTriple(option_arg, platform_sp.get()))
+ launch_info.GetArchitecture().SetTriple(option_arg);
+ } break;
+
+ case 'A': // Disable ASLR.
+ {
+ bool success;
+ const bool disable_aslr_arg =
+ Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo;
+ else
+ error.SetErrorStringWithFormat(
+ "Invalid boolean value for disable-aslr option: '%s'",
+ option_arg ? option_arg : "<null>");
+ break;
+ }
+
+ case 'X': // shell expand args.
+ {
+ bool success;
+ const bool expand_args = Args::StringToBoolean(option_arg, true, &success);
+ if (success)
+ launch_info.SetShellExpandArguments(expand_args);
+ else
+ error.SetErrorStringWithFormat(
+ "Invalid boolean value for shell-expand-args option: '%s'",
+ option_arg ? option_arg : "<null>");
+ break;
+ }
+
+ case 'c':
+ if (option_arg && option_arg[0])
+ launch_info.SetShell(FileSpec(option_arg, false));
+ else
+ launch_info.SetShell(HostInfo::GetDefaultShell());
+ break;
+
+ case 'v':
+ launch_info.GetEnvironmentEntries().AppendArgument(option_arg);
+ break;
+
+ default:
+ error.SetErrorStringWithFormat("unrecognized short option character '%c'",
+ short_option);
+ break;
+ }
+ return error;
+}
+
+OptionDefinition ProcessLaunchCommandOptions::g_option_table[] = {
+ {LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument,
+ nullptr, nullptr, 0, eArgTypeNone,
+ "Stop at the entry point of the program when launching a process."},
+ {LLDB_OPT_SET_ALL, false, "disable-aslr", 'A',
+ OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,
+ "Set whether to disable address space layout randomization when launching "
+ "a process."},
+ {LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument,
+ nullptr, nullptr, 0, eArgTypePlugin,
+ "Name of the process plugin you want to use."},
+ {LLDB_OPT_SET_ALL, false, "working-dir", 'w',
+ OptionParser::eRequiredArgument, nullptr, nullptr, 0,
+ eArgTypeDirectoryName,
+ "Set the current working directory to <path> when running the inferior."},
+ {LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument,
+ nullptr, nullptr, 0, eArgTypeArchitecture,
+ "Set the architecture for the process to launch when ambiguous."},
+ {LLDB_OPT_SET_ALL, false, "environment", 'v',
+ OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone,
+ "Specify an environment variable name/value string (--environment "
+ "NAME=VALUE). Can be specified multiple times for subsequent environment "
+ "entries."},
+ {LLDB_OPT_SET_1 | LLDB_OPT_SET_2 | LLDB_OPT_SET_3, false, "shell", 'c',
+ OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeFilename,
+ "Run the process in a shell (not supported on all platforms)."},
+
+ {LLDB_OPT_SET_1, false, "stdin", 'i', OptionParser::eRequiredArgument,
+ nullptr, nullptr, 0, eArgTypeFilename,
+ "Redirect stdin for the process to <filename>."},
+ {LLDB_OPT_SET_1, false, "stdout", 'o', OptionParser::eRequiredArgument,
+ nullptr, nullptr, 0, eArgTypeFilename,
+ "Redirect stdout for the process to <filename>."},
+ {LLDB_OPT_SET_1, false, "stderr", 'e', OptionParser::eRequiredArgument,
+ nullptr, nullptr, 0, eArgTypeFilename,
+ "Redirect stderr for the process to <filename>."},
+
+ {LLDB_OPT_SET_2, false, "tty", 't', OptionParser::eNoArgument, nullptr,
+ nullptr, 0, eArgTypeNone,
+ "Start the process in a terminal (not supported on all platforms)."},
+
+ {LLDB_OPT_SET_3, false, "no-stdio", 'n', OptionParser::eNoArgument, nullptr,
+ nullptr, 0, eArgTypeNone,
+ "Do not set up for terminal I/O to go to running process."},
+ {LLDB_OPT_SET_4, false, "shell-expand-args", 'X',
+ OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean,
+ "Set whether to shell expand arguments to the process when launching."},
+ {0, false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr}};
- if (verbose || show_args)
- {
- const uint32_t argc = m_arguments.GetArgumentCount();
- if (argc > 0)
- {
- for (uint32_t i = 0; i < argc; i++)
- {
- if (i > 0)
- s.PutChar (' ');
- s.PutCString (m_arguments.GetArgumentAtIndex(i));
- }
- }
- }
- else
- {
- s.PutCString (GetName());
- }
+bool ProcessInstanceInfoMatch::NameMatches(const char *process_name) const {
+ if (m_name_match_type == eNameMatchIgnore || process_name == nullptr)
+ return true;
+ const char *match_name = m_match_info.GetName();
+ if (!match_name)
+ return true;
- s.EOL();
- }
+ return lldb_private::NameMatches(process_name, m_name_match_type, match_name);
}
-Error
-ProcessLaunchCommandOptions::SetOptionValue(uint32_t option_idx,
- const char *option_arg,
- ExecutionContext *execution_context)
-{
- Error error;
- const int short_option = m_getopt_table[option_idx].val;
-
- switch (short_option)
- {
- case 's': // Stop at program entry point
- launch_info.GetFlags().Set (eLaunchFlagStopAtEntry);
- break;
-
- case 'i': // STDIN for read only
- {
- FileAction action;
- if (action.Open(STDIN_FILENO, FileSpec{option_arg, false}, true, false))
- launch_info.AppendFileAction (action);
- break;
- }
-
- case 'o': // Open STDOUT for write only
- {
- FileAction action;
- if (action.Open(STDOUT_FILENO, FileSpec{option_arg, false}, false, true))
- launch_info.AppendFileAction (action);
- break;
- }
+bool ProcessInstanceInfoMatch::Matches(
+ const ProcessInstanceInfo &proc_info) const {
+ if (!NameMatches(proc_info.GetName()))
+ return false;
- case 'e': // STDERR for write only
- {
- FileAction action;
- if (action.Open(STDERR_FILENO, FileSpec{option_arg, false}, false, true))
- launch_info.AppendFileAction (action);
- break;
- }
+ if (m_match_info.ProcessIDIsValid() &&
+ m_match_info.GetProcessID() != proc_info.GetProcessID())
+ return false;
- case 'p': // Process plug-in name
- launch_info.SetProcessPluginName (option_arg);
- break;
-
- case 'n': // Disable STDIO
- {
- FileAction action;
- const FileSpec dev_null{FileSystem::DEV_NULL, false};
- if (action.Open(STDIN_FILENO, dev_null, true, false))
- launch_info.AppendFileAction (action);
- if (action.Open(STDOUT_FILENO, dev_null, false, true))
- launch_info.AppendFileAction (action);
- if (action.Open(STDERR_FILENO, dev_null, false, true))
- launch_info.AppendFileAction (action);
- break;
- }
-
- case 'w':
- launch_info.SetWorkingDirectory(FileSpec{option_arg, false});
- break;
-
- case 't': // Open process in new terminal window
- launch_info.GetFlags().Set (eLaunchFlagLaunchInTTY);
- break;
-
- case 'a':
- {
- TargetSP target_sp = execution_context ?
- execution_context->GetTargetSP() : TargetSP();
- PlatformSP platform_sp = target_sp ?
- target_sp->GetPlatform() : PlatformSP();
- if (!launch_info.GetArchitecture().SetTriple (option_arg, platform_sp.get()))
- launch_info.GetArchitecture().SetTriple (option_arg);
- }
- break;
-
- case 'A': // Disable ASLR.
- {
- bool success;
- const bool disable_aslr_arg = Args::StringToBoolean (option_arg, true, &success);
- if (success)
- disable_aslr = disable_aslr_arg ? eLazyBoolYes : eLazyBoolNo;
- else
- error.SetErrorStringWithFormat ("Invalid boolean value for disable-aslr option: '%s'", option_arg ? option_arg : "<null>");
- break;
- }
+ if (m_match_info.ParentProcessIDIsValid() &&
+ m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
+ return false;
- case 'X': // shell expand args.
- {
- bool success;
- const bool expand_args = Args::StringToBoolean (option_arg, true, &success);
- if (success)
- launch_info.SetShellExpandArguments(expand_args);
- else
- error.SetErrorStringWithFormat ("Invalid boolean value for shell-expand-args option: '%s'", option_arg ? option_arg : "<null>");
- break;
- }
-
- case 'c':
- if (option_arg && option_arg[0])
- launch_info.SetShell (FileSpec(option_arg, false));
- else
- launch_info.SetShell (HostInfo::GetDefaultShell());
- break;
-
- case 'v':
- launch_info.GetEnvironmentEntries().AppendArgument(option_arg);
- break;
+ if (m_match_info.UserIDIsValid() &&
+ m_match_info.GetUserID() != proc_info.GetUserID())
+ return false;
- default:
- error.SetErrorStringWithFormat("unrecognized short option character '%c'", short_option);
- break;
- }
- return error;
-}
+ if (m_match_info.GroupIDIsValid() &&
+ m_match_info.GetGroupID() != proc_info.GetGroupID())
+ return false;
-OptionDefinition
-ProcessLaunchCommandOptions::g_option_table[] =
-{
-{ LLDB_OPT_SET_ALL, false, "stop-at-entry", 's', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Stop at the entry point of the program when launching a process." },
-{ LLDB_OPT_SET_ALL, false, "disable-aslr", 'A', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set whether to disable address space layout randomization when launching a process." },
-{ LLDB_OPT_SET_ALL, false, "plugin", 'p', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypePlugin, "Name of the process plugin you want to use." },
-{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior." },
-{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous." },
-{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries." },
-{ LLDB_OPT_SET_1|LLDB_OPT_SET_2|LLDB_OPT_SET_3, false, "shell", 'c', OptionParser::eOptionalArgument, nullptr, nullptr, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)." },
-
-{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>." },
-{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>." },
-{ LLDB_OPT_SET_1 , false, "stderr", 'e', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeFilename, "Redirect stderr for the process to <filename>." },
-
-{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)." },
-
-{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, nullptr, nullptr, 0, eArgTypeNone, "Do not set up for terminal I/O to go to running process." },
-{ LLDB_OPT_SET_4, false, "shell-expand-args", 'X', OptionParser::eRequiredArgument, nullptr, nullptr, 0, eArgTypeBoolean, "Set whether to shell expand arguments to the process when launching." },
-{ 0 , false, nullptr, 0, 0, nullptr, nullptr, 0, eArgTypeNone, nullptr }
-};
+ if (m_match_info.EffectiveUserIDIsValid() &&
+ m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
+ return false;
-bool
-ProcessInstanceInfoMatch::NameMatches (const char *process_name) const
-{
- if (m_name_match_type == eNameMatchIgnore || process_name == nullptr)
- return true;
- const char *match_name = m_match_info.GetName();
- if (!match_name)
- return true;
-
- return lldb_private::NameMatches (process_name, m_name_match_type, match_name);
+ if (m_match_info.EffectiveGroupIDIsValid() &&
+ m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
+ return false;
+
+ if (m_match_info.GetArchitecture().IsValid() &&
+ !m_match_info.GetArchitecture().IsCompatibleMatch(
+ proc_info.GetArchitecture()))
+ return false;
+ return true;
}
-bool
-ProcessInstanceInfoMatch::Matches (const ProcessInstanceInfo &proc_info) const
-{
- if (!NameMatches (proc_info.GetName()))
- return false;
+bool ProcessInstanceInfoMatch::MatchAllProcesses() const {
+ if (m_name_match_type != eNameMatchIgnore)
+ return false;
- if (m_match_info.ProcessIDIsValid() &&
- m_match_info.GetProcessID() != proc_info.GetProcessID())
- return false;
-
- if (m_match_info.ParentProcessIDIsValid() &&
- m_match_info.GetParentProcessID() != proc_info.GetParentProcessID())
- return false;
-
- if (m_match_info.UserIDIsValid () &&
- m_match_info.GetUserID() != proc_info.GetUserID())
- return false;
-
- if (m_match_info.GroupIDIsValid () &&
- m_match_info.GetGroupID() != proc_info.GetGroupID())
- return false;
-
- if (m_match_info.EffectiveUserIDIsValid () &&
- m_match_info.GetEffectiveUserID() != proc_info.GetEffectiveUserID())
- return false;
-
- if (m_match_info.EffectiveGroupIDIsValid () &&
- m_match_info.GetEffectiveGroupID() != proc_info.GetEffectiveGroupID())
- return false;
-
- if (m_match_info.GetArchitecture().IsValid() &&
- !m_match_info.GetArchitecture().IsCompatibleMatch(proc_info.GetArchitecture()))
- return false;
- return true;
-}
+ if (m_match_info.ProcessIDIsValid())
+ return false;
-bool
-ProcessInstanceInfoMatch::MatchAllProcesses () const
-{
- if (m_name_match_type != eNameMatchIgnore)
- return false;
-
- if (m_match_info.ProcessIDIsValid())
- return false;
-
- if (m_match_info.ParentProcessIDIsValid())
- return false;
-
- if (m_match_info.UserIDIsValid ())
- return false;
-
- if (m_match_info.GroupIDIsValid ())
- return false;
-
- if (m_match_info.EffectiveUserIDIsValid ())
- return false;
-
- if (m_match_info.EffectiveGroupIDIsValid ())
- return false;
-
- if (m_match_info.GetArchitecture().IsValid())
- return false;
+ if (m_match_info.ParentProcessIDIsValid())
+ return false;
- if (m_match_all_users)
- return false;
+ if (m_match_info.UserIDIsValid())
+ return false;
- return true;
-}
+ if (m_match_info.GroupIDIsValid())
+ return false;
-void
-ProcessInstanceInfoMatch::Clear()
-{
- m_match_info.Clear();
- m_name_match_type = eNameMatchIgnore;
- m_match_all_users = false;
-}
+ if (m_match_info.EffectiveUserIDIsValid())
+ return false;
-ProcessSP
-Process::FindPlugin (lldb::TargetSP target_sp, const char *plugin_name, ListenerSP listener_sp, const FileSpec *crash_file_path)
-{
- static uint32_t g_process_unique_id = 0;
+ if (m_match_info.EffectiveGroupIDIsValid())
+ return false;
- ProcessSP process_sp;
- ProcessCreateInstance create_callback = nullptr;
- if (plugin_name)
- {
- ConstString const_plugin_name(plugin_name);
- create_callback = PluginManager::GetProcessCreateCallbackForPluginName (const_plugin_name);
- if (create_callback)
- {
- process_sp = create_callback(target_sp, listener_sp, crash_file_path);
- if (process_sp)
- {
- if (process_sp->CanDebug(target_sp, true))
- {
- process_sp->m_process_unique_id = ++g_process_unique_id;
- }
- else
- process_sp.reset();
- }
- }
- }
- else
- {
- for (uint32_t idx = 0; (create_callback = PluginManager::GetProcessCreateCallbackAtIndex(idx)) != nullptr; ++idx)
- {
- process_sp = create_callback(target_sp, listener_sp, crash_file_path);
- if (process_sp)
- {
- if (process_sp->CanDebug(target_sp, false))
- {
- process_sp->m_process_unique_id = ++g_process_unique_id;
- break;
- }
- else
- process_sp.reset();
- }
- }
- }
- return process_sp;
-}
+ if (m_match_info.GetArchitecture().IsValid())
+ return false;
-ConstString &
-Process::GetStaticBroadcasterClass ()
-{
- static ConstString class_name ("lldb.process");
- return class_name;
-}
+ if (m_match_all_users)
+ return false;
-Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp) :
- Process(target_sp, listener_sp, UnixSignals::Create(HostInfo::GetArchitecture()))
-{
- // This constructor just delegates to the full Process constructor,
- // defaulting to using the Host's UnixSignals.
+ return true;
}
-Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp, const UnixSignalsSP &unix_signals_sp)
- : ProcessProperties(this),
- UserID(LLDB_INVALID_PROCESS_ID),
- Broadcaster((target_sp->GetDebugger().GetBroadcasterManager()), Process::GetStaticBroadcasterClass().AsCString()),
- m_target_sp(target_sp),
- m_public_state(eStateUnloaded),
+void ProcessInstanceInfoMatch::Clear() {
+ m_match_info.Clear();
+ m_name_match_type = eNameMatchIgnore;
+ m_match_all_users = false;
+}
+
+ProcessSP Process::FindPlugin(lldb::TargetSP target_sp, const char *plugin_name,
+ ListenerSP listener_sp,
+ const FileSpec *crash_file_path) {
+ static uint32_t g_process_unique_id = 0;
+
+ ProcessSP process_sp;
+ ProcessCreateInstance create_callback = nullptr;
+ if (plugin_name) {
+ ConstString const_plugin_name(plugin_name);
+ create_callback =
+ PluginManager::GetProcessCreateCallbackForPluginName(const_plugin_name);
+ if (create_callback) {
+ process_sp = create_callback(target_sp, listener_sp, crash_file_path);
+ if (process_sp) {
+ if (process_sp->CanDebug(target_sp, true)) {
+ process_sp->m_process_unique_id = ++g_process_unique_id;
+ } else
+ process_sp.reset();
+ }
+ }
+ } else {
+ for (uint32_t idx = 0;
+ (create_callback =
+ PluginManager::GetProcessCreateCallbackAtIndex(idx)) != nullptr;
+ ++idx) {
+ process_sp = create_callback(target_sp, listener_sp, crash_file_path);
+ if (process_sp) {
+ if (process_sp->CanDebug(target_sp, false)) {
+ process_sp->m_process_unique_id = ++g_process_unique_id;
+ break;
+ } else
+ process_sp.reset();
+ }
+ }
+ }
+ return process_sp;
+}
+
+ConstString &Process::GetStaticBroadcasterClass() {
+ static ConstString class_name("lldb.process");
+ return class_name;
+}
+
+Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp)
+ : Process(target_sp, listener_sp,
+ UnixSignals::Create(HostInfo::GetArchitecture())) {
+ // This constructor just delegates to the full Process constructor,
+ // defaulting to using the Host's UnixSignals.
+}
+
+Process::Process(lldb::TargetSP target_sp, ListenerSP listener_sp,
+ const UnixSignalsSP &unix_signals_sp)
+ : ProcessProperties(this), UserID(LLDB_INVALID_PROCESS_ID),
+ Broadcaster((target_sp->GetDebugger().GetBroadcasterManager()),
+ Process::GetStaticBroadcasterClass().AsCString()),
+ m_target_sp(target_sp), m_public_state(eStateUnloaded),
m_private_state(eStateUnloaded),
- m_private_state_broadcaster(nullptr, "lldb.process.internal_state_broadcaster"),
- m_private_state_control_broadcaster(nullptr, "lldb.process.internal_state_control_broadcaster"),
- m_private_state_listener_sp(Listener::MakeListener("lldb.process.internal_state_listener")),
- m_mod_id(),
- m_process_unique_id(0),
- m_thread_index_id(0),
- m_thread_id_to_index_id_map(),
- m_exit_status(-1),
- m_exit_string(),
- m_exit_status_mutex(),
- m_thread_mutex(),
- m_thread_list_real(this),
- m_thread_list(this),
- m_extended_thread_list(this),
- m_extended_thread_stop_id(0),
- m_queue_list(this),
- m_queue_list_stop_id(0),
- m_notifications(),
- m_image_tokens(),
- m_listener_sp(listener_sp),
- m_breakpoint_site_list(),
- m_dynamic_checkers_ap(),
- m_unix_signals_sp(unix_signals_sp),
- m_abi_sp(),
- m_process_input_reader(),
- m_stdio_communication("process.stdio"),
- m_stdio_communication_mutex(),
- m_stdin_forward(false),
- m_stdout_data(),
- m_stderr_data(),
- m_profile_data_comm_mutex(),
- m_profile_data(),
- m_iohandler_sync(0),
- m_memory_cache(*this),
- m_allocated_memory_cache(*this),
- m_should_detach(false),
- m_next_event_action_ap(),
- m_public_run_lock(),
- m_private_run_lock(),
- m_stop_info_override_callback(nullptr),
- m_finalizing(false),
- m_finalize_called(false),
- m_clear_thread_plans_on_stop(false),
- m_force_next_event_delivery(false),
- m_last_broadcast_state(eStateInvalid),
- m_destroy_in_process(false),
- m_can_interpret_function_calls(false),
- m_warnings_issued(),
- m_run_thread_plan_lock(),
- m_can_jit(eCanJITDontKnow)
-{
- CheckInWithManager();
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
- if (log)
- log->Printf("%p Process::Process()", static_cast<void *>(this));
-
- if (!m_unix_signals_sp)
- m_unix_signals_sp = std::make_shared<UnixSignals>();
+ m_private_state_broadcaster(nullptr,
+ "lldb.process.internal_state_broadcaster"),
+ m_private_state_control_broadcaster(
+ nullptr, "lldb.process.internal_state_control_broadcaster"),
+ m_private_state_listener_sp(
+ Listener::MakeListener("lldb.process.internal_state_listener")),
+ m_mod_id(), m_process_unique_id(0), m_thread_index_id(0),
+ m_thread_id_to_index_id_map(), m_exit_status(-1), m_exit_string(),
+ m_exit_status_mutex(), m_thread_mutex(), m_thread_list_real(this),
+ m_thread_list(this), m_extended_thread_list(this),
+ m_extended_thread_stop_id(0), m_queue_list(this), m_queue_list_stop_id(0),
+ m_notifications(), m_image_tokens(), m_listener_sp(listener_sp),
+ m_breakpoint_site_list(), m_dynamic_checkers_ap(),
+ m_unix_signals_sp(unix_signals_sp), m_abi_sp(), m_process_input_reader(),
+ m_stdio_communication("process.stdio"), m_stdio_communication_mutex(),
+ m_stdin_forward(false), m_stdout_data(), m_stderr_data(),
+ m_profile_data_comm_mutex(), m_profile_data(), m_iohandler_sync(0),
+ m_memory_cache(*this), m_allocated_memory_cache(*this),
+ m_should_detach(false), m_next_event_action_ap(), m_public_run_lock(),
+ m_private_run_lock(), m_stop_info_override_callback(nullptr),
+ m_finalizing(false), m_finalize_called(false),
+ m_clear_thread_plans_on_stop(false), m_force_next_event_delivery(false),
+ m_last_broadcast_state(eStateInvalid), m_destroy_in_process(false),
+ m_can_interpret_function_calls(false), m_warnings_issued(),
+ m_run_thread_plan_lock(), m_can_jit(eCanJITDontKnow) {
+ CheckInWithManager();
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf("%p Process::Process()", static_cast<void *>(this));
+
+ if (!m_unix_signals_sp)
+ m_unix_signals_sp = std::make_shared<UnixSignals>();
+
+ SetEventName(eBroadcastBitStateChanged, "state-changed");
+ SetEventName(eBroadcastBitInterrupt, "interrupt");
+ SetEventName(eBroadcastBitSTDOUT, "stdout-available");
+ SetEventName(eBroadcastBitSTDERR, "stderr-available");
+ SetEventName(eBroadcastBitProfileData, "profile-data-available");
+ SetEventName(eBroadcastBitStructuredData, "structured-data-available");
+
+ m_private_state_control_broadcaster.SetEventName(
+ eBroadcastInternalStateControlStop, "control-stop");
+ m_private_state_control_broadcaster.SetEventName(
+ eBroadcastInternalStateControlPause, "control-pause");
+ m_private_state_control_broadcaster.SetEventName(
+ eBroadcastInternalStateControlResume, "control-resume");
+
+ m_listener_sp->StartListeningForEvents(
+ this, eBroadcastBitStateChanged | eBroadcastBitInterrupt |
+ eBroadcastBitSTDOUT | eBroadcastBitSTDERR |
+ eBroadcastBitProfileData | eBroadcastBitStructuredData);
+
+ m_private_state_listener_sp->StartListeningForEvents(
+ &m_private_state_broadcaster,
+ eBroadcastBitStateChanged | eBroadcastBitInterrupt);
+
+ m_private_state_listener_sp->StartListeningForEvents(
+ &m_private_state_control_broadcaster,
+ eBroadcastInternalStateControlStop | eBroadcastInternalStateControlPause |
+ eBroadcastInternalStateControlResume);
+ // We need something valid here, even if just the default UnixSignalsSP.
+ assert(m_unix_signals_sp && "null m_unix_signals_sp after initialization");
+
+ // Allow the platform to override the default cache line size
+ OptionValueSP value_sp =
+ m_collection_sp
+ ->GetPropertyAtIndex(nullptr, true, ePropertyMemCacheLineSize)
+ ->GetValue();
+ uint32_t platform_cache_line_size =
+ target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize();
+ if (!value_sp->OptionWasSet() && platform_cache_line_size != 0)
+ value_sp->SetUInt64Value(platform_cache_line_size);
+}
+
+Process::~Process() {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_OBJECT));
+ if (log)
+ log->Printf("%p Process::~Process()", static_cast<void *>(this));
+ StopPrivateStateThread();
+
+ // ThreadList::Clear() will try to acquire this process's mutex, so
+ // explicitly clear the thread list here to ensure that the mutex
+ // is not destroyed before the thread list.
+ m_thread_list.Clear();
+}
+
+const ProcessPropertiesSP &Process::GetGlobalProperties() {
+ // NOTE: intentional leak so we don't crash if global destructor chain gets
+ // called as other threads still use the result of this function
+ static ProcessPropertiesSP *g_settings_sp_ptr = nullptr;
+ static std::once_flag g_once_flag;
+ std::call_once(g_once_flag, []() {
+ g_settings_sp_ptr = new ProcessPropertiesSP(new ProcessProperties(nullptr));
+ });
+ return *g_settings_sp_ptr;
+}
+
+void Process::Finalize() {
+ m_finalizing = true;
+
+ // Destroy this process if needed
+ switch (GetPrivateState()) {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStopped:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ Destroy(false);
+ break;
+
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateDetached:
+ case eStateExited:
+ break;
+ }
+
+ // Clear our broadcaster before we proceed with destroying
+ Broadcaster::Clear();
+
+ // Do any cleanup needed prior to being destructed... Subclasses
+ // that override this method should call this superclass method as well.
+
+ // We need to destroy the loader before the derived Process class gets
+ // destroyed
+ // since it is very likely that undoing the loader will require access to the
+ // real process.
+ m_dynamic_checkers_ap.reset();
+ m_abi_sp.reset();
+ m_os_ap.reset();
+ m_system_runtime_ap.reset();
+ m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
+ m_thread_list_real.Destroy();
+ m_thread_list.Destroy();
+ m_extended_thread_list.Destroy();
+ m_queue_list.Clear();
+ m_queue_list_stop_id = 0;
+ std::vector<Notifications> empty_notifications;
+ m_notifications.swap(empty_notifications);
+ m_image_tokens.clear();
+ m_memory_cache.Clear();
+ m_allocated_memory_cache.Clear();
+ m_language_runtimes.clear();
+ m_instrumentation_runtimes.clear();
+ m_next_event_action_ap.reset();
+ m_stop_info_override_callback = nullptr;
+ // Clear the last natural stop ID since it has a strong
+ // reference to this process
+ m_mod_id.SetStopEventForLastNaturalStopID(EventSP());
+ //#ifdef LLDB_CONFIGURATION_DEBUG
+ // StreamFile s(stdout, false);
+ // EventSP event_sp;
+ // while (m_private_state_listener_sp->GetNextEvent(event_sp))
+ // {
+ // event_sp->Dump (&s);
+ // s.EOL();
+ // }
+ //#endif
+ // We have to be very careful here as the m_private_state_listener might
+ // contain events that have ProcessSP values in them which can keep this
+ // process around forever. These events need to be cleared out.
+ m_private_state_listener_sp->Clear();
+ m_public_run_lock.TrySetRunning(); // This will do nothing if already locked
+ m_public_run_lock.SetStopped();
+ m_private_run_lock.TrySetRunning(); // This will do nothing if already locked
+ m_private_run_lock.SetStopped();
+ m_finalize_called = true;
+}
+
+void Process::RegisterNotificationCallbacks(const Notifications &callbacks) {
+ m_notifications.push_back(callbacks);
+ if (callbacks.initialize != nullptr)
+ callbacks.initialize(callbacks.baton, this);
+}
+
+bool Process::UnregisterNotificationCallbacks(const Notifications &callbacks) {
+ std::vector<Notifications>::iterator pos, end = m_notifications.end();
+ for (pos = m_notifications.begin(); pos != end; ++pos) {
+ if (pos->baton == callbacks.baton &&
+ pos->initialize == callbacks.initialize &&
+ pos->process_state_changed == callbacks.process_state_changed) {
+ m_notifications.erase(pos);
+ return true;
+ }
+ }
+ return false;
+}
+
+void Process::SynchronouslyNotifyStateChanged(StateType state) {
+ std::vector<Notifications>::iterator notification_pos,
+ notification_end = m_notifications.end();
+ for (notification_pos = m_notifications.begin();
+ notification_pos != notification_end; ++notification_pos) {
+ if (notification_pos->process_state_changed)
+ notification_pos->process_state_changed(notification_pos->baton, this,
+ state);
+ }
+}
+
+// FIXME: We need to do some work on events before the general Listener sees
+// them.
+// For instance if we are continuing from a breakpoint, we need to ensure that
+// we do
+// the little "insert real insn, step & stop" trick. But we can't do that when
+// the
+// event is delivered by the broadcaster - since that is done on the thread that
+// is
+// waiting for new events, so if we needed more than one event for our handling,
+// we would
+// stall. So instead we do it when we fetch the event off of the queue.
+//
- SetEventName(eBroadcastBitStateChanged, "state-changed");
- SetEventName(eBroadcastBitInterrupt, "interrupt");
- SetEventName(eBroadcastBitSTDOUT, "stdout-available");
- SetEventName(eBroadcastBitSTDERR, "stderr-available");
- SetEventName(eBroadcastBitProfileData, "profile-data-available");
- SetEventName(eBroadcastBitStructuredData, "structured-data-available");
-
- m_private_state_control_broadcaster.SetEventName(eBroadcastInternalStateControlStop, "control-stop");
- m_private_state_control_broadcaster.SetEventName(eBroadcastInternalStateControlPause, "control-pause");
- m_private_state_control_broadcaster.SetEventName(eBroadcastInternalStateControlResume, "control-resume");
-
- m_listener_sp->StartListeningForEvents(this, eBroadcastBitStateChanged | eBroadcastBitInterrupt |
- eBroadcastBitSTDOUT | eBroadcastBitSTDERR |
- eBroadcastBitProfileData |
- eBroadcastBitStructuredData);
-
- m_private_state_listener_sp->StartListeningForEvents(&m_private_state_broadcaster,
- eBroadcastBitStateChanged | eBroadcastBitInterrupt);
-
- m_private_state_listener_sp->StartListeningForEvents(
- &m_private_state_control_broadcaster, eBroadcastInternalStateControlStop | eBroadcastInternalStateControlPause |
- eBroadcastInternalStateControlResume);
- // We need something valid here, even if just the default UnixSignalsSP.
- assert(m_unix_signals_sp && "null m_unix_signals_sp after initialization");
-
- // Allow the platform to override the default cache line size
- OptionValueSP value_sp = m_collection_sp->GetPropertyAtIndex(nullptr, true, ePropertyMemCacheLineSize)->GetValue();
- uint32_t platform_cache_line_size = target_sp->GetPlatform()->GetDefaultMemoryCacheLineSize();
- if (!value_sp->OptionWasSet() && platform_cache_line_size != 0)
- value_sp->SetUInt64Value(platform_cache_line_size);
-}
+StateType Process::GetNextEvent(EventSP &event_sp) {
+ StateType state = eStateInvalid;
-Process::~Process()
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_OBJECT));
- if (log)
- log->Printf ("%p Process::~Process()", static_cast<void*>(this));
- StopPrivateStateThread();
+ if (m_listener_sp->GetNextEventForBroadcaster(this, event_sp) && event_sp)
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- // 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();
+ return state;
}
-const ProcessPropertiesSP &
-Process::GetGlobalProperties()
-{
- // NOTE: intentional leak so we don't crash if global destructor chain gets
- // called as other threads still use the result of this function
- static ProcessPropertiesSP *g_settings_sp_ptr = nullptr;
- static std::once_flag g_once_flag;
- std::call_once(g_once_flag, []() {
- g_settings_sp_ptr = new ProcessPropertiesSP(new ProcessProperties(nullptr));
- });
- return *g_settings_sp_ptr;
+void Process::SyncIOHandler(uint32_t iohandler_id, uint64_t timeout_msec) {
+ // don't sync (potentially context switch) in case where there is no process
+ // IO
+ if (!m_process_input_reader)
+ return;
+
+ uint32_t new_iohandler_id = 0;
+ m_iohandler_sync.WaitForValueNotEqualTo(
+ iohandler_id, new_iohandler_id, std::chrono::milliseconds(timeout_msec));
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s waited for m_iohandler_sync to change from %u, "
+ "new value is %u",
+ __FUNCTION__, iohandler_id, new_iohandler_id);
}
-void
-Process::Finalize()
-{
- m_finalizing = true;
-
- // Destroy this process if needed
- switch (GetPrivateState())
- {
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- case eStateStopped:
- case eStateRunning:
- case eStateStepping:
- case eStateCrashed:
- case eStateSuspended:
- Destroy(false);
- break;
-
- case eStateInvalid:
- case eStateUnloaded:
- case eStateDetached:
- case eStateExited:
- break;
- }
-
- // Clear our broadcaster before we proceed with destroying
- Broadcaster::Clear();
-
- // Do any cleanup needed prior to being destructed... Subclasses
- // that override this method should call this superclass method as well.
-
- // We need to destroy the loader before the derived Process class gets destroyed
- // since it is very likely that undoing the loader will require access to the real process.
- m_dynamic_checkers_ap.reset();
- m_abi_sp.reset();
- m_os_ap.reset();
- m_system_runtime_ap.reset();
- m_dyld_ap.reset();
- m_jit_loaders_ap.reset();
- m_thread_list_real.Destroy();
- m_thread_list.Destroy();
- m_extended_thread_list.Destroy();
- m_queue_list.Clear();
- m_queue_list_stop_id = 0;
- std::vector<Notifications> empty_notifications;
- m_notifications.swap(empty_notifications);
- m_image_tokens.clear();
- m_memory_cache.Clear();
- m_allocated_memory_cache.Clear();
- m_language_runtimes.clear();
- m_instrumentation_runtimes.clear();
- m_next_event_action_ap.reset();
- m_stop_info_override_callback = nullptr;
- // Clear the last natural stop ID since it has a strong
- // reference to this process
- m_mod_id.SetStopEventForLastNaturalStopID(EventSP());
-//#ifdef LLDB_CONFIGURATION_DEBUG
-// StreamFile s(stdout, false);
-// EventSP event_sp;
-// while (m_private_state_listener_sp->GetNextEvent(event_sp))
-// {
-// event_sp->Dump (&s);
-// s.EOL();
-// }
-//#endif
- // We have to be very careful here as the m_private_state_listener might
- // contain events that have ProcessSP values in them which can keep this
- // process around forever. These events need to be cleared out.
- m_private_state_listener_sp->Clear();
- m_public_run_lock.TrySetRunning(); // This will do nothing if already locked
- m_public_run_lock.SetStopped();
- m_private_run_lock.TrySetRunning(); // This will do nothing if already locked
- m_private_run_lock.SetStopped();
- m_finalize_called = true;
-}
+StateType
+Process::WaitForProcessToStop(const std::chrono::microseconds &timeout,
+ EventSP *event_sp_ptr, bool wait_always,
+ ListenerSP hijack_listener_sp, Stream *stream,
+ bool use_run_lock) {
+ // We can't just wait for a "stopped" event, because the stopped event may
+ // have restarted the target.
+ // We have to actually check each event, and in the case of a stopped event
+ // check the restarted flag
+ // on the event.
+ if (event_sp_ptr)
+ event_sp_ptr->reset();
+ StateType state = GetState();
+ // If we are exited or detached, we won't ever get back to any
+ // other valid state...
+ if (state == eStateDetached || state == eStateExited)
+ return state;
-void
-Process::RegisterNotificationCallbacks (const Notifications& callbacks)
-{
- m_notifications.push_back(callbacks);
- if (callbacks.initialize != nullptr)
- callbacks.initialize (callbacks.baton, this);
-}
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s (timeout = %llu)", __FUNCTION__,
+ static_cast<unsigned long long>(timeout.count()));
-bool
-Process::UnregisterNotificationCallbacks(const Notifications& callbacks)
-{
- std::vector<Notifications>::iterator pos, end = m_notifications.end();
- for (pos = m_notifications.begin(); pos != end; ++pos)
- {
- if (pos->baton == callbacks.baton &&
- pos->initialize == callbacks.initialize &&
- pos->process_state_changed == callbacks.process_state_changed)
- {
- m_notifications.erase(pos);
- return true;
- }
- }
- return false;
-}
+ if (!wait_always && StateIsStoppedState(state, true) &&
+ StateIsStoppedState(GetPrivateState(), true)) {
+ if (log)
+ log->Printf("Process::%s returning without waiting for events; process "
+ "private and public states are already 'stopped'.",
+ __FUNCTION__);
+ // We need to toggle the run lock as this won't get done in
+ // SetPublicState() if the process is hijacked.
+ if (hijack_listener_sp && use_run_lock)
+ m_public_run_lock.SetStopped();
+ return state;
+ }
-void
-Process::SynchronouslyNotifyStateChanged (StateType state)
-{
- std::vector<Notifications>::iterator notification_pos, notification_end = m_notifications.end();
- for (notification_pos = m_notifications.begin(); notification_pos != notification_end; ++notification_pos)
- {
- if (notification_pos->process_state_changed)
- notification_pos->process_state_changed (notification_pos->baton, this, state);
+ while (state != eStateInvalid) {
+ EventSP event_sp;
+ state = WaitForStateChangedEvents(timeout, event_sp, hijack_listener_sp);
+ if (event_sp_ptr && event_sp)
+ *event_sp_ptr = event_sp;
+
+ bool pop_process_io_handler = (hijack_listener_sp.get() != nullptr);
+ Process::HandleProcessStateChangedEvent(event_sp, stream,
+ pop_process_io_handler);
+
+ switch (state) {
+ case eStateCrashed:
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ // We need to toggle the run lock as this won't get done in
+ // SetPublicState() if the process is hijacked.
+ if (hijack_listener_sp && use_run_lock)
+ m_public_run_lock.SetStopped();
+ return state;
+ case eStateStopped:
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
+ continue;
+ else {
+ // We need to toggle the run lock as this won't get done in
+ // SetPublicState() if the process is hijacked.
+ if (hijack_listener_sp && use_run_lock)
+ m_public_run_lock.SetStopped();
+ return state;
+ }
+ default:
+ continue;
}
+ }
+ return state;
}
-// FIXME: We need to do some work on events before the general Listener sees them.
-// For instance if we are continuing from a breakpoint, we need to ensure that we do
-// the little "insert real insn, step & stop" trick. But we can't do that when the
-// event is delivered by the broadcaster - since that is done on the thread that is
-// waiting for new events, so if we needed more than one event for our handling, we would
-// stall. So instead we do it when we fetch the event off of the queue.
-//
-
-StateType
-Process::GetNextEvent (EventSP &event_sp)
-{
- StateType state = eStateInvalid;
-
- if (m_listener_sp->GetNextEventForBroadcaster (this, event_sp) && event_sp)
- state = Process::ProcessEventData::GetStateFromEvent (event_sp.get());
+bool Process::HandleProcessStateChangedEvent(const EventSP &event_sp,
+ Stream *stream,
+ bool &pop_process_io_handler) {
+ const bool handle_pop = pop_process_io_handler;
- return state;
-}
+ pop_process_io_handler = false;
+ ProcessSP process_sp =
+ Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
-void
-Process::SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec)
-{
- // don't sync (potentially context switch) in case where there is no process IO
- if (!m_process_input_reader)
- return;
+ if (!process_sp)
+ return false;
- uint32_t new_iohandler_id = 0;
- m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, new_iohandler_id, std::chrono::milliseconds(timeout_msec));
+ StateType event_state =
+ Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (event_state == eStateInvalid)
+ return false;
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::%s waited for m_iohandler_sync to change from %u, new value is %u", __FUNCTION__, iohandler_id, new_iohandler_id);
-}
+ switch (event_state) {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStepping:
+ case eStateDetached:
+ if (stream)
+ stream->Printf("Process %" PRIu64 " %s\n", process_sp->GetID(),
+ StateAsCString(event_state));
+ if (event_state == eStateDetached)
+ pop_process_io_handler = true;
+ break;
+
+ case eStateConnected:
+ case eStateRunning:
+ // Don't be chatty when we run...
+ break;
+
+ case eStateExited:
+ if (stream)
+ process_sp->GetStatus(*stream);
+ pop_process_io_handler = true;
+ break;
+
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ // Make sure the program hasn't been auto-restarted:
+ if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) {
+ if (stream) {
+ size_t num_reasons =
+ Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
+ if (num_reasons > 0) {
+ // FIXME: Do we want to report this, or would that just be annoyingly
+ // chatty?
+ if (num_reasons == 1) {
+ const char *reason =
+ Process::ProcessEventData::GetRestartedReasonAtIndex(
+ event_sp.get(), 0);
+ stream->Printf("Process %" PRIu64 " stopped and restarted: %s\n",
+ process_sp->GetID(),
+ reason ? reason : "<UNKNOWN REASON>");
+ } else {
+ stream->Printf("Process %" PRIu64
+ " stopped and restarted, reasons:\n",
+ process_sp->GetID());
+
+ for (size_t i = 0; i < num_reasons; i++) {
+ const char *reason =
+ Process::ProcessEventData::GetRestartedReasonAtIndex(
+ event_sp.get(), i);
+ stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
+ }
+ }
+ }
+ }
+ } else {
+ StopInfoSP curr_thread_stop_info_sp;
+ // Lock the thread list so it doesn't change on us, this is the scope for
+ // the locker:
+ {
+ ThreadList &thread_list = process_sp->GetThreadList();
+ std::lock_guard<std::recursive_mutex> guard(thread_list.GetMutex());
+
+ ThreadSP curr_thread(thread_list.GetSelectedThread());
+ ThreadSP thread;
+ StopReason curr_thread_stop_reason = eStopReasonInvalid;
+ if (curr_thread) {
+ curr_thread_stop_reason = curr_thread->GetStopReason();
+ curr_thread_stop_info_sp = curr_thread->GetStopInfo();
+ }
+ if (!curr_thread || !curr_thread->IsValid() ||
+ curr_thread_stop_reason == eStopReasonInvalid ||
+ curr_thread_stop_reason == eStopReasonNone) {
+ // Prefer a thread that has just completed its plan over another
+ // thread as current thread.
+ ThreadSP plan_thread;
+ ThreadSP other_thread;
+
+ const size_t num_threads = thread_list.GetSize();
+ size_t i;
+ for (i = 0; i < num_threads; ++i) {
+ thread = thread_list.GetThreadAtIndex(i);
+ StopReason thread_stop_reason = thread->GetStopReason();
+ switch (thread_stop_reason) {
+ case eStopReasonInvalid:
+ case eStopReasonNone:
+ break;
+
+ case eStopReasonSignal: {
+ // Don't select a signal thread if we weren't going to stop at
+ // that
+ // signal. We have to have had another reason for stopping here,
+ // and
+ // the user doesn't want to see this thread.
+ uint64_t signo = thread->GetStopInfo()->GetValue();
+ if (process_sp->GetUnixSignals()->GetShouldStop(signo)) {
+ if (!other_thread)
+ other_thread = thread;
+ }
+ break;
+ }
+ case eStopReasonTrace:
+ case eStopReasonBreakpoint:
+ case eStopReasonWatchpoint:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonThreadExiting:
+ case eStopReasonInstrumentation:
+ if (!other_thread)
+ other_thread = thread;
+ break;
+ case eStopReasonPlanComplete:
+ if (!plan_thread)
+ plan_thread = thread;
+ break;
+ }
+ }
+ if (plan_thread)
+ thread_list.SetSelectedThreadByID(plan_thread->GetID());
+ else if (other_thread)
+ thread_list.SetSelectedThreadByID(other_thread->GetID());
+ else {
+ if (curr_thread && curr_thread->IsValid())
+ thread = curr_thread;
+ else
+ thread = thread_list.GetThreadAtIndex(0);
-StateType
-Process::WaitForProcessToStop(const std::chrono::microseconds &timeout, EventSP *event_sp_ptr, bool wait_always,
- ListenerSP hijack_listener_sp, Stream *stream, bool use_run_lock)
-{
- // We can't just wait for a "stopped" event, because the stopped event may have restarted the target.
- // We have to actually check each event, and in the case of a stopped event check the restarted flag
- // on the event.
- if (event_sp_ptr)
- event_sp_ptr->reset();
- StateType state = GetState();
+ if (thread)
+ thread_list.SetSelectedThreadByID(thread->GetID());
+ }
+ }
+ }
+ // Drop the ThreadList mutex by here, since GetThreadStatus below might
+ // have to run code,
+ // e.g. for Data formatters, and if we hold the ThreadList mutex, then the
+ // process is going to
+ // have a hard time restarting the process.
+ if (stream) {
+ Debugger &debugger = process_sp->GetTarget().GetDebugger();
+ if (debugger.GetTargetList().GetSelectedTarget().get() ==
+ &process_sp->GetTarget()) {
+ const bool only_threads_with_stop_reason = true;
+ const uint32_t start_frame = 0;
+ const uint32_t num_frames = 1;
+ const uint32_t num_frames_with_source = 1;
+ process_sp->GetStatus(*stream);
+ process_sp->GetThreadStatus(*stream, only_threads_with_stop_reason,
+ start_frame, num_frames,
+ num_frames_with_source);
+ if (curr_thread_stop_info_sp) {
+ lldb::addr_t crashing_address;
+ ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference(
+ curr_thread_stop_info_sp, &crashing_address);
+ if (valobj_sp) {
+ const bool qualify_cxx_base_classes = false;
+
+ const ValueObject::GetExpressionPathFormat format =
+ ValueObject::GetExpressionPathFormat::
+ eGetExpressionPathFormatHonorPointers;
+ stream->PutCString("Likely cause: ");
+ valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes,
+ format);
+ stream->Printf(" accessed 0x%" PRIx64 "\n", crashing_address);
+ }
+ }
+ } else {
+ uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget(
+ process_sp->GetTarget().shared_from_this());
+ if (target_idx != UINT32_MAX)
+ stream->Printf("Target %d: (", target_idx);
+ else
+ stream->Printf("Target <unknown index>: (");
+ process_sp->GetTarget().Dump(stream, eDescriptionLevelBrief);
+ stream->Printf(") stopped.\n");
+ }
+ }
+
+ // 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(const std::chrono::microseconds &timeout,
+ const StateType *match_states,
+ const uint32_t num_match_states) {
+ EventSP event_sp;
+ StateType state = GetState();
+ while (state != eStateInvalid) {
// If we are exited or detached, we won't ever get back to any
// other valid state...
if (state == eStateDetached || state == eStateExited)
- return state;
+ return state;
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::%s (timeout = %llu)", __FUNCTION__, static_cast<unsigned long long>(timeout.count()));
+ state = WaitForStateChangedEvents(timeout, event_sp, nullptr);
- if (!wait_always &&
- StateIsStoppedState(state, true) &&
- StateIsStoppedState(GetPrivateState(), true))
- {
- if (log)
- log->Printf("Process::%s returning without waiting for events; process private and public states are already 'stopped'.",
- __FUNCTION__);
- // We need to toggle the run lock as this won't get done in
- // SetPublicState() if the process is hijacked.
- if (hijack_listener_sp && use_run_lock)
- m_public_run_lock.SetStopped();
+ for (uint32_t i = 0; i < num_match_states; ++i) {
+ if (match_states[i] == state)
return state;
}
+ }
+ return state;
+}
- while (state != eStateInvalid)
- {
- EventSP event_sp;
- state = WaitForStateChangedEvents(timeout, event_sp, hijack_listener_sp);
- if (event_sp_ptr && event_sp)
- *event_sp_ptr = event_sp;
-
- bool pop_process_io_handler = (hijack_listener_sp.get() != nullptr);
- Process::HandleProcessStateChangedEvent (event_sp, stream, pop_process_io_handler);
-
- switch (state)
- {
- case eStateCrashed:
- case eStateDetached:
- case eStateExited:
- case eStateUnloaded:
- // We need to toggle the run lock as this won't get done in
- // SetPublicState() if the process is hijacked.
- if (hijack_listener_sp && use_run_lock)
- m_public_run_lock.SetStopped();
- return state;
- case eStateStopped:
- if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
- continue;
- else
- {
- // We need to toggle the run lock as this won't get done in
- // SetPublicState() if the process is hijacked.
- if (hijack_listener_sp && use_run_lock)
- m_public_run_lock.SetStopped();
- return state;
- }
- default:
- continue;
- }
- }
- return state;
+bool Process::HijackProcessEvents(ListenerSP listener_sp) {
+ if (listener_sp) {
+ return HijackBroadcaster(listener_sp, eBroadcastBitStateChanged |
+ eBroadcastBitInterrupt);
+ } else
+ return false;
}
-bool
-Process::HandleProcessStateChangedEvent (const EventSP &event_sp,
- Stream *stream,
- bool &pop_process_io_handler)
-{
- const bool handle_pop = pop_process_io_handler;
+void Process::RestoreProcessEvents() { RestoreBroadcaster(); }
- pop_process_io_handler = false;
- ProcessSP process_sp = Process::ProcessEventData::GetProcessFromEvent(event_sp.get());
+StateType
+Process::WaitForStateChangedEvents(const std::chrono::microseconds &timeout,
+ EventSP &event_sp,
+ ListenerSP hijack_listener_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
+ static_cast<unsigned long long>(timeout.count()));
+
+ ListenerSP listener_sp = hijack_listener_sp;
+ if (!listener_sp)
+ listener_sp = m_listener_sp;
+
+ StateType state = eStateInvalid;
+ if (listener_sp->WaitForEventForBroadcasterWithType(
+ timeout, this, eBroadcastBitStateChanged | eBroadcastBitInterrupt,
+ event_sp)) {
+ if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ else if (log)
+ log->Printf("Process::%s got no event or was interrupted.", __FUNCTION__);
+ }
- if (!process_sp)
- return false;
+ if (log)
+ log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__,
+ static_cast<unsigned long long>(timeout.count()),
+ StateAsCString(state));
+ return state;
+}
- 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;
+Event *Process::PeekAtStateChangedEvents() {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- case eStateConnected:
- case eStateRunning:
- // Don't be chatty when we run...
- break;
+ if (log)
+ log->Printf("Process::%s...", __FUNCTION__);
- case eStateExited:
- if (stream)
- process_sp->GetStatus(*stream);
- pop_process_io_handler = true;
- break;
+ Event *event_ptr;
+ event_ptr = m_listener_sp->PeekAtNextEventForBroadcasterWithType(
+ this, eBroadcastBitStateChanged);
+ if (log) {
+ if (event_ptr) {
+ log->Printf(
+ "Process::%s (event_ptr) => %s", __FUNCTION__,
+ StateAsCString(ProcessEventData::GetStateFromEvent(event_ptr)));
+ } else {
+ log->Printf("Process::%s no events found", __FUNCTION__);
+ }
+ }
+ return event_ptr;
+}
- case eStateStopped:
- case eStateCrashed:
- case eStateSuspended:
- // Make sure the program hasn't been auto-restarted:
- if (Process::ProcessEventData::GetRestartedFromEvent (event_sp.get()))
- {
- if (stream)
- {
- size_t num_reasons = Process::ProcessEventData::GetNumRestartedReasons(event_sp.get());
- if (num_reasons > 0)
- {
- // FIXME: Do we want to report this, or would that just be annoyingly chatty?
- if (num_reasons == 1)
- {
- const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), 0);
- stream->Printf ("Process %" PRIu64 " stopped and restarted: %s\n",
- process_sp->GetID(),
- reason ? reason : "<UNKNOWN REASON>");
- }
- else
- {
- stream->Printf ("Process %" PRIu64 " stopped and restarted, reasons:\n",
- process_sp->GetID());
-
-
- for (size_t i = 0; i < num_reasons; i++)
- {
- const char *reason = Process::ProcessEventData::GetRestartedReasonAtIndex (event_sp.get(), i);
- stream->Printf("\t%s\n", reason ? reason : "<UNKNOWN REASON>");
- }
- }
- }
- }
- }
- else
- {
- StopInfoSP curr_thread_stop_info_sp;
- // Lock the thread list so it doesn't change on us, this is the scope for the locker:
- {
- ThreadList &thread_list = process_sp->GetThreadList();
- std::lock_guard<std::recursive_mutex> guard(thread_list.GetMutex());
-
- ThreadSP curr_thread (thread_list.GetSelectedThread());
- ThreadSP thread;
- StopReason curr_thread_stop_reason = eStopReasonInvalid;
- if (curr_thread)
- {
- curr_thread_stop_reason = curr_thread->GetStopReason();
- curr_thread_stop_info_sp = curr_thread->GetStopInfo();
- }
- if (!curr_thread ||
- !curr_thread->IsValid() ||
- curr_thread_stop_reason == eStopReasonInvalid ||
- curr_thread_stop_reason == eStopReasonNone)
- {
- // Prefer a thread that has just completed its plan over another thread as current thread.
- ThreadSP plan_thread;
- ThreadSP other_thread;
-
- const size_t num_threads = thread_list.GetSize();
- size_t i;
- for (i = 0; i < num_threads; ++i)
- {
- thread = thread_list.GetThreadAtIndex(i);
- StopReason thread_stop_reason = thread->GetStopReason();
- switch (thread_stop_reason)
- {
- case eStopReasonInvalid:
- case eStopReasonNone:
- break;
-
- case eStopReasonSignal:
- {
- // Don't select a signal thread if we weren't going to stop at that
- // signal. We have to have had another reason for stopping here, and
- // the user doesn't want to see this thread.
- uint64_t signo = thread->GetStopInfo()->GetValue();
- if (process_sp->GetUnixSignals()->GetShouldStop(signo))
- {
- if (!other_thread)
- other_thread = thread;
- }
- break;
- }
- case eStopReasonTrace:
- case eStopReasonBreakpoint:
- case eStopReasonWatchpoint:
- case eStopReasonException:
- case eStopReasonExec:
- case eStopReasonThreadExiting:
- case eStopReasonInstrumentation:
- if (!other_thread)
- other_thread = thread;
- break;
- case eStopReasonPlanComplete:
- if (!plan_thread)
- plan_thread = thread;
- break;
- }
- }
- if (plan_thread)
- thread_list.SetSelectedThreadByID (plan_thread->GetID());
- else if (other_thread)
- thread_list.SetSelectedThreadByID (other_thread->GetID());
- else
- {
- if (curr_thread && curr_thread->IsValid())
- thread = curr_thread;
- else
- thread = thread_list.GetThreadAtIndex(0);
-
- if (thread)
- thread_list.SetSelectedThreadByID (thread->GetID());
- }
- }
- }
- // Drop the ThreadList mutex by here, since GetThreadStatus below might have to run code,
- // e.g. for Data formatters, and if we hold the ThreadList mutex, then the process is going to
- // have a hard time restarting the process.
- if (stream)
- {
- Debugger &debugger = process_sp->GetTarget().GetDebugger();
- if (debugger.GetTargetList().GetSelectedTarget().get() == &process_sp->GetTarget())
- {
- const bool only_threads_with_stop_reason = true;
- const uint32_t start_frame = 0;
- const uint32_t num_frames = 1;
- const uint32_t num_frames_with_source = 1;
- process_sp->GetStatus(*stream);
- process_sp->GetThreadStatus (*stream,
- only_threads_with_stop_reason,
- start_frame,
- num_frames,
- num_frames_with_source);
- if (curr_thread_stop_info_sp)
- {
- lldb::addr_t crashing_address;
- ValueObjectSP valobj_sp = StopInfo::GetCrashingDereference(curr_thread_stop_info_sp, &crashing_address);
- if (valobj_sp)
- {
- const bool qualify_cxx_base_classes = false;
-
- const ValueObject::GetExpressionPathFormat format = ValueObject::GetExpressionPathFormat::eGetExpressionPathFormatHonorPointers;
- stream->PutCString("Likely cause: ");
- valobj_sp->GetExpressionPath(*stream, qualify_cxx_base_classes, format);
- stream->Printf(" accessed 0x%" PRIx64 "\n", crashing_address);
- }
- }
- }
- else
- {
- uint32_t target_idx = debugger.GetTargetList().GetIndexOfTarget(process_sp->GetTarget().shared_from_this());
- if (target_idx != UINT32_MAX)
- stream->Printf ("Target %d: (", target_idx);
- else
- stream->Printf ("Target <unknown index>: (");
- process_sp->GetTarget().Dump (stream, eDescriptionLevelBrief);
- stream->Printf (") stopped.\n");
- }
- }
+StateType Process::WaitForStateChangedEventsPrivate(
+ const std::chrono::microseconds &timeout, EventSP &event_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- // Pop the process IO handler
- pop_process_io_handler = true;
- }
- break;
- }
+ if (log)
+ log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
+ static_cast<unsigned long long>(timeout.count()));
- if (handle_pop && pop_process_io_handler)
- process_sp->PopProcessIOHandler();
+ StateType state = eStateInvalid;
+ if (m_private_state_listener_sp->WaitForEventForBroadcasterWithType(
+ timeout, &m_private_state_broadcaster,
+ eBroadcastBitStateChanged | eBroadcastBitInterrupt, event_sp))
+ if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
+ state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- return true;
+ // This is a bit of a hack, but when we wait here we could very well return
+ // to the command-line, and that could disable the log, which would render the
+ // log we got above invalid.
+ if (log)
+ log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__,
+ static_cast<unsigned long long>(timeout.count()),
+ state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));
+ return state;
}
-StateType
-Process::WaitForState(const std::chrono::microseconds &timeout, const StateType *match_states,
- const uint32_t num_match_states)
-{
- EventSP event_sp;
- StateType state = GetState();
- while (state != eStateInvalid)
- {
- // If we are exited or detached, we won't ever get back to any
- // other valid state...
- if (state == eStateDetached || state == eStateExited)
- return state;
-
- state = WaitForStateChangedEvents(timeout, event_sp, nullptr);
-
- for (uint32_t i = 0; i < num_match_states; ++i)
- {
- if (match_states[i] == state)
- return state;
- }
- }
- return state;
-}
+bool Process::WaitForEventsPrivate(const std::chrono::microseconds &timeout,
+ EventSP &event_sp, bool control_only) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-bool
-Process::HijackProcessEvents (ListenerSP listener_sp)
-{
- if (listener_sp)
- {
- return HijackBroadcaster(listener_sp, eBroadcastBitStateChanged | eBroadcastBitInterrupt);
- }
- else
- return false;
+ if (log)
+ log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
+ static_cast<unsigned long long>(timeout.count()));
+
+ if (control_only)
+ return m_private_state_listener_sp->WaitForEventForBroadcaster(
+ timeout, &m_private_state_control_broadcaster, event_sp);
+ else
+ return m_private_state_listener_sp->WaitForEvent(timeout, event_sp);
}
-void
-Process::RestoreProcessEvents ()
-{
- RestoreBroadcaster();
+bool Process::IsRunning() const {
+ return StateIsRunningState(m_public_state.GetValue());
}
-StateType
-Process::WaitForStateChangedEvents(const std::chrono::microseconds &timeout, EventSP &event_sp,
- ListenerSP hijack_listener_sp)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+int Process::GetExitStatus() {
+ std::lock_guard<std::mutex> guard(m_exit_status_mutex);
- if (log)
- log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
- static_cast<unsigned long long>(timeout.count()));
+ if (m_public_state.GetValue() == eStateExited)
+ return m_exit_status;
+ return -1;
+}
- ListenerSP listener_sp = hijack_listener_sp;
- if (!listener_sp)
- listener_sp = m_listener_sp;
-
- StateType state = eStateInvalid;
- if (listener_sp->WaitForEventForBroadcasterWithType (timeout,
- this,
- eBroadcastBitStateChanged | eBroadcastBitInterrupt,
- event_sp))
- {
- if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
- state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- else if (log)
- log->Printf ("Process::%s got no event or was interrupted.", __FUNCTION__);
- }
+const char *Process::GetExitDescription() {
+ std::lock_guard<std::mutex> guard(m_exit_status_mutex);
- if (log)
- log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__,
- static_cast<unsigned long long>(timeout.count()), StateAsCString(state));
- return state;
+ if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty())
+ return m_exit_string.c_str();
+ return nullptr;
}
-Event *
-Process::PeekAtStateChangedEvents ()
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+bool Process::SetExitStatus(int status, const char *cstr) {
+ // Use a mutex to protect setting the exit status.
+ std::lock_guard<std::mutex> guard(m_exit_status_mutex);
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
+ LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf(
+ "Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)",
+ status, status, cstr ? "\"" : "", cstr ? cstr : "NULL",
+ cstr ? "\"" : "");
+ // We were already in the exited state
+ if (m_private_state.GetValue() == eStateExited) {
if (log)
- log->Printf ("Process::%s...", __FUNCTION__);
+ log->Printf("Process::SetExitStatus () ignoring exit status because "
+ "state was already set to eStateExited");
+ return false;
+ }
- Event *event_ptr;
- event_ptr = m_listener_sp->PeekAtNextEventForBroadcasterWithType (this,
- eBroadcastBitStateChanged);
- if (log)
- {
- if (event_ptr)
- {
- log->Printf ("Process::%s (event_ptr) => %s",
- __FUNCTION__,
- StateAsCString(ProcessEventData::GetStateFromEvent (event_ptr)));
- }
- else
- {
- log->Printf ("Process::%s no events found",
- __FUNCTION__);
- }
- }
- return event_ptr;
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+
+ // Clear the last natural stop ID since it has a strong
+ // reference to this process
+ m_mod_id.SetStopEventForLastNaturalStopID(EventSP());
+
+ SetPrivateState(eStateExited);
+
+ // Allow subclasses to do some cleanup
+ DidExit();
+
+ return true;
+}
+
+bool Process::IsAlive() {
+ switch (m_private_state.GetValue()) {
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateStopped:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ return true;
+ default:
+ return false;
+ }
}
-StateType
-Process::WaitForStateChangedEventsPrivate(const std::chrono::microseconds &timeout, EventSP &event_sp)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+// This static callback can be used to watch for local child processes on
+// the current host. The child process exits, the process will be
+// found in the global target list (we want to be completely sure that the
+// lldb_private::Process doesn't go away before we can deliver the signal.
+bool Process::SetProcessExitStatus(
+ lldb::pid_t pid, bool exited,
+ int signo, // Zero for no signal
+ int exit_status // Exit value of process if signal is zero
+ ) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::SetProcessExitStatus (pid=%" PRIu64
+ ", exited=%i, signal=%i, exit_status=%i)\n",
+ pid, exited, signo, exit_status);
+
+ if (exited) {
+ TargetSP target_sp(Debugger::FindTargetWithProcessID(pid));
+ if (target_sp) {
+ ProcessSP process_sp(target_sp->GetProcessSP());
+ if (process_sp) {
+ const char *signal_cstr = nullptr;
+ if (signo)
+ signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo);
- if (log)
- log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
- static_cast<unsigned long long>(timeout.count()));
+ process_sp->SetExitStatus(exit_status, signal_cstr);
+ }
+ }
+ return true;
+ }
+ return false;
+}
- StateType state = eStateInvalid;
- if (m_private_state_listener_sp->WaitForEventForBroadcasterWithType (timeout,
- &m_private_state_broadcaster,
- eBroadcastBitStateChanged | eBroadcastBitInterrupt,
- event_sp))
- if (event_sp && event_sp->GetType() == eBroadcastBitStateChanged)
- state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
-
- // This is a bit of a hack, but when we wait here we could very well return
- // to the command-line, and that could disable the log, which would render the
- // log we got above invalid.
+void Process::UpdateThreadListIfNeeded() {
+ const uint32_t stop_id = GetStopID();
+ if (m_thread_list.GetSize(false) == 0 ||
+ stop_id != m_thread_list.GetStopID()) {
+ const StateType state = GetPrivateState();
+ if (StateIsStoppedState(state, true)) {
+ std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
+ // m_thread_list does have its own mutex, but we need to
+ // hold onto the mutex between the call to UpdateThreadList(...)
+ // and the os->UpdateThreadList(...) so it doesn't change on us
+ ThreadList &old_thread_list = m_thread_list;
+ ThreadList real_thread_list(this);
+ ThreadList new_thread_list(this);
+ // Always update the thread list with the protocol specific
+ // thread list, but only update if "true" is returned
+ if (UpdateThreadList(m_thread_list_real, real_thread_list)) {
+ // Don't call into the OperatingSystem to update the thread list if we
+ // are shutting down, since
+ // that may call back into the SBAPI's, requiring the API lock which is
+ // already held by whoever is
+ // shutting us down, causing a deadlock.
+ OperatingSystem *os = GetOperatingSystem();
+ if (os && !m_destroy_in_process) {
+ // Clear any old backing threads where memory threads might have been
+ // backed by actual threads from the lldb_private::Process subclass
+ size_t num_old_threads = old_thread_list.GetSize(false);
+ for (size_t i = 0; i < num_old_threads; ++i)
+ old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread();
+
+ // Turn off dynamic types to ensure we don't run any expressions.
+ // Objective C
+ // can run an expression to determine if a SBValue is a dynamic type
+ // or not
+ // and we need to avoid this. OperatingSystem plug-ins can't run
+ // expressions
+ // that require running code...
+
+ Target &target = GetTarget();
+ const lldb::DynamicValueType saved_prefer_dynamic =
+ target.GetPreferDynamicValue();
+ if (saved_prefer_dynamic != lldb::eNoDynamicValues)
+ target.SetPreferDynamicValue(lldb::eNoDynamicValues);
+
+ // Now let the OperatingSystem plug-in update the thread list
+
+ os->UpdateThreadList(
+ old_thread_list, // Old list full of threads created by OS plug-in
+ real_thread_list, // The actual thread list full of threads
+ // created by each lldb_private::Process
+ // subclass
+ new_thread_list); // The new thread list that we will show to the
+ // user that gets filled in
+
+ if (saved_prefer_dynamic != lldb::eNoDynamicValues)
+ target.SetPreferDynamicValue(saved_prefer_dynamic);
+ } else {
+ // No OS plug-in, the new thread list is the same as the real thread
+ // list
+ new_thread_list = real_thread_list;
+ }
+
+ m_thread_list_real.Update(real_thread_list);
+ m_thread_list.Update(new_thread_list);
+ m_thread_list.SetStopID(stop_id);
+
+ if (GetLastNaturalStopID() != m_extended_thread_stop_id) {
+ // Clear any extended threads that we may have accumulated previously
+ m_extended_thread_list.Clear();
+ m_extended_thread_stop_id = GetLastNaturalStopID();
+
+ m_queue_list.Clear();
+ m_queue_list_stop_id = GetLastNaturalStopID();
+ }
+ }
+ }
+ }
+}
+
+void Process::UpdateQueueListIfNeeded() {
+ if (m_system_runtime_ap) {
+ if (m_queue_list.GetSize() == 0 ||
+ m_queue_list_stop_id != GetLastNaturalStopID()) {
+ const StateType state = GetPrivateState();
+ if (StateIsStoppedState(state, true)) {
+ m_system_runtime_ap->PopulateQueueList(m_queue_list);
+ m_queue_list_stop_id = GetLastNaturalStopID();
+ }
+ }
+ }
+}
+
+ThreadSP Process::CreateOSPluginThread(lldb::tid_t tid, lldb::addr_t context) {
+ OperatingSystem *os = GetOperatingSystem();
+ if (os)
+ return os->CreateThread(tid, context);
+ return ThreadSP();
+}
+
+uint32_t Process::GetNextThreadIndexID(uint64_t thread_id) {
+ return AssignIndexIDToThread(thread_id);
+}
+
+bool Process::HasAssignedIndexIDToThread(uint64_t thread_id) {
+ return (m_thread_id_to_index_id_map.find(thread_id) !=
+ m_thread_id_to_index_id_map.end());
+}
+
+uint32_t Process::AssignIndexIDToThread(uint64_t thread_id) {
+ uint32_t result = 0;
+ std::map<uint64_t, uint32_t>::iterator iterator =
+ m_thread_id_to_index_id_map.find(thread_id);
+ if (iterator == m_thread_id_to_index_id_map.end()) {
+ result = ++m_thread_index_id;
+ m_thread_id_to_index_id_map[thread_id] = result;
+ } else {
+ result = iterator->second;
+ }
+
+ return result;
+}
+
+StateType Process::GetState() {
+ // If any other threads access this we will need a mutex for it
+ return m_public_state.GetValue();
+}
+
+bool Process::StateChangedIsExternallyHijacked() {
+ if (IsHijackedForEvent(eBroadcastBitStateChanged)) {
+ const char *hijacking_name = GetHijackingListenerName();
+ if (hijacking_name &&
+ strcmp(hijacking_name, "lldb.Process.ResumeSynchronous.hijack"))
+ return true;
+ }
+ return false;
+}
+
+void Process::SetPublicState(StateType new_state, bool restarted) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
+ LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::SetPublicState (state = %s, restarted = %i)",
+ StateAsCString(new_state), restarted);
+ const StateType old_state = m_public_state.GetValue();
+ m_public_state.SetValue(new_state);
+
+ // On the transition from Run to Stopped, we unlock the writer end of the
+ // run lock. The lock gets locked in Resume, which is the public API
+ // to tell the program to run.
+ if (!StateChangedIsExternallyHijacked()) {
+ if (new_state == eStateDetached) {
+ if (log)
+ log->Printf(
+ "Process::SetPublicState (%s) -- unlocking run lock for detach",
+ StateAsCString(new_state));
+ m_public_run_lock.SetStopped();
+ } else {
+ const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
+ const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+ if ((old_state_is_stopped != new_state_is_stopped)) {
+ if (new_state_is_stopped && !restarted) {
+ if (log)
+ log->Printf("Process::SetPublicState (%s) -- unlocking run lock",
+ StateAsCString(new_state));
+ m_public_run_lock.SetStopped();
+ }
+ }
+ }
+ }
+}
+
+Error Process::Resume() {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
+ LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::Resume -- locking run lock");
+ if (!m_public_run_lock.TrySetRunning()) {
+ Error error("Resume request failed - process still running.");
if (log)
- log->Printf("Process::%s (timeout = %llu, event_sp) => %s", __FUNCTION__,
- static_cast<unsigned long long>(timeout.count()),
- state == eStateInvalid ? "TIMEOUT" : StateAsCString(state));
- return state;
+ log->Printf("Process::Resume: -- TrySetRunning failed, not resuming.");
+ return error;
+ }
+ return PrivateResume();
}
-bool
-Process::WaitForEventsPrivate(const std::chrono::microseconds &timeout, EventSP &event_sp, bool control_only)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-
+Error Process::ResumeSynchronous(Stream *stream) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
+ LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::ResumeSynchronous -- locking run lock");
+ if (!m_public_run_lock.TrySetRunning()) {
+ Error error("Resume request failed - process still running.");
if (log)
- log->Printf("Process::%s (timeout = %llu, event_sp)...", __FUNCTION__,
- static_cast<unsigned long long>(timeout.count()));
+ log->Printf("Process::Resume: -- TrySetRunning failed, not resuming.");
+ return error;
+ }
- if (control_only)
- return m_private_state_listener_sp->WaitForEventForBroadcaster(timeout, &m_private_state_control_broadcaster, event_sp);
+ ListenerSP listener_sp(
+ Listener::MakeListener("lldb.Process.ResumeSynchronous.hijack"));
+ HijackProcessEvents(listener_sp);
+
+ Error error = PrivateResume();
+ if (error.Success()) {
+ StateType state = WaitForProcessToStop(std::chrono::microseconds(0), NULL,
+ true, listener_sp, stream);
+ const bool must_be_alive =
+ false; // eStateExited is ok, so this must be false
+ if (!StateIsStoppedState(state, must_be_alive))
+ error.SetErrorStringWithFormat(
+ "process not in stopped state after synchronous resume: %s",
+ StateAsCString(state));
+ }
+
+ // Undo the hijacking of process events...
+ RestoreProcessEvents();
+
+ return error;
+}
+
+StateType Process::GetPrivateState() { return m_private_state.GetValue(); }
+
+void Process::SetPrivateState(StateType new_state) {
+ if (m_finalize_called)
+ return;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
+ LIBLLDB_LOG_PROCESS));
+ bool state_changed = false;
+
+ if (log)
+ log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state));
+
+ std::lock_guard<std::recursive_mutex> thread_guard(m_thread_list.GetMutex());
+ std::lock_guard<std::recursive_mutex> guard(m_private_state.GetMutex());
+
+ const StateType old_state = m_private_state.GetValueNoLock();
+ state_changed = old_state != new_state;
+
+ const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
+ const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+ if (old_state_is_stopped != new_state_is_stopped) {
+ if (new_state_is_stopped)
+ m_private_run_lock.SetStopped();
+ else
+ m_private_run_lock.SetRunning();
+ }
+
+ if (state_changed) {
+ m_private_state.SetValueNoLock(new_state);
+ EventSP event_sp(
+ new Event(eBroadcastBitStateChanged,
+ new ProcessEventData(shared_from_this(), new_state)));
+ if (StateIsStoppedState(new_state, false)) {
+ // Note, this currently assumes that all threads in the list
+ // stop when the process stops. In the future we will want to
+ // support a debugging model where some threads continue to run
+ // while others are stopped. When that happens we will either need
+ // a way for the thread list to identify which threads are stopping
+ // or create a special thread list containing only threads which
+ // actually stopped.
+ //
+ // The process plugin is responsible for managing the actual
+ // behavior of the threads and should have stopped any threads
+ // that are going to stop before we get here.
+ m_thread_list.DidStop();
+
+ m_mod_id.BumpStopID();
+ if (!m_mod_id.IsLastResumeForUserExpression())
+ m_mod_id.SetStopEventForLastNaturalStopID(event_sp);
+ m_memory_cache.Clear();
+ if (log)
+ log->Printf("Process::SetPrivateState (%s) stop_id = %u",
+ StateAsCString(new_state), m_mod_id.GetStopID());
+ }
+
+ // Use our target to get a shared pointer to ourselves...
+ if (m_finalize_called && !PrivateStateThreadIsValid())
+ BroadcastEvent(event_sp);
else
- return m_private_state_listener_sp->WaitForEvent(timeout, event_sp);
+ m_private_state_broadcaster.BroadcastEvent(event_sp);
+ } else {
+ if (log)
+ log->Printf(
+ "Process::SetPrivateState (%s) state didn't change. Ignoring...",
+ StateAsCString(new_state));
+ }
}
-bool
-Process::IsRunning () const
-{
- return StateIsRunningState (m_public_state.GetValue());
+void Process::SetRunningUserExpression(bool on) {
+ m_mod_id.SetRunningUserExpression(on);
}
-int
-Process::GetExitStatus ()
-{
- std::lock_guard<std::mutex> guard(m_exit_status_mutex);
+addr_t Process::GetImageInfoAddress() { return LLDB_INVALID_ADDRESS; }
- if (m_public_state.GetValue() == eStateExited)
- return m_exit_status;
- return -1;
+const lldb::ABISP &Process::GetABI() {
+ if (!m_abi_sp)
+ m_abi_sp = ABI::FindPlugin(GetTarget().GetArchitecture());
+ return m_abi_sp;
}
-const char *
-Process::GetExitDescription ()
-{
- std::lock_guard<std::mutex> guard(m_exit_status_mutex);
-
- if (m_public_state.GetValue() == eStateExited && !m_exit_string.empty())
- return m_exit_string.c_str();
+LanguageRuntime *Process::GetLanguageRuntime(lldb::LanguageType language,
+ bool retry_if_null) {
+ if (m_finalizing)
return nullptr;
-}
-
-bool
-Process::SetExitStatus (int status, const char *cstr)
-{
- // Use a mutex to protect setting the exit status.
- std::lock_guard<std::mutex> guard(m_exit_status_mutex);
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::SetExitStatus (status=%i (0x%8.8x), description=%s%s%s)",
- status, status,
- cstr ? "\"" : "",
- cstr ? cstr : "NULL",
- cstr ? "\"" : "");
-
- // We were already in the exited state
- if (m_private_state.GetValue() == eStateExited)
- {
- if (log)
- log->Printf("Process::SetExitStatus () ignoring exit status because state was already set to eStateExited");
- return false;
- }
- m_exit_status = status;
- if (cstr)
- m_exit_string = cstr;
- else
- m_exit_string.clear();
+ LanguageRuntimeCollection::iterator pos;
+ pos = m_language_runtimes.find(language);
+ if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second)) {
+ lldb::LanguageRuntimeSP runtime_sp(
+ LanguageRuntime::FindPlugin(this, language));
+
+ m_language_runtimes[language] = runtime_sp;
+ return runtime_sp.get();
+ } else
+ return (*pos).second.get();
+}
+
+CPPLanguageRuntime *Process::GetCPPLanguageRuntime(bool retry_if_null) {
+ LanguageRuntime *runtime =
+ GetLanguageRuntime(eLanguageTypeC_plus_plus, retry_if_null);
+ if (runtime != nullptr &&
+ runtime->GetLanguageType() == eLanguageTypeC_plus_plus)
+ return static_cast<CPPLanguageRuntime *>(runtime);
+ return nullptr;
+}
+
+ObjCLanguageRuntime *Process::GetObjCLanguageRuntime(bool retry_if_null) {
+ LanguageRuntime *runtime =
+ GetLanguageRuntime(eLanguageTypeObjC, retry_if_null);
+ if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeObjC)
+ return static_cast<ObjCLanguageRuntime *>(runtime);
+ return nullptr;
+}
- // Clear the last natural stop ID since it has a strong
- // reference to this process
- m_mod_id.SetStopEventForLastNaturalStopID(EventSP());
+bool Process::IsPossibleDynamicValue(ValueObject &in_value) {
+ if (m_finalizing)
+ return false;
- SetPrivateState (eStateExited);
+ if (in_value.IsDynamic())
+ return false;
+ LanguageType known_type = in_value.GetObjectRuntimeLanguage();
- // Allow subclasses to do some cleanup
- DidExit ();
+ if (known_type != eLanguageTypeUnknown && known_type != eLanguageTypeC) {
+ LanguageRuntime *runtime = GetLanguageRuntime(known_type);
+ return runtime ? runtime->CouldHaveDynamicValue(in_value) : false;
+ }
+ LanguageRuntime *cpp_runtime = GetLanguageRuntime(eLanguageTypeC_plus_plus);
+ if (cpp_runtime && cpp_runtime->CouldHaveDynamicValue(in_value))
return true;
+
+ LanguageRuntime *objc_runtime = GetLanguageRuntime(eLanguageTypeObjC);
+ return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false;
}
-bool
-Process::IsAlive ()
-{
- switch (m_private_state.GetValue())
- {
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- case eStateStopped:
- case eStateRunning:
- case eStateStepping:
- case eStateCrashed:
- case eStateSuspended:
- return true;
- default:
- return false;
- }
+void Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers) {
+ m_dynamic_checkers_ap.reset(dynamic_checkers);
}
-// This static callback can be used to watch for local child processes on
-// the current host. The child process exits, the process will be
-// found in the global target list (we want to be completely sure that the
-// lldb_private::Process doesn't go away before we can deliver the signal.
-bool
-Process::SetProcessExitStatus(lldb::pid_t pid, bool exited,
- int signo, // Zero for no signal
- int exit_status // Exit value of process if signal is zero
- )
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::SetProcessExitStatus (pid=%" PRIu64 ", exited=%i, signal=%i, exit_status=%i)\n", pid,
- exited, signo, exit_status);
+BreakpointSiteList &Process::GetBreakpointSiteList() {
+ return m_breakpoint_site_list;
+}
- if (exited)
- {
- TargetSP target_sp(Debugger::FindTargetWithProcessID (pid));
- if (target_sp)
- {
- ProcessSP process_sp (target_sp->GetProcessSP());
- if (process_sp)
- {
- const char *signal_cstr = nullptr;
- if (signo)
- signal_cstr = process_sp->GetUnixSignals()->GetSignalAsCString(signo);
+const BreakpointSiteList &Process::GetBreakpointSiteList() const {
+ return m_breakpoint_site_list;
+}
- process_sp->SetExitStatus (exit_status, signal_cstr);
- }
- }
- return true;
- }
- return false;
+void Process::DisableAllBreakpointSites() {
+ m_breakpoint_site_list.ForEach([this](BreakpointSite *bp_site) -> void {
+ // bp_site->SetEnabled(true);
+ DisableBreakpointSite(bp_site);
+ });
}
-void
-Process::UpdateThreadListIfNeeded ()
-{
- const uint32_t stop_id = GetStopID();
- if (m_thread_list.GetSize(false) == 0 || stop_id != m_thread_list.GetStopID())
- {
- const StateType state = GetPrivateState();
- if (StateIsStoppedState (state, true))
- {
- std::lock_guard<std::recursive_mutex> guard(m_thread_list.GetMutex());
- // m_thread_list does have its own mutex, but we need to
- // hold onto the mutex between the call to UpdateThreadList(...)
- // and the os->UpdateThreadList(...) so it doesn't change on us
- ThreadList &old_thread_list = m_thread_list;
- ThreadList real_thread_list(this);
- ThreadList new_thread_list(this);
- // Always update the thread list with the protocol specific
- // thread list, but only update if "true" is returned
- if (UpdateThreadList (m_thread_list_real, real_thread_list))
- {
- // Don't call into the OperatingSystem to update the thread list if we are shutting down, since
- // that may call back into the SBAPI's, requiring the API lock which is already held by whoever is
- // shutting us down, causing a deadlock.
- OperatingSystem *os = GetOperatingSystem ();
- if (os && !m_destroy_in_process)
- {
- // Clear any old backing threads where memory threads might have been
- // backed by actual threads from the lldb_private::Process subclass
- size_t num_old_threads = old_thread_list.GetSize(false);
- for (size_t i = 0; i < num_old_threads; ++i)
- old_thread_list.GetThreadAtIndex(i, false)->ClearBackingThread();
-
- // Turn off dynamic types to ensure we don't run any expressions. Objective C
- // can run an expression to determine if a SBValue is a dynamic type or not
- // and we need to avoid this. OperatingSystem plug-ins can't run expressions
- // that require running code...
-
- Target &target = GetTarget();
- const lldb::DynamicValueType saved_prefer_dynamic = target.GetPreferDynamicValue ();
- if (saved_prefer_dynamic != lldb::eNoDynamicValues)
- target.SetPreferDynamicValue(lldb::eNoDynamicValues);
-
- // Now let the OperatingSystem plug-in update the thread list
-
- os->UpdateThreadList (old_thread_list, // Old list full of threads created by OS plug-in
- real_thread_list, // The actual thread list full of threads created by each lldb_private::Process subclass
- new_thread_list); // The new thread list that we will show to the user that gets filled in
+Error Process::ClearBreakpointSiteByID(lldb::user_id_t break_id) {
+ Error error(DisableBreakpointSiteByID(break_id));
- if (saved_prefer_dynamic != lldb::eNoDynamicValues)
- target.SetPreferDynamicValue(saved_prefer_dynamic);
- }
- else
- {
- // No OS plug-in, the new thread list is the same as the real thread list
- new_thread_list = real_thread_list;
- }
-
- m_thread_list_real.Update(real_thread_list);
- m_thread_list.Update (new_thread_list);
- m_thread_list.SetStopID (stop_id);
-
- if (GetLastNaturalStopID () != m_extended_thread_stop_id)
- {
- // Clear any extended threads that we may have accumulated previously
- m_extended_thread_list.Clear();
- m_extended_thread_stop_id = GetLastNaturalStopID ();
+ if (error.Success())
+ m_breakpoint_site_list.Remove(break_id);
- m_queue_list.Clear();
- m_queue_list_stop_id = GetLastNaturalStopID ();
- }
- }
- }
- }
+ return error;
}
-void
-Process::UpdateQueueListIfNeeded ()
-{
- if (m_system_runtime_ap)
- {
- if (m_queue_list.GetSize() == 0 || m_queue_list_stop_id != GetLastNaturalStopID())
- {
- const StateType state = GetPrivateState();
- if (StateIsStoppedState (state, true))
- {
- m_system_runtime_ap->PopulateQueueList (m_queue_list);
- m_queue_list_stop_id = GetLastNaturalStopID();
- }
- }
- }
-}
+Error Process::DisableBreakpointSiteByID(lldb::user_id_t break_id) {
+ Error error;
+ BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID(break_id);
+ if (bp_site_sp) {
+ if (bp_site_sp->IsEnabled())
+ error = DisableBreakpointSite(bp_site_sp.get());
+ } else {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64,
+ break_id);
+ }
-ThreadSP
-Process::CreateOSPluginThread (lldb::tid_t tid, lldb::addr_t context)
-{
- OperatingSystem *os = GetOperatingSystem ();
- if (os)
- return os->CreateThread(tid, context);
- return ThreadSP();
+ return error;
}
-uint32_t
-Process::GetNextThreadIndexID (uint64_t thread_id)
-{
- return AssignIndexIDToThread(thread_id);
+Error Process::EnableBreakpointSiteByID(lldb::user_id_t break_id) {
+ Error error;
+ BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID(break_id);
+ if (bp_site_sp) {
+ if (!bp_site_sp->IsEnabled())
+ error = EnableBreakpointSite(bp_site_sp.get());
+ } else {
+ error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64,
+ break_id);
+ }
+ return error;
}
-bool
-Process::HasAssignedIndexIDToThread(uint64_t thread_id)
-{
- return (m_thread_id_to_index_id_map.find(thread_id) != m_thread_id_to_index_id_map.end());
+lldb::break_id_t
+Process::CreateBreakpointSite(const BreakpointLocationSP &owner,
+ bool use_hardware) {
+ addr_t load_addr = LLDB_INVALID_ADDRESS;
+
+ bool show_error = true;
+ switch (GetState()) {
+ case eStateInvalid:
+ case eStateUnloaded:
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ case eStateDetached:
+ case eStateExited:
+ show_error = false;
+ break;
+
+ case eStateStopped:
+ case eStateRunning:
+ case eStateStepping:
+ case eStateCrashed:
+ case eStateSuspended:
+ show_error = IsAlive();
+ break;
+ }
+
+ // Reset the IsIndirect flag here, in case the location changes from
+ // pointing to a indirect symbol to a regular symbol.
+ owner->SetIsIndirect(false);
+
+ if (owner->ShouldResolveIndirectFunctions()) {
+ Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol();
+ if (symbol && symbol->IsIndirect()) {
+ Error error;
+ Address symbol_address = symbol->GetAddress();
+ load_addr = ResolveIndirectFunction(&symbol_address, error);
+ if (!error.Success() && show_error) {
+ GetTarget().GetDebugger().GetErrorFile()->Printf(
+ "warning: failed to resolve indirect function at 0x%" PRIx64
+ " for breakpoint %i.%i: %s\n",
+ symbol->GetLoadAddress(&GetTarget()),
+ owner->GetBreakpoint().GetID(), owner->GetID(),
+ error.AsCString() ? error.AsCString() : "unknown error");
+ return LLDB_INVALID_BREAK_ID;
+ }
+ Address resolved_address(load_addr);
+ load_addr = resolved_address.GetOpcodeLoadAddress(&GetTarget());
+ owner->SetIsIndirect(true);
+ } else
+ load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget());
+ } else
+ load_addr = owner->GetAddress().GetOpcodeLoadAddress(&GetTarget());
+
+ if (load_addr != LLDB_INVALID_ADDRESS) {
+ BreakpointSiteSP bp_site_sp;
+
+ // Look up this breakpoint site. If it exists, then add this new owner,
+ // otherwise
+ // create a new breakpoint site and add it.
+
+ bp_site_sp = m_breakpoint_site_list.FindByAddress(load_addr);
+
+ if (bp_site_sp) {
+ bp_site_sp->AddOwner(owner);
+ owner->SetBreakpointSite(bp_site_sp);
+ return bp_site_sp->GetID();
+ } else {
+ bp_site_sp.reset(new BreakpointSite(&m_breakpoint_site_list, owner,
+ load_addr, use_hardware));
+ if (bp_site_sp) {
+ Error error = EnableBreakpointSite(bp_site_sp.get());
+ if (error.Success()) {
+ owner->SetBreakpointSite(bp_site_sp);
+ return m_breakpoint_site_list.Add(bp_site_sp);
+ } else {
+ if (show_error) {
+ // Report error for setting breakpoint...
+ GetTarget().GetDebugger().GetErrorFile()->Printf(
+ "warning: failed to set breakpoint site at 0x%" PRIx64
+ " for breakpoint %i.%i: %s\n",
+ load_addr, owner->GetBreakpoint().GetID(), owner->GetID(),
+ error.AsCString() ? error.AsCString() : "unknown error");
+ }
+ }
+ }
+ }
+ }
+ // We failed to enable the breakpoint
+ return LLDB_INVALID_BREAK_ID;
+}
+
+void Process::RemoveOwnerFromBreakpointSite(lldb::user_id_t owner_id,
+ lldb::user_id_t owner_loc_id,
+ BreakpointSiteSP &bp_site_sp) {
+ uint32_t num_owners = bp_site_sp->RemoveOwner(owner_id, owner_loc_id);
+ if (num_owners == 0) {
+ // Don't try to disable the site if we don't have a live process anymore.
+ if (IsAlive())
+ DisableBreakpointSite(bp_site_sp.get());
+ m_breakpoint_site_list.RemoveByAddress(bp_site_sp->GetLoadAddress());
+ }
+}
+
+size_t Process::RemoveBreakpointOpcodesFromBuffer(addr_t bp_addr, size_t size,
+ uint8_t *buf) const {
+ size_t bytes_removed = 0;
+ BreakpointSiteList bp_sites_in_range;
+
+ if (m_breakpoint_site_list.FindInRange(bp_addr, bp_addr + size,
+ bp_sites_in_range)) {
+ bp_sites_in_range.ForEach([bp_addr, size, buf, &bytes_removed](
+ BreakpointSite *bp_site) -> void {
+ if (bp_site->GetType() == BreakpointSite::eSoftware) {
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr,
+ &intersect_size, &opcode_offset)) {
+ assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size);
+ assert(bp_addr < intersect_addr + intersect_size &&
+ intersect_addr + intersect_size <= bp_addr + size);
+ assert(opcode_offset + intersect_size <= bp_site->GetByteSize());
+ size_t buf_offset = intersect_addr - bp_addr;
+ ::memcpy(buf + buf_offset,
+ bp_site->GetSavedOpcodeBytes() + opcode_offset,
+ intersect_size);
+ }
+ }
+ });
+ }
+ return bytes_removed;
}
-uint32_t
-Process::AssignIndexIDToThread(uint64_t thread_id)
-{
- uint32_t result = 0;
- std::map<uint64_t, uint32_t>::iterator iterator = m_thread_id_to_index_id_map.find(thread_id);
- if (iterator == m_thread_id_to_index_id_map.end())
- {
- result = ++m_thread_index_id;
- m_thread_id_to_index_id_map[thread_id] = result;
- }
- else
- {
- result = iterator->second;
+size_t Process::GetSoftwareBreakpointTrapOpcode(BreakpointSite *bp_site) {
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ if (platform_sp)
+ return platform_sp->GetSoftwareBreakpointTrapOpcode(GetTarget(), bp_site);
+ return 0;
+}
+
+Error Process::EnableSoftwareBreakpoint(BreakpointSite *bp_site) {
+ Error error;
+ assert(bp_site != nullptr);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ const addr_t bp_addr = bp_site->GetLoadAddress();
+ if (log)
+ log->Printf(
+ "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64,
+ bp_site->GetID(), (uint64_t)bp_addr);
+ if (bp_site->IsEnabled()) {
+ if (log)
+ log->Printf(
+ "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64
+ " -- already enabled",
+ bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
+
+ if (bp_addr == LLDB_INVALID_ADDRESS) {
+ error.SetErrorString("BreakpointSite contains an invalid load address.");
+ return error;
+ }
+ // Ask the lldb::Process subclass to fill in the correct software breakpoint
+ // trap for the breakpoint site
+ const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode(bp_site);
+
+ if (bp_opcode_size == 0) {
+ error.SetErrorStringWithFormat("Process::GetSoftwareBreakpointTrapOpcode() "
+ "returned zero, unable to get breakpoint "
+ "trap for address 0x%" PRIx64,
+ bp_addr);
+ } else {
+ const uint8_t *const bp_opcode_bytes = bp_site->GetTrapOpcodeBytes();
+
+ if (bp_opcode_bytes == nullptr) {
+ error.SetErrorString(
+ "BreakpointSite doesn't contain a valid breakpoint trap opcode.");
+ return error;
+ }
+
+ // Save the original opcode by reading it
+ if (DoReadMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), bp_opcode_size,
+ error) == bp_opcode_size) {
+ // Write a software breakpoint in place of the original opcode
+ if (DoWriteMemory(bp_addr, bp_opcode_bytes, bp_opcode_size, error) ==
+ bp_opcode_size) {
+ uint8_t verify_bp_opcode_bytes[64];
+ if (DoReadMemory(bp_addr, verify_bp_opcode_bytes, bp_opcode_size,
+ error) == bp_opcode_size) {
+ if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes,
+ bp_opcode_size) == 0) {
+ bp_site->SetEnabled(true);
+ bp_site->SetType(BreakpointSite::eSoftware);
+ if (log)
+ log->Printf("Process::EnableSoftwareBreakpoint (site_id = %d) "
+ "addr = 0x%" PRIx64 " -- SUCCESS",
+ bp_site->GetID(), (uint64_t)bp_addr);
+ } else
+ error.SetErrorString(
+ "failed to verify the breakpoint trap in memory.");
+ } else
+ error.SetErrorString(
+ "Unable to read memory to verify breakpoint trap.");
+ } else
+ error.SetErrorString("Unable to write breakpoint trap to memory.");
+ } else
+ error.SetErrorString("Unable to read memory at breakpoint address.");
+ }
+ if (log && error.Fail())
+ log->Printf(
+ "Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64
+ " -- FAILED: %s",
+ bp_site->GetID(), (uint64_t)bp_addr, error.AsCString());
+ return error;
+}
+
+Error Process::DisableSoftwareBreakpoint(BreakpointSite *bp_site) {
+ Error error;
+ assert(bp_site != nullptr);
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
+ addr_t bp_addr = bp_site->GetLoadAddress();
+ lldb::user_id_t breakID = bp_site->GetID();
+ if (log)
+ log->Printf("Process::DisableSoftwareBreakpoint (breakID = %" PRIu64
+ ") addr = 0x%" PRIx64,
+ breakID, (uint64_t)bp_addr);
+
+ if (bp_site->IsHardware()) {
+ error.SetErrorString("Breakpoint site is a hardware breakpoint.");
+ } else if (bp_site->IsEnabled()) {
+ const size_t break_op_size = bp_site->GetByteSize();
+ const uint8_t *const break_op = bp_site->GetTrapOpcodeBytes();
+ if (break_op_size > 0) {
+ // Clear a software breakpoint instruction
+ uint8_t curr_break_op[8];
+ assert(break_op_size <= sizeof(curr_break_op));
+ bool break_op_found = false;
+
+ // Read the breakpoint opcode
+ if (DoReadMemory(bp_addr, curr_break_op, break_op_size, error) ==
+ break_op_size) {
+ bool verify = false;
+ // Make sure the breakpoint opcode exists at this address
+ if (::memcmp(curr_break_op, break_op, break_op_size) == 0) {
+ break_op_found = true;
+ // We found a valid breakpoint opcode at this address, now restore
+ // the saved opcode.
+ if (DoWriteMemory(bp_addr, bp_site->GetSavedOpcodeBytes(),
+ break_op_size, error) == break_op_size) {
+ verify = true;
+ } else
+ error.SetErrorString(
+ "Memory write failed when restoring original opcode.");
+ } else {
+ error.SetErrorString(
+ "Original breakpoint trap is no longer in memory.");
+ // Set verify to true and so we can check if the original opcode has
+ // already been restored
+ verify = true;
+ }
+
+ if (verify) {
+ uint8_t verify_opcode[8];
+ assert(break_op_size < sizeof(verify_opcode));
+ // Verify that our original opcode made it back to the inferior
+ if (DoReadMemory(bp_addr, verify_opcode, break_op_size, error) ==
+ break_op_size) {
+ // compare the memory we just read with the original opcode
+ if (::memcmp(bp_site->GetSavedOpcodeBytes(), verify_opcode,
+ break_op_size) == 0) {
+ // SUCCESS
+ bp_site->SetEnabled(false);
+ if (log)
+ log->Printf("Process::DisableSoftwareBreakpoint (site_id = %d) "
+ "addr = 0x%" PRIx64 " -- SUCCESS",
+ bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ } else {
+ if (break_op_found)
+ error.SetErrorString("Failed to restore original opcode.");
+ }
+ } else
+ error.SetErrorString("Failed to read memory to verify that "
+ "breakpoint trap was restored.");
+ }
+ } else
+ error.SetErrorString(
+ "Unable to read memory that should contain the breakpoint trap.");
}
-
- return result;
-}
+ } else {
+ if (log)
+ log->Printf(
+ "Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64
+ " -- already disabled",
+ bp_site->GetID(), (uint64_t)bp_addr);
+ return error;
+ }
-StateType
-Process::GetState()
-{
- // If any other threads access this we will need a mutex for it
- return m_public_state.GetValue ();
+ if (log)
+ log->Printf(
+ "Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64
+ " -- FAILED: %s",
+ bp_site->GetID(), (uint64_t)bp_addr, error.AsCString());
+ return error;
}
-bool
-Process::StateChangedIsExternallyHijacked()
-{
- if (IsHijackedForEvent(eBroadcastBitStateChanged))
- {
- const char *hijacking_name = GetHijackingListenerName();
- if (hijacking_name && strcmp(hijacking_name, "lldb.Process.ResumeSynchronous.hijack"))
- return true;
- }
- return false;
-}
+// Uncomment to verify memory caching works after making changes to caching code
+//#define VERIFY_MEMORY_READS
-void
-Process::SetPublicState (StateType new_state, bool restarted)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::SetPublicState (state = %s, restarted = %i)", StateAsCString(new_state), restarted);
- const StateType old_state = m_public_state.GetValue();
- m_public_state.SetValue (new_state);
-
- // On the transition from Run to Stopped, we unlock the writer end of the
- // run lock. The lock gets locked in Resume, which is the public API
- // to tell the program to run.
- if (!StateChangedIsExternallyHijacked())
- {
- if (new_state == eStateDetached)
- {
- if (log)
- log->Printf("Process::SetPublicState (%s) -- unlocking run lock for detach", StateAsCString(new_state));
- m_public_run_lock.SetStopped();
- }
- else
- {
- const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
- const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
- if ((old_state_is_stopped != new_state_is_stopped))
- {
- if (new_state_is_stopped && !restarted)
- {
- if (log)
- log->Printf("Process::SetPublicState (%s) -- unlocking run lock", StateAsCString(new_state));
- m_public_run_lock.SetStopped();
- }
- }
- }
+size_t Process::ReadMemory(addr_t addr, void *buf, size_t size, Error &error) {
+ error.Clear();
+ if (!GetDisableMemoryCache()) {
+#if defined(VERIFY_MEMORY_READS)
+ // Memory caching is enabled, with debug verification
+
+ if (buf && size) {
+ // Uncomment the line below to make sure memory caching is working.
+ // I ran this through the test suite and got no assertions, so I am
+ // pretty confident this is working well. If any changes are made to
+ // memory caching, uncomment the line below and test your changes!
+
+ // Verify all memory reads by using the cache first, then redundantly
+ // reading the same memory from the inferior and comparing to make sure
+ // everything is exactly the same.
+ std::string verify_buf(size, '\0');
+ assert(verify_buf.size() == size);
+ const size_t cache_bytes_read =
+ m_memory_cache.Read(this, addr, buf, size, error);
+ Error verify_error;
+ const size_t verify_bytes_read =
+ ReadMemoryFromInferior(addr, const_cast<char *>(verify_buf.data()),
+ verify_buf.size(), verify_error);
+ assert(cache_bytes_read == verify_bytes_read);
+ assert(memcmp(buf, verify_buf.data(), verify_buf.size()) == 0);
+ assert(verify_error.Success() == error.Success());
+ return cache_bytes_read;
}
+ return 0;
+#else // !defined(VERIFY_MEMORY_READS)
+ // Memory caching is enabled, without debug verification
+
+ return m_memory_cache.Read(addr, buf, size, error);
+#endif // defined (VERIFY_MEMORY_READS)
+ } else {
+ // Memory caching is disabled
+
+ return ReadMemoryFromInferior(addr, buf, size, error);
+ }
}
-Error
-Process::Resume ()
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::Resume -- locking run lock");
- if (!m_public_run_lock.TrySetRunning())
- {
- Error error("Resume request failed - process still running.");
- if (log)
- log->Printf ("Process::Resume: -- TrySetRunning failed, not resuming.");
- return error;
- }
- return PrivateResume();
+size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str,
+ Error &error) {
+ char buf[256];
+ out_str.clear();
+ addr_t curr_addr = addr;
+ while (true) {
+ size_t length = ReadCStringFromMemory(curr_addr, buf, sizeof(buf), error);
+ if (length == 0)
+ break;
+ out_str.append(buf, length);
+ // If we got "length - 1" bytes, we didn't get the whole C string, we
+ // need to read some more characters
+ if (length == sizeof(buf) - 1)
+ curr_addr += length;
+ else
+ break;
+ }
+ return out_str.size();
+}
+
+size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes,
+ Error &error, size_t type_width) {
+ size_t total_bytes_read = 0;
+ if (dst && max_bytes && type_width && max_bytes >= type_width) {
+ // Ensure a null terminator independent of the number of bytes that is read.
+ memset(dst, 0, max_bytes);
+ size_t bytes_left = max_bytes - type_width;
+
+ const char terminator[4] = {'\0', '\0', '\0', '\0'};
+ assert(sizeof(terminator) >= type_width && "Attempting to validate a "
+ "string with more than 4 bytes "
+ "per character!");
+
+ addr_t curr_addr = addr;
+ const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
+ char *curr_dst = dst;
+
+ error.Clear();
+ while (bytes_left > 0 && error.Success()) {
+ addr_t cache_line_bytes_left =
+ cache_line_size - (curr_addr % cache_line_size);
+ addr_t bytes_to_read =
+ std::min<addr_t>(bytes_left, cache_line_bytes_left);
+ size_t bytes_read = ReadMemory(curr_addr, curr_dst, bytes_to_read, error);
+
+ if (bytes_read == 0)
+ break;
+
+ // Search for a null terminator of correct size and alignment in
+ // bytes_read
+ size_t aligned_start = total_bytes_read - total_bytes_read % type_width;
+ for (size_t i = aligned_start;
+ i + type_width <= total_bytes_read + bytes_read; i += type_width)
+ if (::memcmp(&dst[i], terminator, type_width) == 0) {
+ error.Clear();
+ return i;
+ }
+
+ total_bytes_read += bytes_read;
+ curr_dst += bytes_read;
+ curr_addr += bytes_read;
+ bytes_left -= bytes_read;
+ }
+ } else {
+ if (max_bytes)
+ error.SetErrorString("invalid arguments");
+ }
+ return total_bytes_read;
}
-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;
- }
+// Deprecated in favor of ReadStringFromMemory which has wchar support and
+// correct code to find
+// null terminators.
+size_t Process::ReadCStringFromMemory(addr_t addr, char *dst,
+ size_t dst_max_len, Error &result_error) {
+ size_t total_cstr_len = 0;
+ if (dst && dst_max_len) {
+ result_error.Clear();
+ // NULL out everything just to be safe
+ memset(dst, 0, dst_max_len);
+ Error error;
+ addr_t curr_addr = addr;
+ const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
+ size_t bytes_left = dst_max_len - 1;
+ char *curr_dst = dst;
+
+ while (bytes_left > 0) {
+ addr_t cache_line_bytes_left =
+ cache_line_size - (curr_addr % cache_line_size);
+ addr_t bytes_to_read =
+ std::min<addr_t>(bytes_left, cache_line_bytes_left);
+ size_t bytes_read = ReadMemory(curr_addr, curr_dst, bytes_to_read, error);
+
+ if (bytes_read == 0) {
+ result_error = error;
+ dst[total_cstr_len] = '\0';
+ break;
+ }
+ const size_t len = strlen(curr_dst);
+
+ total_cstr_len += len;
+
+ if (len < bytes_to_read)
+ break;
+
+ curr_dst += bytes_read;
+ curr_addr += bytes_read;
+ bytes_left -= bytes_read;
+ }
+ } else {
+ if (dst == nullptr)
+ result_error.SetErrorString("invalid arguments");
+ else
+ result_error.Clear();
+ }
+ return total_cstr_len;
+}
+
+size_t Process::ReadMemoryFromInferior(addr_t addr, void *buf, size_t size,
+ Error &error) {
+ if (buf == nullptr || size == 0)
+ return 0;
- ListenerSP listener_sp (Listener::MakeListener("lldb.Process.ResumeSynchronous.hijack"));
- HijackProcessEvents(listener_sp);
+ size_t bytes_read = 0;
+ uint8_t *bytes = (uint8_t *)buf;
- Error error = PrivateResume();
- if (error.Success())
- {
- StateType state = WaitForProcessToStop(std::chrono::microseconds(0), NULL, true, listener_sp, stream);
- const bool must_be_alive = false; // eStateExited is ok, so this must be false
- if (!StateIsStoppedState(state, must_be_alive))
- error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state));
- }
+ while (bytes_read < size) {
+ const size_t curr_size = size - bytes_read;
+ const size_t curr_bytes_read =
+ DoReadMemory(addr + bytes_read, bytes + bytes_read, curr_size, error);
+ bytes_read += curr_bytes_read;
+ if (curr_bytes_read == curr_size || curr_bytes_read == 0)
+ break;
+ }
+
+ // Replace any software breakpoint opcodes that fall into this range back
+ // into "buf" before we return
+ if (bytes_read > 0)
+ RemoveBreakpointOpcodesFromBuffer(addr, bytes_read, (uint8_t *)buf);
+ return bytes_read;
+}
+
+uint64_t Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr,
+ size_t integer_byte_size,
+ uint64_t fail_value,
+ Error &error) {
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar,
+ error))
+ return scalar.ULongLong(fail_value);
+ return fail_value;
+}
+
+int64_t Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr,
+ size_t integer_byte_size,
+ int64_t fail_value, Error &error) {
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, true, scalar,
+ error))
+ return scalar.SLongLong(fail_value);
+ return fail_value;
+}
+
+addr_t Process::ReadPointerFromMemory(lldb::addr_t vm_addr, Error &error) {
+ Scalar scalar;
+ if (ReadScalarIntegerFromMemory(vm_addr, GetAddressByteSize(), false, scalar,
+ error))
+ return scalar.ULongLong(LLDB_INVALID_ADDRESS);
+ return LLDB_INVALID_ADDRESS;
+}
+
+bool Process::WritePointerToMemory(lldb::addr_t vm_addr, lldb::addr_t ptr_value,
+ Error &error) {
+ Scalar scalar;
+ const uint32_t addr_byte_size = GetAddressByteSize();
+ if (addr_byte_size <= 4)
+ scalar = (uint32_t)ptr_value;
+ else
+ scalar = ptr_value;
+ return WriteScalarToMemory(vm_addr, scalar, addr_byte_size, error) ==
+ addr_byte_size;
+}
+
+size_t Process::WriteMemoryPrivate(addr_t addr, const void *buf, size_t size,
+ Error &error) {
+ size_t bytes_written = 0;
+ const uint8_t *bytes = (const uint8_t *)buf;
+
+ while (bytes_written < size) {
+ const size_t curr_size = size - bytes_written;
+ const size_t curr_bytes_written = DoWriteMemory(
+ addr + bytes_written, bytes + bytes_written, curr_size, error);
+ bytes_written += curr_bytes_written;
+ if (curr_bytes_written == curr_size || curr_bytes_written == 0)
+ break;
+ }
+ return bytes_written;
+}
+
+size_t Process::WriteMemory(addr_t addr, const void *buf, size_t size,
+ Error &error) {
+#if defined(ENABLE_MEMORY_CACHING)
+ m_memory_cache.Flush(addr, size);
+#endif
- // Undo the hijacking of process events...
- RestoreProcessEvents();
+ if (buf == nullptr || size == 0)
+ return 0;
- return error;
-}
+ m_mod_id.BumpMemoryID();
-StateType
-Process::GetPrivateState ()
-{
- return m_private_state.GetValue();
+ // We need to write any data that would go where any current software traps
+ // (enabled software breakpoints) any software traps (breakpoints) that we
+ // may have placed in our tasks memory.
+
+ BreakpointSiteList bp_sites_in_range;
+
+ if (m_breakpoint_site_list.FindInRange(addr, addr + size,
+ bp_sites_in_range)) {
+ // No breakpoint sites overlap
+ if (bp_sites_in_range.IsEmpty())
+ return WriteMemoryPrivate(addr, buf, size, error);
+ else {
+ const uint8_t *ubuf = (const uint8_t *)buf;
+ uint64_t bytes_written = 0;
+
+ bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf,
+ &error](BreakpointSite *bp) -> void {
+
+ if (error.Success()) {
+ addr_t intersect_addr;
+ size_t intersect_size;
+ size_t opcode_offset;
+ const bool intersects = bp->IntersectsRange(
+ addr, size, &intersect_addr, &intersect_size, &opcode_offset);
+ UNUSED_IF_ASSERT_DISABLED(intersects);
+ assert(intersects);
+ assert(addr <= intersect_addr && intersect_addr < addr + size);
+ assert(addr < intersect_addr + intersect_size &&
+ intersect_addr + intersect_size <= addr + size);
+ assert(opcode_offset + intersect_size <= bp->GetByteSize());
+
+ // Check for bytes before this breakpoint
+ const addr_t curr_addr = addr + bytes_written;
+ if (intersect_addr > curr_addr) {
+ // There are some bytes before this breakpoint that we need to
+ // just write to memory
+ size_t curr_size = intersect_addr - curr_addr;
+ size_t curr_bytes_written = WriteMemoryPrivate(
+ curr_addr, ubuf + bytes_written, curr_size, error);
+ bytes_written += curr_bytes_written;
+ if (curr_bytes_written != curr_size) {
+ // We weren't able to write all of the requested bytes, we
+ // are done looping and will return the number of bytes that
+ // we have written so far.
+ if (error.Success())
+ error.SetErrorToGenericError();
+ }
+ }
+ // Now write any bytes that would cover up any software breakpoints
+ // directly into the breakpoint opcode buffer
+ ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset,
+ ubuf + bytes_written, intersect_size);
+ bytes_written += intersect_size;
+ }
+ });
+
+ if (bytes_written < size)
+ WriteMemoryPrivate(addr + bytes_written, ubuf + bytes_written,
+ size - bytes_written, error);
+ }
+ } else {
+ return WriteMemoryPrivate(addr, buf, size, error);
+ }
+
+ // Write any remaining bytes after the last breakpoint if we have any left
+ return 0; // bytes_written;
+}
+
+size_t Process::WriteScalarToMemory(addr_t addr, const Scalar &scalar,
+ size_t byte_size, Error &error) {
+ if (byte_size == UINT32_MAX)
+ byte_size = scalar.GetByteSize();
+ if (byte_size > 0) {
+ uint8_t buf[32];
+ const size_t mem_size =
+ scalar.GetAsMemoryData(buf, byte_size, GetByteOrder(), error);
+ if (mem_size > 0)
+ return WriteMemory(addr, buf, mem_size, error);
+ else
+ error.SetErrorString("failed to get scalar as memory data");
+ } else {
+ error.SetErrorString("invalid scalar value");
+ }
+ return 0;
+}
+
+size_t Process::ReadScalarIntegerFromMemory(addr_t addr, uint32_t byte_size,
+ bool is_signed, Scalar &scalar,
+ Error &error) {
+ uint64_t uval = 0;
+ if (byte_size == 0) {
+ error.SetErrorString("byte size is zero");
+ } else if (byte_size & (byte_size - 1)) {
+ error.SetErrorStringWithFormat("byte size %u is not a power of 2",
+ byte_size);
+ } else if (byte_size <= sizeof(uval)) {
+ const size_t bytes_read = ReadMemory(addr, &uval, byte_size, error);
+ if (bytes_read == byte_size) {
+ DataExtractor data(&uval, sizeof(uval), GetByteOrder(),
+ GetAddressByteSize());
+ lldb::offset_t offset = 0;
+ if (byte_size <= 4)
+ scalar = data.GetMaxU32(&offset, byte_size);
+ else
+ scalar = data.GetMaxU64(&offset, byte_size);
+ if (is_signed)
+ scalar.SignExtend(byte_size * 8);
+ return bytes_read;
+ }
+ } else {
+ error.SetErrorStringWithFormat(
+ "byte size of %u is too large for integer scalar type", byte_size);
+ }
+ return 0;
}
-void
-Process::SetPrivateState (StateType new_state)
-{
- if (m_finalize_called)
- return;
+#define USE_ALLOCATE_MEMORY_CACHE 1
+addr_t Process::AllocateMemory(size_t size, uint32_t permissions,
+ Error &error) {
+ if (GetPrivateState() != eStateStopped)
+ return LLDB_INVALID_ADDRESS;
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STATE | LIBLLDB_LOG_PROCESS));
- bool state_changed = false;
+#if defined(USE_ALLOCATE_MEMORY_CACHE)
+ return m_allocated_memory_cache.AllocateMemory(size, permissions, error);
+#else
+ addr_t allocated_addr = DoAllocateMemory(size, permissions, error);
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::AllocateMemory(size=%" PRIu64
+ ", permissions=%s) => 0x%16.16" PRIx64
+ " (m_stop_id = %u m_memory_id = %u)",
+ (uint64_t)size, GetPermissionsAsCString(permissions),
+ (uint64_t)allocated_addr, m_mod_id.GetStopID(),
+ m_mod_id.GetMemoryID());
+ return allocated_addr;
+#endif
+}
- if (log)
- log->Printf("Process::SetPrivateState (%s)", StateAsCString(new_state));
+addr_t Process::CallocateMemory(size_t size, uint32_t permissions,
+ Error &error) {
+ addr_t return_addr = AllocateMemory(size, permissions, error);
+ if (error.Success()) {
+ std::string buffer(size, 0);
+ WriteMemory(return_addr, buffer.c_str(), size, error);
+ }
+ return return_addr;
+}
- std::lock_guard<std::recursive_mutex> thread_guard(m_thread_list.GetMutex());
- std::lock_guard<std::recursive_mutex> guard(m_private_state.GetMutex());
+bool Process::CanJIT() {
+ if (m_can_jit == eCanJITDontKnow) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Error err;
- const StateType old_state = m_private_state.GetValueNoLock ();
- state_changed = old_state != new_state;
+ uint64_t allocated_memory = AllocateMemory(
+ 8, ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable,
+ err);
- const bool old_state_is_stopped = StateIsStoppedState(old_state, false);
- const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
- if (old_state_is_stopped != new_state_is_stopped)
- {
- if (new_state_is_stopped)
- m_private_run_lock.SetStopped();
- else
- m_private_run_lock.SetRunning();
+ if (err.Success()) {
+ m_can_jit = eCanJITYes;
+ if (log)
+ log->Printf("Process::%s pid %" PRIu64
+ " allocation test passed, CanJIT () is true",
+ __FUNCTION__, GetID());
+ } else {
+ m_can_jit = eCanJITNo;
+ if (log)
+ log->Printf("Process::%s pid %" PRIu64
+ " allocation test failed, CanJIT () is false: %s",
+ __FUNCTION__, GetID(), err.AsCString());
}
- if (state_changed)
- {
- m_private_state.SetValueNoLock (new_state);
- EventSP event_sp (new Event (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state)));
- if (StateIsStoppedState(new_state, false))
- {
- // Note, this currently assumes that all threads in the list
- // stop when the process stops. In the future we will want to
- // support a debugging model where some threads continue to run
- // while others are stopped. When that happens we will either need
- // a way for the thread list to identify which threads are stopping
- // or create a special thread list containing only threads which
- // actually stopped.
- //
- // The process plugin is responsible for managing the actual
- // behavior of the threads and should have stopped any threads
- // that are going to stop before we get here.
- m_thread_list.DidStop();
-
- m_mod_id.BumpStopID();
- if (!m_mod_id.IsLastResumeForUserExpression())
- m_mod_id.SetStopEventForLastNaturalStopID(event_sp);
- m_memory_cache.Clear();
- if (log)
- log->Printf("Process::SetPrivateState (%s) stop_id = %u", StateAsCString(new_state), m_mod_id.GetStopID());
- }
-
- // Use our target to get a shared pointer to ourselves...
- if (m_finalize_called && !PrivateStateThreadIsValid())
- BroadcastEvent (event_sp);
- else
- m_private_state_broadcaster.BroadcastEvent (event_sp);
- }
- else
- {
- if (log)
- log->Printf("Process::SetPrivateState (%s) state didn't change. Ignoring...", StateAsCString(new_state));
- }
-}
+ DeallocateMemory(allocated_memory);
+ }
-void
-Process::SetRunningUserExpression (bool on)
-{
- m_mod_id.SetRunningUserExpression (on);
+ return m_can_jit == eCanJITYes;
}
-addr_t
-Process::GetImageInfoAddress()
-{
- return LLDB_INVALID_ADDRESS;
+void Process::SetCanJIT(bool can_jit) {
+ m_can_jit = (can_jit ? eCanJITYes : eCanJITNo);
}
-const lldb::ABISP &
-Process::GetABI()
-{
- if (!m_abi_sp)
- m_abi_sp = ABI::FindPlugin(GetTarget().GetArchitecture());
- return m_abi_sp;
+void Process::SetCanRunCode(bool can_run_code) {
+ SetCanJIT(can_run_code);
+ m_can_interpret_function_calls = can_run_code;
}
-LanguageRuntime *
-Process::GetLanguageRuntime(lldb::LanguageType language, bool retry_if_null)
-{
- if (m_finalizing)
- return nullptr;
+Error Process::DeallocateMemory(addr_t ptr) {
+ Error error;
+#if defined(USE_ALLOCATE_MEMORY_CACHE)
+ if (!m_allocated_memory_cache.DeallocateMemory(ptr)) {
+ error.SetErrorStringWithFormat(
+ "deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr);
+ }
+#else
+ error = DoDeallocateMemory(ptr);
- LanguageRuntimeCollection::iterator pos;
- pos = m_language_runtimes.find (language);
- if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second))
- {
- lldb::LanguageRuntimeSP runtime_sp(LanguageRuntime::FindPlugin(this, language));
-
- m_language_runtimes[language] = runtime_sp;
- return runtime_sp.get();
- }
- else
- return (*pos).second.get();
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::DeallocateMemory(addr=0x%16.16" PRIx64
+ ") => err = %s (m_stop_id = %u, m_memory_id = %u)",
+ ptr, error.AsCString("SUCCESS"), m_mod_id.GetStopID(),
+ m_mod_id.GetMemoryID());
+#endif
+ return error;
}
-CPPLanguageRuntime *
-Process::GetCPPLanguageRuntime (bool retry_if_null)
-{
- LanguageRuntime *runtime = GetLanguageRuntime(eLanguageTypeC_plus_plus, retry_if_null);
- if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeC_plus_plus)
- return static_cast<CPPLanguageRuntime *> (runtime);
- return nullptr;
+ModuleSP Process::ReadModuleFromMemory(const FileSpec &file_spec,
+ lldb::addr_t header_addr,
+ size_t size_to_read) {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
+ if (log) {
+ log->Printf("Process::ReadModuleFromMemory reading %s binary from memory",
+ file_spec.GetPath().c_str());
+ }
+ ModuleSP module_sp(new Module(file_spec, ArchSpec()));
+ if (module_sp) {
+ Error error;
+ ObjectFile *objfile = module_sp->GetMemoryObjectFile(
+ shared_from_this(), header_addr, error, size_to_read);
+ if (objfile)
+ return module_sp;
+ }
+ return ModuleSP();
}
-ObjCLanguageRuntime *
-Process::GetObjCLanguageRuntime (bool retry_if_null)
-{
- LanguageRuntime *runtime = GetLanguageRuntime(eLanguageTypeObjC, retry_if_null);
- if (runtime != nullptr && runtime->GetLanguageType() == eLanguageTypeObjC)
- return static_cast<ObjCLanguageRuntime *> (runtime);
- return nullptr;
-}
+bool Process::GetLoadAddressPermissions(lldb::addr_t load_addr,
+ uint32_t &permissions) {
+ MemoryRegionInfo range_info;
+ permissions = 0;
+ Error error(GetMemoryRegionInfo(load_addr, range_info));
+ if (!error.Success())
+ return false;
+ if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow ||
+ range_info.GetWritable() == MemoryRegionInfo::eDontKnow ||
+ range_info.GetExecutable() == MemoryRegionInfo::eDontKnow) {
+ return false;
+ }
-bool
-Process::IsPossibleDynamicValue (ValueObject& in_value)
-{
- if (m_finalizing)
- return false;
+ if (range_info.GetReadable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsReadable;
- if (in_value.IsDynamic())
- return false;
- LanguageType known_type = in_value.GetObjectRuntimeLanguage();
+ if (range_info.GetWritable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsWritable;
- if (known_type != eLanguageTypeUnknown && known_type != eLanguageTypeC)
- {
- LanguageRuntime *runtime = GetLanguageRuntime (known_type);
- return runtime ? runtime->CouldHaveDynamicValue(in_value) : false;
- }
+ if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsExecutable;
- LanguageRuntime *cpp_runtime = GetLanguageRuntime (eLanguageTypeC_plus_plus);
- if (cpp_runtime && cpp_runtime->CouldHaveDynamicValue(in_value))
- return true;
-
- LanguageRuntime *objc_runtime = GetLanguageRuntime (eLanguageTypeObjC);
- return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false;
+ return true;
}
-void
-Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers)
-{
- m_dynamic_checkers_ap.reset(dynamic_checkers);
+Error Process::EnableWatchpoint(Watchpoint *watchpoint, bool notify) {
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
}
-BreakpointSiteList &
-Process::GetBreakpointSiteList()
-{
- return m_breakpoint_site_list;
+Error Process::DisableWatchpoint(Watchpoint *watchpoint, bool notify) {
+ Error error;
+ error.SetErrorString("watchpoints are not supported");
+ return error;
}
-const BreakpointSiteList &
-Process::GetBreakpointSiteList() const
-{
- return m_breakpoint_site_list;
+StateType
+Process::WaitForProcessStopPrivate(const std::chrono::microseconds &timeout,
+ EventSP &event_sp) {
+ StateType state;
+ // Now wait for the process to launch and return control to us, and then
+ // call DidLaunch:
+ while (true) {
+ event_sp.reset();
+ state = WaitForStateChangedEventsPrivate(timeout, event_sp);
+
+ if (StateIsStoppedState(state, false))
+ break;
+
+ // If state is invalid, then we timed out
+ if (state == eStateInvalid)
+ break;
+
+ if (event_sp)
+ HandlePrivateEvent(event_sp);
+ }
+ return state;
}
-void
-Process::DisableAllBreakpointSites ()
-{
- m_breakpoint_site_list.ForEach([this](BreakpointSite *bp_site) -> void {
-// bp_site->SetEnabled(true);
- DisableBreakpointSite(bp_site);
- });
+void Process::LoadOperatingSystemPlugin(bool flush) {
+ if (flush)
+ m_thread_list.Clear();
+ m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
+ if (flush)
+ Flush();
}
-Error
-Process::ClearBreakpointSiteByID (lldb::user_id_t break_id)
-{
- Error error (DisableBreakpointSiteByID (break_id));
-
- if (error.Success())
- m_breakpoint_site_list.Remove(break_id);
+Error Process::Launch(ProcessLaunchInfo &launch_info) {
+ Error error;
+ m_abi_sp.reset();
+ m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
+ m_system_runtime_ap.reset();
+ m_os_ap.reset();
+ m_process_input_reader.reset();
+ m_stop_info_override_callback = nullptr;
+
+ Module *exe_module = GetTarget().GetExecutableModulePointer();
+ if (exe_module) {
+ char local_exec_file_path[PATH_MAX];
+ char platform_exec_file_path[PATH_MAX];
+ exe_module->GetFileSpec().GetPath(local_exec_file_path,
+ sizeof(local_exec_file_path));
+ exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path,
+ sizeof(platform_exec_file_path));
+ if (exe_module->GetFileSpec().Exists()) {
+ // Install anything that might need to be installed prior to launching.
+ // For host systems, this will do nothing, but if we are connected to a
+ // remote platform it will install any needed binaries
+ error = GetTarget().Install(&launch_info);
+ if (error.Fail())
+ return error;
- return error;
-}
+ if (PrivateStateThreadIsValid())
+ PausePrivateStateThread();
-Error
-Process::DisableBreakpointSiteByID (lldb::user_id_t break_id)
-{
- Error error;
- BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id);
- if (bp_site_sp)
- {
- if (bp_site_sp->IsEnabled())
- error = DisableBreakpointSite (bp_site_sp.get());
- }
- else
- {
- error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, break_id);
- }
+ error = WillLaunch(exe_module);
+ if (error.Success()) {
+ const bool restarted = false;
+ SetPublicState(eStateLaunching, restarted);
+ m_should_detach = false;
- return error;
-}
+ if (m_public_run_lock.TrySetRunning()) {
+ // Now launch using these arguments.
+ error = DoLaunch(exe_module, launch_info);
+ } else {
+ // This shouldn't happen
+ error.SetErrorString("failed to acquire process run lock");
+ }
+
+ if (error.Fail()) {
+ if (GetID() != LLDB_INVALID_PROCESS_ID) {
+ SetID(LLDB_INVALID_PROCESS_ID);
+ const char *error_string = error.AsCString();
+ if (error_string == nullptr)
+ error_string = "launch failed";
+ SetExitStatus(-1, error_string);
+ }
+ } else {
+ EventSP event_sp;
+ StateType state =
+ WaitForProcessStopPrivate(std::chrono::seconds(10), event_sp);
+
+ if (state == eStateInvalid || !event_sp) {
+ // We were able to launch the process, but we failed to
+ // catch the initial stop.
+ error.SetErrorString("failed to catch stop after launch");
+ SetExitStatus(0, "failed to catch stop after launch");
+ Destroy(false);
+ } else if (state == eStateStopped || state == eStateCrashed) {
+ DidLaunch();
-Error
-Process::EnableBreakpointSiteByID (lldb::user_id_t break_id)
-{
- Error error;
- BreakpointSiteSP bp_site_sp = m_breakpoint_site_list.FindByID (break_id);
- if (bp_site_sp)
- {
- if (!bp_site_sp->IsEnabled())
- error = EnableBreakpointSite (bp_site_sp.get());
- }
- else
- {
- error.SetErrorStringWithFormat("invalid breakpoint site ID: %" PRIu64, break_id);
- }
- return error;
-}
+ DynamicLoader *dyld = GetDynamicLoader();
+ if (dyld)
+ dyld->DidLaunch();
+
+ GetJITLoaders().DidLaunch();
+
+ SystemRuntime *system_runtime = GetSystemRuntime();
+ if (system_runtime)
+ system_runtime->DidLaunch();
+
+ 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);
-lldb::break_id_t
-Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardware)
-{
- addr_t load_addr = LLDB_INVALID_ADDRESS;
-
- bool show_error = true;
- switch (GetState())
- {
- case eStateInvalid:
- case eStateUnloaded:
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- case eStateDetached:
- case eStateExited:
- show_error = false;
- break;
-
- case eStateStopped:
- case eStateRunning:
- case eStateStepping:
- case eStateCrashed:
- case eStateSuspended:
- show_error = IsAlive();
- break;
- }
+ if (PrivateStateThreadIsValid())
+ ResumePrivateStateThread();
+ else
+ StartPrivateStateThread();
- // Reset the IsIndirect flag here, in case the location changes from
- // pointing to a indirect symbol to a regular symbol.
- owner->SetIsIndirect (false);
-
- if (owner->ShouldResolveIndirectFunctions())
- {
- Symbol *symbol = owner->GetAddress().CalculateSymbolContextSymbol();
- if (symbol && symbol->IsIndirect())
- {
- Error error;
- Address symbol_address = symbol->GetAddress();
- load_addr = ResolveIndirectFunction (&symbol_address, error);
- if (!error.Success() && show_error)
- {
- GetTarget().GetDebugger().GetErrorFile()->Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n",
- symbol->GetLoadAddress(&GetTarget()),
- owner->GetBreakpoint().GetID(),
- owner->GetID(),
- error.AsCString() ? error.AsCString() : "unknown error");
- return LLDB_INVALID_BREAK_ID;
- }
- Address resolved_address(load_addr);
- load_addr = resolved_address.GetOpcodeLoadAddress (&GetTarget());
- owner->SetIsIndirect(true);
- }
- else
- load_addr = owner->GetAddress().GetOpcodeLoadAddress (&GetTarget());
- }
+ m_stop_info_override_callback =
+ GetTarget().GetArchitecture().GetStopInfoOverrideCallback();
+
+ // Target was stopped at entry as was intended. Need to notify the
+ // listeners
+ // about it.
+ if (state == eStateStopped &&
+ launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
+ HandlePrivateEvent(event_sp);
+ } else if (state == eStateExited) {
+ // We exited while trying to launch somehow. Don't call DidLaunch
+ // as that's
+ // not likely to work, and return an invalid pid.
+ HandlePrivateEvent(event_sp);
+ }
+ }
+ }
+ } else {
+ error.SetErrorStringWithFormat("file doesn't exist: '%s'",
+ local_exec_file_path);
+ }
+ }
+ return error;
+}
+
+Error Process::LoadCore() {
+ Error error = DoLoadCore();
+ if (error.Success()) {
+ ListenerSP listener_sp(
+ Listener::MakeListener("lldb.process.load_core_listener"));
+ HijackProcessEvents(listener_sp);
+
+ if (PrivateStateThreadIsValid())
+ ResumePrivateStateThread();
else
- load_addr = owner->GetAddress().GetOpcodeLoadAddress (&GetTarget());
-
- if (load_addr != LLDB_INVALID_ADDRESS)
- {
- BreakpointSiteSP bp_site_sp;
-
- // Look up this breakpoint site. If it exists, then add this new owner, otherwise
- // create a new breakpoint site and add it.
-
- bp_site_sp = m_breakpoint_site_list.FindByAddress (load_addr);
-
- if (bp_site_sp)
- {
- bp_site_sp->AddOwner (owner);
- owner->SetBreakpointSite (bp_site_sp);
- return bp_site_sp->GetID();
- }
- else
- {
- bp_site_sp.reset (new BreakpointSite (&m_breakpoint_site_list, owner, load_addr, use_hardware));
- if (bp_site_sp)
- {
- Error error = EnableBreakpointSite (bp_site_sp.get());
- if (error.Success())
- {
- owner->SetBreakpointSite (bp_site_sp);
- return m_breakpoint_site_list.Add (bp_site_sp);
- }
- else
- {
- if (show_error)
- {
- // Report error for setting breakpoint...
- GetTarget().GetDebugger().GetErrorFile()->Printf ("warning: failed to set breakpoint site at 0x%" PRIx64 " for breakpoint %i.%i: %s\n",
- load_addr,
- owner->GetBreakpoint().GetID(),
- owner->GetID(),
- error.AsCString() ? error.AsCString() : "unknown error");
- }
- }
- }
- }
+ StartPrivateStateThread();
+
+ DynamicLoader *dyld = GetDynamicLoader();
+ if (dyld)
+ dyld->DidAttach();
+
+ GetJITLoaders().DidAttach();
+
+ SystemRuntime *system_runtime = GetSystemRuntime();
+ if (system_runtime)
+ system_runtime->DidAttach();
+
+ m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
+ // We successfully loaded a core file, now pretend we stopped so we can
+ // show all of the threads in the core file and explore the crashed
+ // state.
+ SetPrivateState(eStateStopped);
+
+ // Wait indefinitely for a stopped event since we just posted one above...
+ lldb::EventSP event_sp;
+ listener_sp->WaitForEvent(std::chrono::microseconds(0), event_sp);
+ StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (!StateIsStoppedState(state, false)) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::Halt() failed to stop, state is: %s",
+ StateAsCString(state));
+ error.SetErrorString(
+ "Did not get stopped event after loading the core file.");
}
- // We failed to enable the breakpoint
- return LLDB_INVALID_BREAK_ID;
+ RestoreProcessEvents();
+ }
+ return error;
}
-void
-Process::RemoveOwnerFromBreakpointSite (lldb::user_id_t owner_id, lldb::user_id_t owner_loc_id, BreakpointSiteSP &bp_site_sp)
-{
- uint32_t num_owners = bp_site_sp->RemoveOwner (owner_id, owner_loc_id);
- if (num_owners == 0)
- {
- // Don't try to disable the site if we don't have a live process anymore.
- if (IsAlive())
- DisableBreakpointSite (bp_site_sp.get());
- m_breakpoint_site_list.RemoveByAddress(bp_site_sp->GetLoadAddress());
- }
+DynamicLoader *Process::GetDynamicLoader() {
+ if (!m_dyld_ap)
+ m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr));
+ return m_dyld_ap.get();
}
-size_t
-Process::RemoveBreakpointOpcodesFromBuffer (addr_t bp_addr, size_t size, uint8_t *buf) const
-{
- size_t bytes_removed = 0;
- BreakpointSiteList bp_sites_in_range;
+const lldb::DataBufferSP Process::GetAuxvData() { return DataBufferSP(); }
- if (m_breakpoint_site_list.FindInRange (bp_addr, bp_addr + size, bp_sites_in_range))
- {
- bp_sites_in_range.ForEach([bp_addr, size, buf, &bytes_removed](BreakpointSite *bp_site) -> void {
- if (bp_site->GetType() == BreakpointSite::eSoftware)
- {
- addr_t intersect_addr;
- size_t intersect_size;
- size_t opcode_offset;
- if (bp_site->IntersectsRange(bp_addr, size, &intersect_addr, &intersect_size, &opcode_offset))
- {
- assert(bp_addr <= intersect_addr && intersect_addr < bp_addr + size);
- assert(bp_addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= bp_addr + size);
- assert(opcode_offset + intersect_size <= bp_site->GetByteSize());
- size_t buf_offset = intersect_addr - bp_addr;
- ::memcpy(buf + buf_offset, bp_site->GetSavedOpcodeBytes() + opcode_offset, intersect_size);
- }
- }
- });
- }
- return bytes_removed;
+JITLoaderList &Process::GetJITLoaders() {
+ if (!m_jit_loaders_ap) {
+ m_jit_loaders_ap.reset(new JITLoaderList());
+ JITLoader::LoadPlugins(this, *m_jit_loaders_ap);
+ }
+ return *m_jit_loaders_ap;
}
-size_t
-Process::GetSoftwareBreakpointTrapOpcode (BreakpointSite* bp_site)
-{
- PlatformSP platform_sp (GetTarget().GetPlatform());
- if (platform_sp)
- return platform_sp->GetSoftwareBreakpointTrapOpcode (GetTarget(), bp_site);
- return 0;
+SystemRuntime *Process::GetSystemRuntime() {
+ if (!m_system_runtime_ap)
+ m_system_runtime_ap.reset(SystemRuntime::FindPlugin(this));
+ return m_system_runtime_ap.get();
}
-Error
-Process::EnableSoftwareBreakpoint (BreakpointSite *bp_site)
-{
- Error error;
- assert(bp_site != nullptr);
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
- const addr_t bp_addr = bp_site->GetLoadAddress();
- if (log)
- log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64, bp_site->GetID(), (uint64_t)bp_addr);
- if (bp_site->IsEnabled())
- {
- if (log)
- log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- already enabled", bp_site->GetID(), (uint64_t)bp_addr);
- return error;
- }
+Process::AttachCompletionHandler::AttachCompletionHandler(Process *process,
+ uint32_t exec_count)
+ : NextEventAction(process), m_exec_count(exec_count) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf(
+ "Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32,
+ __FUNCTION__, static_cast<void *>(process), exec_count);
+}
- if (bp_addr == LLDB_INVALID_ADDRESS)
- {
- error.SetErrorString("BreakpointSite contains an invalid load address.");
- return error;
- }
- // Ask the lldb::Process subclass to fill in the correct software breakpoint
- // trap for the breakpoint site
- const size_t bp_opcode_size = GetSoftwareBreakpointTrapOpcode(bp_site);
-
- if (bp_opcode_size == 0)
- {
- error.SetErrorStringWithFormat ("Process::GetSoftwareBreakpointTrapOpcode() returned zero, unable to get breakpoint trap for address 0x%" PRIx64, bp_addr);
- }
- else
- {
- const uint8_t * const bp_opcode_bytes = bp_site->GetTrapOpcodeBytes();
-
- if (bp_opcode_bytes == nullptr)
- {
- error.SetErrorString ("BreakpointSite doesn't contain a valid breakpoint trap opcode.");
- return error;
- }
-
- // Save the original opcode by reading it
- if (DoReadMemory(bp_addr, bp_site->GetSavedOpcodeBytes(), bp_opcode_size, error) == bp_opcode_size)
- {
- // Write a software breakpoint in place of the original opcode
- if (DoWriteMemory(bp_addr, bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size)
- {
- uint8_t verify_bp_opcode_bytes[64];
- if (DoReadMemory(bp_addr, verify_bp_opcode_bytes, bp_opcode_size, error) == bp_opcode_size)
- {
- if (::memcmp(bp_opcode_bytes, verify_bp_opcode_bytes, bp_opcode_size) == 0)
- {
- bp_site->SetEnabled(true);
- bp_site->SetType (BreakpointSite::eSoftware);
- if (log)
- log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- SUCCESS",
- bp_site->GetID(),
- (uint64_t)bp_addr);
- }
- else
- error.SetErrorString("failed to verify the breakpoint trap in memory.");
- }
- else
- error.SetErrorString("Unable to read memory to verify breakpoint trap.");
- }
- else
- error.SetErrorString("Unable to write breakpoint trap to memory.");
- }
- else
- error.SetErrorString("Unable to read memory at breakpoint address.");
- }
- if (log && error.Fail())
- log->Printf ("Process::EnableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- FAILED: %s",
- bp_site->GetID(),
- (uint64_t)bp_addr,
- error.AsCString());
- return error;
-}
-
-Error
-Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
-{
- Error error;
- assert(bp_site != nullptr);
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS));
- addr_t bp_addr = bp_site->GetLoadAddress();
- lldb::user_id_t breakID = bp_site->GetID();
- if (log)
- log->Printf ("Process::DisableSoftwareBreakpoint (breakID = %" PRIu64 ") addr = 0x%" PRIx64, breakID, (uint64_t)bp_addr);
-
- if (bp_site->IsHardware())
- {
- error.SetErrorString("Breakpoint site is a hardware breakpoint.");
- }
- else if (bp_site->IsEnabled())
- {
- const size_t break_op_size = bp_site->GetByteSize();
- const uint8_t * const break_op = bp_site->GetTrapOpcodeBytes();
- if (break_op_size > 0)
- {
- // Clear a software breakpoint instruction
- uint8_t curr_break_op[8];
- assert (break_op_size <= sizeof(curr_break_op));
- bool break_op_found = false;
-
- // Read the breakpoint opcode
- if (DoReadMemory (bp_addr, curr_break_op, break_op_size, error) == break_op_size)
- {
- bool verify = false;
- // Make sure the breakpoint opcode exists at this address
- if (::memcmp (curr_break_op, break_op, break_op_size) == 0)
- {
- break_op_found = true;
- // We found a valid breakpoint opcode at this address, now restore
- // the saved opcode.
- if (DoWriteMemory (bp_addr, bp_site->GetSavedOpcodeBytes(), break_op_size, error) == break_op_size)
- {
- verify = true;
- }
- else
- error.SetErrorString("Memory write failed when restoring original opcode.");
- }
- else
- {
- error.SetErrorString("Original breakpoint trap is no longer in memory.");
- // Set verify to true and so we can check if the original opcode has already been restored
- verify = true;
- }
+Process::NextEventAction::EventActionResult
+Process::AttachCompletionHandler::PerformAction(lldb::EventSP &event_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (verify)
- {
- uint8_t verify_opcode[8];
- assert (break_op_size < sizeof(verify_opcode));
- // Verify that our original opcode made it back to the inferior
- if (DoReadMemory (bp_addr, verify_opcode, break_op_size, error) == break_op_size)
- {
- // compare the memory we just read with the original opcode
- if (::memcmp (bp_site->GetSavedOpcodeBytes(), verify_opcode, break_op_size) == 0)
- {
- // SUCCESS
- bp_site->SetEnabled(false);
- if (log)
- log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- SUCCESS", bp_site->GetID(), (uint64_t)bp_addr);
- return error;
- }
- else
- {
- if (break_op_found)
- error.SetErrorString("Failed to restore original opcode.");
- }
- }
- else
- error.SetErrorString("Failed to read memory to verify that breakpoint trap was restored.");
- }
- }
- else
- error.SetErrorString("Unable to read memory that should contain the breakpoint trap.");
- }
- }
- else
- {
- if (log)
- log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- already disabled", bp_site->GetID(), (uint64_t)bp_addr);
- return error;
- }
+ StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (log)
+ log->Printf(
+ "Process::AttachCompletionHandler::%s called with state %s (%d)",
+ __FUNCTION__, StateAsCString(state), static_cast<int>(state));
- if (log)
- log->Printf ("Process::DisableSoftwareBreakpoint (site_id = %d) addr = 0x%" PRIx64 " -- FAILED: %s",
- bp_site->GetID(),
- (uint64_t)bp_addr,
- error.AsCString());
- return error;
-}
+ switch (state) {
+ case eStateAttaching:
+ return eEventActionSuccess;
-// Uncomment to verify memory caching works after making changes to caching code
-//#define VERIFY_MEMORY_READS
+ case eStateRunning:
+ case eStateConnected:
+ return eEventActionRetry;
+
+ case eStateStopped:
+ case eStateCrashed:
+ // During attach, prior to sending the eStateStopped event,
+ // lldb_private::Process subclasses must set the new process ID.
+ assert(m_process->GetID() != LLDB_INVALID_PROCESS_ID);
+ // We don't want these events to be reported, so go set the ShouldReportStop
+ // here:
+ m_process->GetThreadList().SetShouldReportStop(eVoteNo);
+
+ if (m_exec_count > 0) {
+ --m_exec_count;
+
+ if (log)
+ log->Printf("Process::AttachCompletionHandler::%s state %s: reduced "
+ "remaining exec count to %" PRIu32 ", requesting resume",
+ __FUNCTION__, StateAsCString(state), m_exec_count);
+
+ RequestResume();
+ return eEventActionRetry;
+ } else {
+ if (log)
+ log->Printf("Process::AttachCompletionHandler::%s state %s: no more "
+ "execs expected to start, continuing with attach",
+ __FUNCTION__, StateAsCString(state));
+
+ m_process->CompleteAttach();
+ return eEventActionSuccess;
+ }
+ break;
+
+ default:
+ case eStateExited:
+ case eStateInvalid:
+ break;
+ }
-size_t
-Process::ReadMemory (addr_t addr, void *buf, size_t size, Error &error)
-{
- error.Clear();
- if (!GetDisableMemoryCache())
- {
-#if defined (VERIFY_MEMORY_READS)
- // Memory caching is enabled, with debug verification
-
- if (buf && size)
- {
- // Uncomment the line below to make sure memory caching is working.
- // I ran this through the test suite and got no assertions, so I am
- // pretty confident this is working well. If any changes are made to
- // memory caching, uncomment the line below and test your changes!
-
- // Verify all memory reads by using the cache first, then redundantly
- // reading the same memory from the inferior and comparing to make sure
- // everything is exactly the same.
- std::string verify_buf (size, '\0');
- assert (verify_buf.size() == size);
- const size_t cache_bytes_read = m_memory_cache.Read (this, addr, buf, size, error);
- Error verify_error;
- const size_t verify_bytes_read = ReadMemoryFromInferior (addr, const_cast<char *>(verify_buf.data()), verify_buf.size(), verify_error);
- assert (cache_bytes_read == verify_bytes_read);
- assert (memcmp(buf, verify_buf.data(), verify_buf.size()) == 0);
- assert (verify_error.Success() == error.Success());
- return cache_bytes_read;
- }
- return 0;
-#else // !defined(VERIFY_MEMORY_READS)
- // Memory caching is enabled, without debug verification
-
- return m_memory_cache.Read (addr, buf, size, error);
-#endif // defined (VERIFY_MEMORY_READS)
- }
- else
- {
- // Memory caching is disabled
-
- return ReadMemoryFromInferior (addr, buf, size, error);
- }
-}
-
-size_t
-Process::ReadCStringFromMemory (addr_t addr, std::string &out_str, Error &error)
-{
- char buf[256];
- out_str.clear();
- addr_t curr_addr = addr;
- while (true)
- {
- size_t length = ReadCStringFromMemory (curr_addr, buf, sizeof(buf), error);
- if (length == 0)
- break;
- out_str.append(buf, length);
- // If we got "length - 1" bytes, we didn't get the whole C string, we
- // need to read some more characters
- if (length == sizeof(buf) - 1)
- curr_addr += length;
- else
- break;
- }
- return out_str.size();
+ m_exit_string.assign("No valid Process");
+ return eEventActionExit;
}
-size_t
-Process::ReadStringFromMemory (addr_t addr, char *dst, size_t max_bytes, Error &error,
- size_t type_width)
-{
- size_t total_bytes_read = 0;
- if (dst && max_bytes && type_width && max_bytes >= type_width)
- {
- // Ensure a null terminator independent of the number of bytes that is read.
- memset (dst, 0, max_bytes);
- size_t bytes_left = max_bytes - type_width;
-
- const char terminator[4] = {'\0', '\0', '\0', '\0'};
- assert(sizeof(terminator) >= type_width &&
- "Attempting to validate a string with more than 4 bytes per character!");
-
- addr_t curr_addr = addr;
- const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
- char *curr_dst = dst;
-
- error.Clear();
- while (bytes_left > 0 && error.Success())
- {
- addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size);
- addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
- size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error);
-
- if (bytes_read == 0)
- break;
-
- // Search for a null terminator of correct size and alignment in bytes_read
- size_t aligned_start = total_bytes_read - total_bytes_read % type_width;
- for (size_t i = aligned_start; i + type_width <= total_bytes_read + bytes_read; i += type_width)
- if (::memcmp(&dst[i], terminator, type_width) == 0)
- {
- error.Clear();
- return i;
- }
-
- total_bytes_read += bytes_read;
- curr_dst += bytes_read;
- curr_addr += bytes_read;
- bytes_left -= bytes_read;
- }
- }
- else
- {
- if (max_bytes)
- error.SetErrorString("invalid arguments");
- }
- return total_bytes_read;
+Process::NextEventAction::EventActionResult
+Process::AttachCompletionHandler::HandleBeingInterrupted() {
+ return eEventActionSuccess;
}
-// Deprecated in favor of ReadStringFromMemory which has wchar support and correct code to find
-// null terminators.
-size_t
-Process::ReadCStringFromMemory (addr_t addr, char *dst, size_t dst_max_len, Error &result_error)
-{
- size_t total_cstr_len = 0;
- if (dst && dst_max_len)
- {
- result_error.Clear();
- // NULL out everything just to be safe
- memset (dst, 0, dst_max_len);
- Error error;
- addr_t curr_addr = addr;
- const size_t cache_line_size = m_memory_cache.GetMemoryCacheLineSize();
- size_t bytes_left = dst_max_len - 1;
- char *curr_dst = dst;
-
- while (bytes_left > 0)
- {
- addr_t cache_line_bytes_left = cache_line_size - (curr_addr % cache_line_size);
- addr_t bytes_to_read = std::min<addr_t>(bytes_left, cache_line_bytes_left);
- size_t bytes_read = ReadMemory (curr_addr, curr_dst, bytes_to_read, error);
-
- if (bytes_read == 0)
- {
- result_error = error;
- dst[total_cstr_len] = '\0';
- break;
- }
- const size_t len = strlen(curr_dst);
-
- total_cstr_len += len;
-
- if (len < bytes_to_read)
- break;
-
- curr_dst += bytes_read;
- curr_addr += bytes_read;
- bytes_left -= bytes_read;
- }
- }
- else
- {
- if (dst == nullptr)
- result_error.SetErrorString("invalid arguments");
- else
- result_error.Clear();
- }
- return total_cstr_len;
+const char *Process::AttachCompletionHandler::GetExitString() {
+ return m_exit_string.c_str();
}
-size_t
-Process::ReadMemoryFromInferior (addr_t addr, void *buf, size_t size, Error &error)
-{
- if (buf == nullptr || size == 0)
- return 0;
+ListenerSP ProcessAttachInfo::GetListenerForProcess(Debugger &debugger) {
+ if (m_listener_sp)
+ return m_listener_sp;
+ else
+ return debugger.GetListener();
+}
+
+Error Process::Attach(ProcessAttachInfo &attach_info) {
+ m_abi_sp.reset();
+ m_process_input_reader.reset();
+ m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
+ m_system_runtime_ap.reset();
+ m_os_ap.reset();
+ m_stop_info_override_callback = nullptr;
+
+ lldb::pid_t attach_pid = attach_info.GetProcessID();
+ Error error;
+ if (attach_pid == LLDB_INVALID_PROCESS_ID) {
+ char process_name[PATH_MAX];
+
+ if (attach_info.GetExecutableFile().GetPath(process_name,
+ sizeof(process_name))) {
+ const bool wait_for_launch = attach_info.GetWaitForLaunch();
+
+ if (wait_for_launch) {
+ error = WillAttachToProcessWithName(process_name, wait_for_launch);
+ if (error.Success()) {
+ if (m_public_run_lock.TrySetRunning()) {
+ m_should_detach = true;
+ const bool restarted = false;
+ SetPublicState(eStateAttaching, restarted);
+ // Now attach using these arguments.
+ error = DoAttachToProcessWithName(process_name, attach_info);
+ } else {
+ // This shouldn't happen
+ error.SetErrorString("failed to acquire process run lock");
+ }
+
+ if (error.Fail()) {
+ if (GetID() != LLDB_INVALID_PROCESS_ID) {
+ SetID(LLDB_INVALID_PROCESS_ID);
+ if (error.AsCString() == nullptr)
+ error.SetErrorString("attach failed");
+
+ SetExitStatus(-1, error.AsCString());
+ }
+ } else {
+ SetNextEventAction(new Process::AttachCompletionHandler(
+ this, attach_info.GetResumeCount()));
+ StartPrivateStateThread();
+ }
+ return error;
+ }
+ } else {
+ ProcessInstanceInfoList process_infos;
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+
+ if (platform_sp) {
+ ProcessInstanceInfoMatch match_info;
+ match_info.GetProcessInfo() = attach_info;
+ match_info.SetNameMatchType(eNameMatchEquals);
+ platform_sp->FindProcesses(match_info, process_infos);
+ const uint32_t num_matches = process_infos.GetSize();
+ if (num_matches == 1) {
+ attach_pid = process_infos.GetProcessIDAtIndex(0);
+ // Fall through and attach using the above process ID
+ } else {
+ match_info.GetProcessInfo().GetExecutableFile().GetPath(
+ process_name, sizeof(process_name));
+ if (num_matches > 1) {
+ StreamString s;
+ ProcessInstanceInfo::DumpTableHeader(s, platform_sp.get(), true,
+ false);
+ for (size_t i = 0; i < num_matches; i++) {
+ process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(
+ s, platform_sp.get(), true, false);
+ }
+ error.SetErrorStringWithFormat(
+ "more than one process named %s:\n%s", process_name,
+ s.GetData());
+ } else
+ error.SetErrorStringWithFormat(
+ "could not find a process named %s", process_name);
+ }
+ } else {
+ error.SetErrorString(
+ "invalid platform, can't find processes by name");
+ return error;
+ }
+ }
+ } else {
+ error.SetErrorString("invalid process name");
+ }
+ }
+
+ if (attach_pid != LLDB_INVALID_PROCESS_ID) {
+ error = WillAttachToProcessWithID(attach_pid);
+ if (error.Success()) {
+
+ if (m_public_run_lock.TrySetRunning()) {
+ // Now attach using these arguments.
+ m_should_detach = true;
+ const bool restarted = false;
+ SetPublicState(eStateAttaching, restarted);
+ error = DoAttachToProcessWithID(attach_pid, attach_info);
+ } else {
+ // This shouldn't happen
+ error.SetErrorString("failed to acquire process run lock");
+ }
+
+ if (error.Success()) {
+ SetNextEventAction(new Process::AttachCompletionHandler(
+ this, attach_info.GetResumeCount()));
+ StartPrivateStateThread();
+ } else {
+ if (GetID() != LLDB_INVALID_PROCESS_ID)
+ SetID(LLDB_INVALID_PROCESS_ID);
- size_t bytes_read = 0;
- uint8_t *bytes = (uint8_t *)buf;
-
- while (bytes_read < size)
- {
- const size_t curr_size = size - bytes_read;
- const size_t curr_bytes_read = DoReadMemory (addr + bytes_read,
- bytes + bytes_read,
- curr_size,
- error);
- bytes_read += curr_bytes_read;
- if (curr_bytes_read == curr_size || curr_bytes_read == 0)
- break;
+ const char *error_string = error.AsCString();
+ if (error_string == nullptr)
+ error_string = "attach failed";
+
+ SetExitStatus(-1, error_string);
+ }
+ }
+ }
+ return error;
+}
+
+void Process::CompleteAttach() {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS |
+ LIBLLDB_LOG_TARGET));
+ if (log)
+ log->Printf("Process::%s()", __FUNCTION__);
+
+ // Let the process subclass figure out at much as it can about the process
+ // before we go looking for a dynamic loader plug-in.
+ ArchSpec process_arch;
+ DidAttach(process_arch);
+
+ if (process_arch.IsValid()) {
+ GetTarget().SetArchitecture(process_arch);
+ if (log) {
+ const char *triple_str = process_arch.GetTriple().getTriple().c_str();
+ log->Printf("Process::%s replacing process architecture with DidAttach() "
+ "architecture: %s",
+ __FUNCTION__, triple_str ? triple_str : "<null>");
+ }
+ }
+
+ // We just attached. If we have a platform, ask it for the process
+ // architecture, and if it isn't
+ // the same as the one we've already set, switch architectures.
+ PlatformSP platform_sp(GetTarget().GetPlatform());
+ assert(platform_sp);
+ if (platform_sp) {
+ const ArchSpec &target_arch = GetTarget().GetArchitecture();
+ if (target_arch.IsValid() &&
+ !platform_sp->IsCompatibleArchitecture(target_arch, false, nullptr)) {
+ ArchSpec platform_arch;
+ platform_sp =
+ platform_sp->GetPlatformForArchitecture(target_arch, &platform_arch);
+ if (platform_sp) {
+ GetTarget().SetPlatform(platform_sp);
+ GetTarget().SetArchitecture(platform_arch);
+ if (log)
+ log->Printf("Process::%s switching platform to %s and architecture "
+ "to %s based on info from attach",
+ __FUNCTION__, platform_sp->GetName().AsCString(""),
+ platform_arch.GetTriple().getTriple().c_str());
+ }
+ } else if (!process_arch.IsValid()) {
+ ProcessInstanceInfo process_info;
+ GetProcessInfo(process_info);
+ const ArchSpec &process_arch = process_info.GetArchitecture();
+ if (process_arch.IsValid() &&
+ !GetTarget().GetArchitecture().IsExactMatch(process_arch)) {
+ GetTarget().SetArchitecture(process_arch);
+ if (log)
+ log->Printf("Process::%s switching architecture to %s based on info "
+ "the platform retrieved for pid %" PRIu64,
+ __FUNCTION__,
+ process_arch.GetTriple().getTriple().c_str(), GetID());
+ }
+ }
+ }
+
+ // We have completed the attach, now it is time to find the dynamic loader
+ // plug-in
+ DynamicLoader *dyld = GetDynamicLoader();
+ if (dyld) {
+ dyld->DidAttach();
+ if (log) {
+ ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
+ log->Printf("Process::%s after DynamicLoader::DidAttach(), target "
+ "executable is %s (using %s plugin)",
+ __FUNCTION__,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str()
+ : "<none>",
+ dyld->GetPluginName().AsCString("<unnamed>"));
+ }
+ }
+
+ GetJITLoaders().DidAttach();
+
+ SystemRuntime *system_runtime = GetSystemRuntime();
+ if (system_runtime) {
+ system_runtime->DidAttach();
+ if (log) {
+ ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
+ log->Printf("Process::%s after SystemRuntime::DidAttach(), target "
+ "executable is %s (using %s plugin)",
+ __FUNCTION__,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str()
+ : "<none>",
+ system_runtime->GetPluginName().AsCString("<unnamed>"));
+ }
+ }
+
+ m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
+ // Figure out which one is the executable, and set that in our target:
+ const ModuleList &target_modules = GetTarget().GetImages();
+ std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
+ size_t num_modules = target_modules.GetSize();
+ ModuleSP new_executable_module_sp;
+
+ for (size_t i = 0; i < num_modules; i++) {
+ ModuleSP module_sp(target_modules.GetModuleAtIndexUnlocked(i));
+ if (module_sp && module_sp->IsExecutable()) {
+ if (GetTarget().GetExecutableModulePointer() != module_sp.get())
+ new_executable_module_sp = module_sp;
+ break;
+ }
+ }
+ if (new_executable_module_sp) {
+ GetTarget().SetExecutableModule(new_executable_module_sp, false);
+ if (log) {
+ ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
+ log->Printf(
+ "Process::%s after looping through modules, target executable is %s",
+ __FUNCTION__,
+ exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str()
+ : "<none>");
+ }
+ }
+
+ m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback();
+}
+
+Error Process::ConnectRemote(Stream *strm, const char *remote_url) {
+ m_abi_sp.reset();
+ m_process_input_reader.reset();
+
+ // Find the process and its architecture. Make sure it matches the
+ // architecture
+ // of the current Target, and if not adjust it.
+
+ Error error(DoConnectRemote(strm, remote_url));
+ if (error.Success()) {
+ if (GetID() != LLDB_INVALID_PROCESS_ID) {
+ EventSP event_sp;
+ StateType state =
+ WaitForProcessStopPrivate(std::chrono::microseconds(0), event_sp);
+
+ if (state == eStateStopped || state == eStateCrashed) {
+ // If we attached and actually have a process on the other end, then
+ // this ended up being the equivalent of an attach.
+ CompleteAttach();
+
+ // This delays passing the stopped event to listeners till
+ // CompleteAttach gets a chance to complete...
+ HandlePrivateEvent(event_sp);
+ }
}
- // Replace any software breakpoint opcodes that fall into this range back
- // into "buf" before we return
- if (bytes_read > 0)
- RemoveBreakpointOpcodesFromBuffer (addr, bytes_read, (uint8_t *)buf);
- return bytes_read;
-}
-
-uint64_t
-Process::ReadUnsignedIntegerFromMemory(lldb::addr_t vm_addr, size_t integer_byte_size, uint64_t fail_value,
- Error &error)
-{
- Scalar scalar;
- if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, false, scalar, error))
- return scalar.ULongLong(fail_value);
- return fail_value;
-}
-
-int64_t
-Process::ReadSignedIntegerFromMemory(lldb::addr_t vm_addr, size_t integer_byte_size, int64_t fail_value, Error &error)
-{
- Scalar scalar;
- if (ReadScalarIntegerFromMemory(vm_addr, integer_byte_size, true, scalar, error))
- return scalar.SLongLong(fail_value);
- return fail_value;
-}
-
-addr_t
-Process::ReadPointerFromMemory (lldb::addr_t vm_addr, Error &error)
-{
- Scalar scalar;
- if (ReadScalarIntegerFromMemory(vm_addr, GetAddressByteSize(), false, scalar, error))
- return scalar.ULongLong(LLDB_INVALID_ADDRESS);
- return LLDB_INVALID_ADDRESS;
-}
-
-bool
-Process::WritePointerToMemory (lldb::addr_t vm_addr,
- lldb::addr_t ptr_value,
- Error &error)
-{
- Scalar scalar;
- const uint32_t addr_byte_size = GetAddressByteSize();
- if (addr_byte_size <= 4)
- scalar = (uint32_t)ptr_value;
+ if (PrivateStateThreadIsValid())
+ ResumePrivateStateThread();
else
- scalar = ptr_value;
- return WriteScalarToMemory(vm_addr, scalar, addr_byte_size, error) == addr_byte_size;
-}
-
-size_t
-Process::WriteMemoryPrivate (addr_t addr, const void *buf, size_t size, Error &error)
-{
- size_t bytes_written = 0;
- const uint8_t *bytes = (const uint8_t *)buf;
-
- while (bytes_written < size)
- {
- const size_t curr_size = size - bytes_written;
- const size_t curr_bytes_written = DoWriteMemory (addr + bytes_written,
- bytes + bytes_written,
- curr_size,
- error);
- bytes_written += curr_bytes_written;
- if (curr_bytes_written == curr_size || curr_bytes_written == 0)
- break;
- }
- return bytes_written;
-}
-
-size_t
-Process::WriteMemory (addr_t addr, const void *buf, size_t size, Error &error)
-{
-#if defined (ENABLE_MEMORY_CACHING)
- m_memory_cache.Flush (addr, size);
-#endif
-
- if (buf == nullptr || size == 0)
- return 0;
+ StartPrivateStateThread();
+ }
+ return error;
+}
+
+Error Process::PrivateResume() {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS |
+ LIBLLDB_LOG_STEP));
+ if (log)
+ log->Printf("Process::PrivateResume() m_stop_id = %u, public state: %s "
+ "private state: %s",
+ m_mod_id.GetStopID(), StateAsCString(m_public_state.GetValue()),
+ StateAsCString(m_private_state.GetValue()));
+
+ Error error(WillResume());
+ // Tell the process it is about to resume before the thread list
+ if (error.Success()) {
+ // Now let the thread list know we are about to resume so it
+ // can let all of our threads know that they are about to be
+ // resumed. Threads will each be called with
+ // Thread::WillResume(StateType) where StateType contains the state
+ // that they are supposed to have when the process is resumed
+ // (suspended/running/stepping). Threads should also check
+ // their resume signal in lldb::Thread::GetResumeSignal()
+ // to see if they are supposed to start back up with a signal.
+ if (m_thread_list.WillResume()) {
+ // Last thing, do the PreResumeActions.
+ if (!RunPreResumeActions()) {
+ error.SetErrorStringWithFormat(
+ "Process::PrivateResume PreResumeActions failed, not resuming.");
+ } else {
+ m_mod_id.BumpResumeID();
+ error = DoResume();
+ if (error.Success()) {
+ DidResume();
+ m_thread_list.DidResume();
+ if (log)
+ log->Printf("Process thinks the process has resumed.");
+ }
+ }
+ } else {
+ // Somebody wanted to run without running (e.g. we were faking a step from
+ // one frame of a set of inlined
+ // frames that share the same PC to another.) So generate a continue & a
+ // stopped event,
+ // and let the world handle them.
+ if (log)
+ log->Printf(
+ "Process::PrivateResume() asked to simulate a start & stop.");
+
+ SetPrivateState(eStateRunning);
+ SetPrivateState(eStateStopped);
+ }
+ } else if (log)
+ log->Printf("Process::PrivateResume() got an error \"%s\".",
+ error.AsCString("<unknown error>"));
+ return error;
+}
+
+Error Process::Halt(bool clear_thread_plans, bool use_run_lock) {
+ if (!StateIsRunningState(m_public_state.GetValue()))
+ return Error("Process is not running.");
+
+ // Don't clear the m_clear_thread_plans_on_stop, only set it to true if
+ // in case it was already set and some thread plan logic calls halt on its
+ // own.
+ m_clear_thread_plans_on_stop |= clear_thread_plans;
+
+ ListenerSP halt_listener_sp(
+ Listener::MakeListener("lldb.process.halt_listener"));
+ HijackProcessEvents(halt_listener_sp);
+
+ EventSP event_sp;
+
+ SendAsyncInterrupt();
+
+ if (m_public_state.GetValue() == eStateAttaching) {
+ // Don't hijack and eat the eStateExited as the code that was doing
+ // the attach will be waiting for this event...
+ RestoreProcessEvents();
+ SetExitStatus(SIGKILL, "Cancelled async attach.");
+ Destroy(false);
+ return Error();
+ }
- m_mod_id.BumpMemoryID();
+ // Wait for 10 second for the process to stop.
+ StateType state =
+ WaitForProcessToStop(std::chrono::seconds(10), &event_sp, true,
+ halt_listener_sp, nullptr, use_run_lock);
+ RestoreProcessEvents();
- // We need to write any data that would go where any current software traps
- // (enabled software breakpoints) any software traps (breakpoints) that we
- // may have placed in our tasks memory.
-
- BreakpointSiteList bp_sites_in_range;
-
- if (m_breakpoint_site_list.FindInRange (addr, addr + size, bp_sites_in_range))
- {
- // No breakpoint sites overlap
- if (bp_sites_in_range.IsEmpty())
- return WriteMemoryPrivate (addr, buf, size, error);
- else
- {
- const uint8_t *ubuf = (const uint8_t *)buf;
- uint64_t bytes_written = 0;
-
- bp_sites_in_range.ForEach([this, addr, size, &bytes_written, &ubuf, &error](BreakpointSite *bp) -> void {
-
- if (error.Success())
- {
- addr_t intersect_addr;
- size_t intersect_size;
- size_t opcode_offset;
- const bool intersects = bp->IntersectsRange(addr, size, &intersect_addr, &intersect_size, &opcode_offset);
- UNUSED_IF_ASSERT_DISABLED(intersects);
- assert(intersects);
- assert(addr <= intersect_addr && intersect_addr < addr + size);
- assert(addr < intersect_addr + intersect_size && intersect_addr + intersect_size <= addr + size);
- assert(opcode_offset + intersect_size <= bp->GetByteSize());
-
- // Check for bytes before this breakpoint
- const addr_t curr_addr = addr + bytes_written;
- if (intersect_addr > curr_addr)
- {
- // There are some bytes before this breakpoint that we need to
- // just write to memory
- size_t curr_size = intersect_addr - curr_addr;
- size_t curr_bytes_written = WriteMemoryPrivate (curr_addr,
- ubuf + bytes_written,
- curr_size,
- error);
- bytes_written += curr_bytes_written;
- if (curr_bytes_written != curr_size)
- {
- // We weren't able to write all of the requested bytes, we
- // are done looping and will return the number of bytes that
- // we have written so far.
- if (error.Success())
- error.SetErrorToGenericError();
- }
- }
- // Now write any bytes that would cover up any software breakpoints
- // directly into the breakpoint opcode buffer
- ::memcpy(bp->GetSavedOpcodeBytes() + opcode_offset, ubuf + bytes_written, intersect_size);
- bytes_written += intersect_size;
- }
- });
-
- if (bytes_written < size)
- WriteMemoryPrivate (addr + bytes_written,
- ubuf + bytes_written,
- size - bytes_written,
- error);
- }
- }
- else
- {
- return WriteMemoryPrivate (addr, buf, size, error);
- }
+ if (state == eStateInvalid || !event_sp) {
+ // We timed out and didn't get a stop event...
+ return Error("Halt timed out. State = %s", StateAsCString(GetState()));
+ }
- // Write any remaining bytes after the last breakpoint if we have any left
- return 0; //bytes_written;
-}
+ BroadcastEvent(event_sp);
-size_t
-Process::WriteScalarToMemory (addr_t addr, const Scalar &scalar, size_t byte_size, Error &error)
-{
- if (byte_size == UINT32_MAX)
- byte_size = scalar.GetByteSize();
- if (byte_size > 0)
- {
- uint8_t buf[32];
- const size_t mem_size = scalar.GetAsMemoryData (buf, byte_size, GetByteOrder(), error);
- if (mem_size > 0)
- return WriteMemory(addr, buf, mem_size, error);
- else
- error.SetErrorString ("failed to get scalar as memory data");
- }
- else
- {
- error.SetErrorString ("invalid scalar value");
- }
- return 0;
+ return Error();
}
-size_t
-Process::ReadScalarIntegerFromMemory (addr_t addr,
- uint32_t byte_size,
- bool is_signed,
- Scalar &scalar,
- Error &error)
-{
- uint64_t uval = 0;
- if (byte_size == 0)
- {
- error.SetErrorString ("byte size is zero");
- }
- else if (byte_size & (byte_size - 1))
- {
- error.SetErrorStringWithFormat ("byte size %u is not a power of 2", byte_size);
- }
- else if (byte_size <= sizeof(uval))
- {
- const size_t bytes_read = ReadMemory (addr, &uval, byte_size, error);
- if (bytes_read == byte_size)
- {
- DataExtractor data (&uval, sizeof(uval), GetByteOrder(), GetAddressByteSize());
- lldb::offset_t offset = 0;
- if (byte_size <= 4)
- scalar = data.GetMaxU32 (&offset, byte_size);
- else
- scalar = data.GetMaxU64 (&offset, byte_size);
- if (is_signed)
- scalar.SignExtend(byte_size * 8);
- return bytes_read;
- }
- }
- else
- {
- error.SetErrorStringWithFormat ("byte size of %u is too large for integer scalar type", byte_size);
- }
- return 0;
-}
+Error Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp) {
+ Error error;
-#define USE_ALLOCATE_MEMORY_CACHE 1
-addr_t
-Process::AllocateMemory(size_t size, uint32_t permissions, Error &error)
-{
- if (GetPrivateState() != eStateStopped)
- return LLDB_INVALID_ADDRESS;
-
-#if defined (USE_ALLOCATE_MEMORY_CACHE)
- return m_allocated_memory_cache.AllocateMemory(size, permissions, error);
-#else
- addr_t allocated_addr = DoAllocateMemory (size, permissions, error);
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ // Check both the public & private states here. If we're hung evaluating an
+ // expression, for instance, then
+ // the public state will be stopped, but we still need to interrupt.
+ if (m_public_state.GetValue() == eStateRunning ||
+ m_private_state.GetValue() == eStateRunning) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
if (log)
- log->Printf("Process::AllocateMemory(size=%" PRIu64 ", permissions=%s) => 0x%16.16" PRIx64 " (m_stop_id = %u m_memory_id = %u)",
- (uint64_t)size,
- GetPermissionsAsCString (permissions),
- (uint64_t)allocated_addr,
- m_mod_id.GetStopID(),
- m_mod_id.GetMemoryID());
- return allocated_addr;
-#endif
-}
-
-addr_t
-Process::CallocateMemory(size_t size, uint32_t permissions, Error &error)
-{
- addr_t return_addr = AllocateMemory(size, permissions, error);
- if (error.Success())
- {
- std::string buffer(size, 0);
- WriteMemory(return_addr, buffer.c_str(), size, error);
- }
- return return_addr;
-}
-
-bool
-Process::CanJIT ()
-{
- if (m_can_jit == eCanJITDontKnow)
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- Error err;
-
- uint64_t allocated_memory = AllocateMemory(8,
- ePermissionsReadable | ePermissionsWritable | ePermissionsExecutable,
- err);
-
- if (err.Success())
- {
- m_can_jit = eCanJITYes;
- if (log)
- log->Printf ("Process::%s pid %" PRIu64 " allocation test passed, CanJIT () is true", __FUNCTION__, GetID ());
- }
- else
- {
- m_can_jit = eCanJITNo;
- if (log)
- log->Printf ("Process::%s pid %" PRIu64 " allocation test failed, CanJIT () is false: %s", __FUNCTION__, GetID (), err.AsCString ());
- }
-
- DeallocateMemory (allocated_memory);
- }
-
- return m_can_jit == eCanJITYes;
-}
+ log->Printf("Process::%s() About to stop.", __FUNCTION__);
-void
-Process::SetCanJIT (bool can_jit)
-{
- m_can_jit = (can_jit ? eCanJITYes : eCanJITNo);
-}
+ ListenerSP listener_sp(
+ Listener::MakeListener("lldb.Process.StopForDestroyOrDetach.hijack"));
+ HijackProcessEvents(listener_sp);
-void
-Process::SetCanRunCode (bool can_run_code)
-{
- SetCanJIT(can_run_code);
- m_can_interpret_function_calls = can_run_code;
-}
+ SendAsyncInterrupt();
-Error
-Process::DeallocateMemory (addr_t ptr)
-{
- Error error;
-#if defined (USE_ALLOCATE_MEMORY_CACHE)
- if (!m_allocated_memory_cache.DeallocateMemory(ptr))
- {
- error.SetErrorStringWithFormat ("deallocation of memory at 0x%" PRIx64 " failed.", (uint64_t)ptr);
- }
-#else
- error = DoDeallocateMemory (ptr);
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::DeallocateMemory(addr=0x%16.16" PRIx64 ") => err = %s (m_stop_id = %u, m_memory_id = %u)",
- ptr,
- error.AsCString("SUCCESS"),
- m_mod_id.GetStopID(),
- m_mod_id.GetMemoryID());
-#endif
- return error;
-}
+ // Consume the interrupt event.
+ StateType state = WaitForProcessToStop(std::chrono::seconds(10),
+ &exit_event_sp, true, listener_sp);
-ModuleSP
-Process::ReadModuleFromMemory (const FileSpec& file_spec,
- lldb::addr_t header_addr,
- size_t size_to_read)
-{
- Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_HOST);
- if (log)
- {
- log->Printf ("Process::ReadModuleFromMemory reading %s binary from memory", file_spec.GetPath().c_str());
- }
- ModuleSP module_sp (new Module (file_spec, ArchSpec()));
- if (module_sp)
- {
- Error error;
- ObjectFile *objfile = module_sp->GetMemoryObjectFile (shared_from_this(), header_addr, error, size_to_read);
- if (objfile)
- return module_sp;
- }
- return ModuleSP();
-}
+ RestoreProcessEvents();
-bool
-Process::GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
-{
- MemoryRegionInfo range_info;
- permissions = 0;
- Error error (GetMemoryRegionInfo (load_addr, range_info));
- if (!error.Success())
- return false;
- if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
- || range_info.GetWritable() == MemoryRegionInfo::eDontKnow
- || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
- {
- return false;
+ // If the process exited while we were waiting for it to stop, put the
+ // exited event into
+ // the shared pointer passed in and return. Our caller doesn't need to do
+ // anything else, since
+ // they don't have a process anymore...
+
+ if (state == eStateExited || m_private_state.GetValue() == eStateExited) {
+ if (log)
+ log->Printf("Process::%s() Process exited while waiting to stop.",
+ __FUNCTION__);
+ return error;
+ } else
+ exit_event_sp.reset(); // It is ok to consume any non-exit stop events
+
+ if (state != eStateStopped) {
+ if (log)
+ log->Printf("Process::%s() failed to stop, state is: %s", __FUNCTION__,
+ StateAsCString(state));
+ // If we really couldn't stop the process then we should just error out
+ // here, but if the
+ // lower levels just bobbled sending the event and we really are stopped,
+ // then continue on.
+ StateType private_state = m_private_state.GetValue();
+ if (private_state != eStateStopped) {
+ return Error("Attempt to stop the target in order to detach timed out. "
+ "State = %s",
+ StateAsCString(GetState()));
+ }
+ }
+ }
+ return error;
+}
+
+Error Process::Detach(bool keep_stopped) {
+ EventSP exit_event_sp;
+ Error error;
+ m_destroy_in_process = true;
+
+ error = WillDetach();
+
+ if (error.Success()) {
+ if (DetachRequiresHalt()) {
+ error = StopForDestroyOrDetach(exit_event_sp);
+ if (!error.Success()) {
+ m_destroy_in_process = false;
+ return error;
+ } else if (exit_event_sp) {
+ // We shouldn't need to do anything else here. There's no process left
+ // to detach from...
+ StopPrivateStateThread();
+ m_destroy_in_process = false;
+ return error;
+ }
}
- if (range_info.GetReadable() == MemoryRegionInfo::eYes)
- permissions |= lldb::ePermissionsReadable;
-
- if (range_info.GetWritable() == MemoryRegionInfo::eYes)
- permissions |= lldb::ePermissionsWritable;
-
- if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
- permissions |= lldb::ePermissionsExecutable;
-
- return true;
-}
-
-Error
-Process::EnableWatchpoint (Watchpoint *watchpoint, bool notify)
-{
- Error error;
- error.SetErrorString("watchpoints are not supported");
- return error;
-}
-
-Error
-Process::DisableWatchpoint (Watchpoint *watchpoint, bool notify)
-{
- Error error;
- error.SetErrorString("watchpoints are not supported");
- return error;
-}
-
-StateType
-Process::WaitForProcessStopPrivate(const std::chrono::microseconds &timeout, EventSP &event_sp)
-{
- StateType state;
- // Now wait for the process to launch and return control to us, and then
- // call DidLaunch:
- while (true)
- {
- event_sp.reset();
- state = WaitForStateChangedEventsPrivate (timeout, event_sp);
-
- if (StateIsStoppedState(state, false))
- break;
-
- // If state is invalid, then we timed out
- if (state == eStateInvalid)
- break;
-
- if (event_sp)
- HandlePrivateEvent (event_sp);
- }
- return state;
-}
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
-void
-Process::LoadOperatingSystemPlugin(bool flush)
-{
- if (flush)
- m_thread_list.Clear();
- m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
- if (flush)
- Flush();
-}
+ error = DoDetach(keep_stopped);
+ if (error.Success()) {
+ DidDetach();
+ StopPrivateStateThread();
+ } else {
+ return error;
+ }
+ }
+ m_destroy_in_process = false;
+
+ // If we exited when we were waiting for a process to stop, then
+ // forward the event here so we don't lose the event
+ if (exit_event_sp) {
+ // Directly broadcast our exited event because we shut down our
+ // private state thread above
+ BroadcastEvent(exit_event_sp);
+ }
+
+ // If we have been interrupted (to kill us) in the middle of running, we may
+ // not end up propagating
+ // the last events through the event system, in which case we might strand the
+ // write lock. Unlock
+ // it here so when we do to tear down the process we don't get an error
+ // destroying the lock.
+
+ m_public_run_lock.SetStopped();
+ return error;
+}
+
+Error Process::Destroy(bool force_kill) {
+
+ // Tell ourselves we are in the process of destroying the process, so that we
+ // don't do any unnecessary work
+ // that might hinder the destruction. Remember to set this back to false when
+ // we are done. That way if the attempt
+ // failed and the process stays around for some reason it won't be in a
+ // confused state.
+
+ if (force_kill)
+ m_should_detach = false;
+
+ if (GetShouldDetach()) {
+ // FIXME: This will have to be a process setting:
+ bool keep_stopped = false;
+ Detach(keep_stopped);
+ }
-Error
-Process::Launch (ProcessLaunchInfo &launch_info)
-{
- Error error;
- m_abi_sp.reset();
- m_dyld_ap.reset();
- m_jit_loaders_ap.reset();
- m_system_runtime_ap.reset();
- m_os_ap.reset();
- m_process_input_reader.reset();
- m_stop_info_override_callback = nullptr;
-
- Module *exe_module = GetTarget().GetExecutableModulePointer();
- if (exe_module)
- {
- char local_exec_file_path[PATH_MAX];
- char platform_exec_file_path[PATH_MAX];
- exe_module->GetFileSpec().GetPath(local_exec_file_path, sizeof(local_exec_file_path));
- exe_module->GetPlatformFileSpec().GetPath(platform_exec_file_path, sizeof(platform_exec_file_path));
- if (exe_module->GetFileSpec().Exists())
- {
- // Install anything that might need to be installed prior to launching.
- // For host systems, this will do nothing, but if we are connected to a
- // remote platform it will install any needed binaries
- error = GetTarget().Install(&launch_info);
- if (error.Fail())
- return error;
-
- if (PrivateStateThreadIsValid ())
- PausePrivateStateThread ();
-
- error = WillLaunch (exe_module);
- if (error.Success())
- {
- const bool restarted = false;
- SetPublicState (eStateLaunching, restarted);
- m_should_detach = false;
-
- if (m_public_run_lock.TrySetRunning())
- {
- // Now launch using these arguments.
- error = DoLaunch (exe_module, launch_info);
- }
- else
- {
- // This shouldn't happen
- error.SetErrorString("failed to acquire process run lock");
- }
+ m_destroy_in_process = true;
- if (error.Fail())
- {
- if (GetID() != LLDB_INVALID_PROCESS_ID)
- {
- SetID (LLDB_INVALID_PROCESS_ID);
- const char *error_string = error.AsCString();
- if (error_string == nullptr)
- error_string = "launch failed";
- SetExitStatus (-1, error_string);
- }
- }
- else
- {
- EventSP event_sp;
- StateType state = WaitForProcessStopPrivate(std::chrono::seconds(10), event_sp);
-
- if (state == eStateInvalid || !event_sp)
- {
- // We were able to launch the process, but we failed to
- // catch the initial stop.
- error.SetErrorString ("failed to catch stop after launch");
- SetExitStatus (0, "failed to catch stop after launch");
- Destroy(false);
- }
- else if (state == eStateStopped || state == eStateCrashed)
- {
- DidLaunch ();
-
- DynamicLoader *dyld = GetDynamicLoader ();
- if (dyld)
- dyld->DidLaunch();
-
- GetJITLoaders().DidLaunch();
-
- SystemRuntime *system_runtime = GetSystemRuntime ();
- if (system_runtime)
- system_runtime->DidLaunch();
-
- 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();
-
- // Target was stopped at entry as was intended. Need to notify the listeners
- // about it.
- if (state == eStateStopped && launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
- HandlePrivateEvent(event_sp);
- }
- else if (state == eStateExited)
- {
- // We exited while trying to launch somehow. Don't call DidLaunch as that's
- // not likely to work, and return an invalid pid.
- HandlePrivateEvent (event_sp);
- }
- }
- }
- }
- else
- {
- error.SetErrorStringWithFormat("file doesn't exist: '%s'", local_exec_file_path);
- }
+ Error error(WillDestroy());
+ if (error.Success()) {
+ EventSP exit_event_sp;
+ if (DestroyRequiresHalt()) {
+ error = StopForDestroyOrDetach(exit_event_sp);
}
- return error;
-}
-
-Error
-Process::LoadCore ()
-{
- Error error = DoLoadCore();
- if (error.Success())
- {
- ListenerSP listener_sp (Listener::MakeListener("lldb.process.load_core_listener"));
- HijackProcessEvents(listener_sp);
- if (PrivateStateThreadIsValid ())
- ResumePrivateStateThread ();
- else
- StartPrivateStateThread ();
-
- DynamicLoader *dyld = GetDynamicLoader ();
- if (dyld)
- dyld->DidAttach();
-
- GetJITLoaders().DidAttach();
-
- SystemRuntime *system_runtime = GetSystemRuntime ();
- if (system_runtime)
- system_runtime->DidAttach();
-
- m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
- // We successfully loaded a core file, now pretend we stopped so we can
- // show all of the threads in the core file and explore the crashed
- // state.
- SetPrivateState (eStateStopped);
-
- // Wait indefinitely for a stopped event since we just posted one above...
- lldb::EventSP event_sp;
- listener_sp->WaitForEvent(std::chrono::microseconds(0), event_sp);
- StateType state = ProcessEventData::GetStateFromEvent(event_sp.get());
-
- if (!StateIsStoppedState (state, false))
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::Halt() failed to stop, state is: %s", StateAsCString(state));
- error.SetErrorString ("Did not get stopped event after loading the core file.");
- }
- RestoreProcessEvents ();
+ if (m_public_state.GetValue() != eStateRunning) {
+ // Ditch all thread plans, and remove all our breakpoints: in case we have
+ // to restart the target to
+ // kill it, we don't want it hitting a breakpoint...
+ // Only do this if we've stopped, however, since if we didn't manage to
+ // halt it above, then
+ // we're not going to have much luck doing this now.
+ m_thread_list.DiscardThreadPlans();
+ DisableAllBreakpointSites();
+ }
+
+ error = DoDestroy();
+ if (error.Success()) {
+ DidDestroy();
+ StopPrivateStateThread();
+ }
+ m_stdio_communication.Disconnect();
+ m_stdio_communication.StopReadThread();
+ m_stdin_forward = false;
+
+ if (m_process_input_reader) {
+ m_process_input_reader->SetIsDone(true);
+ m_process_input_reader->Cancel();
+ m_process_input_reader.reset();
}
- return error;
-}
-
-DynamicLoader *
-Process::GetDynamicLoader ()
-{
- if (!m_dyld_ap)
- m_dyld_ap.reset(DynamicLoader::FindPlugin(this, nullptr));
- return m_dyld_ap.get();
-}
-
-const lldb::DataBufferSP
-Process::GetAuxvData()
-{
- return DataBufferSP ();
-}
-JITLoaderList &
-Process::GetJITLoaders ()
-{
- if (!m_jit_loaders_ap)
- {
- m_jit_loaders_ap.reset(new JITLoaderList());
- JITLoader::LoadPlugins(this, *m_jit_loaders_ap);
+ // If we exited when we were waiting for a process to stop, then
+ // forward the event here so we don't lose the event
+ if (exit_event_sp) {
+ // Directly broadcast our exited event because we shut down our
+ // private state thread above
+ BroadcastEvent(exit_event_sp);
}
- return *m_jit_loaders_ap;
-}
-
-SystemRuntime *
-Process::GetSystemRuntime ()
-{
- if (!m_system_runtime_ap)
- m_system_runtime_ap.reset(SystemRuntime::FindPlugin(this));
- return m_system_runtime_ap.get();
-}
-
-Process::AttachCompletionHandler::AttachCompletionHandler (Process *process, uint32_t exec_count) :
- NextEventAction (process),
- m_exec_count (exec_count)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Process::AttachCompletionHandler::%s process=%p, exec_count=%" PRIu32, __FUNCTION__, static_cast<void*>(process), exec_count);
-}
-
-Process::NextEventAction::EventActionResult
-Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-
- StateType state = ProcessEventData::GetStateFromEvent (event_sp.get());
- if (log)
- log->Printf ("Process::AttachCompletionHandler::%s called with state %s (%d)", __FUNCTION__, StateAsCString(state), static_cast<int> (state));
- switch (state)
- {
- case eStateAttaching:
- return eEventActionSuccess;
-
- case eStateRunning:
- case eStateConnected:
- return eEventActionRetry;
-
- case eStateStopped:
- case eStateCrashed:
- // During attach, prior to sending the eStateStopped event,
- // lldb_private::Process subclasses must set the new process ID.
- assert (m_process->GetID() != LLDB_INVALID_PROCESS_ID);
- // We don't want these events to be reported, so go set the ShouldReportStop here:
- m_process->GetThreadList().SetShouldReportStop (eVoteNo);
-
- if (m_exec_count > 0)
- {
- --m_exec_count;
-
- if (log)
- log->Printf ("Process::AttachCompletionHandler::%s state %s: reduced remaining exec count to %" PRIu32 ", requesting resume", __FUNCTION__, StateAsCString(state), m_exec_count);
-
- RequestResume();
- return eEventActionRetry;
- }
- else
- {
- if (log)
- log->Printf ("Process::AttachCompletionHandler::%s state %s: no more execs expected to start, continuing with attach", __FUNCTION__, StateAsCString(state));
-
- m_process->CompleteAttach ();
- return eEventActionSuccess;
- }
- break;
-
- default:
- case eStateExited:
- case eStateInvalid:
- break;
- }
-
- m_exit_string.assign ("No valid Process");
- return eEventActionExit;
-}
-
-Process::NextEventAction::EventActionResult
-Process::AttachCompletionHandler::HandleBeingInterrupted()
-{
- return eEventActionSuccess;
-}
-
-const char *
-Process::AttachCompletionHandler::GetExitString ()
-{
- return m_exit_string.c_str();
-}
-
-ListenerSP
-ProcessAttachInfo::GetListenerForProcess (Debugger &debugger)
-{
- if (m_listener_sp)
- return m_listener_sp;
- else
- return debugger.GetListener();
-}
-
-Error
-Process::Attach (ProcessAttachInfo &attach_info)
-{
- m_abi_sp.reset();
- m_process_input_reader.reset();
- m_dyld_ap.reset();
- m_jit_loaders_ap.reset();
- m_system_runtime_ap.reset();
- m_os_ap.reset();
- m_stop_info_override_callback = nullptr;
-
- lldb::pid_t attach_pid = attach_info.GetProcessID();
- Error error;
- if (attach_pid == LLDB_INVALID_PROCESS_ID)
- {
- char process_name[PATH_MAX];
-
- if (attach_info.GetExecutableFile().GetPath (process_name, sizeof(process_name)))
- {
- const bool wait_for_launch = attach_info.GetWaitForLaunch();
-
- if (wait_for_launch)
- {
- error = WillAttachToProcessWithName(process_name, wait_for_launch);
- if (error.Success())
- {
- if (m_public_run_lock.TrySetRunning())
- {
- m_should_detach = true;
- const bool restarted = false;
- SetPublicState (eStateAttaching, restarted);
- // Now attach using these arguments.
- error = DoAttachToProcessWithName (process_name, attach_info);
- }
- else
- {
- // This shouldn't happen
- error.SetErrorString("failed to acquire process run lock");
- }
-
- if (error.Fail())
- {
- if (GetID() != LLDB_INVALID_PROCESS_ID)
- {
- SetID (LLDB_INVALID_PROCESS_ID);
- if (error.AsCString() == nullptr)
- error.SetErrorString("attach failed");
-
- SetExitStatus(-1, error.AsCString());
- }
- }
- else
- {
- SetNextEventAction(new Process::AttachCompletionHandler(this, attach_info.GetResumeCount()));
- StartPrivateStateThread();
- }
- return error;
- }
- }
- else
- {
- ProcessInstanceInfoList process_infos;
- PlatformSP platform_sp (GetTarget().GetPlatform ());
-
- if (platform_sp)
- {
- ProcessInstanceInfoMatch match_info;
- match_info.GetProcessInfo() = attach_info;
- match_info.SetNameMatchType (eNameMatchEquals);
- platform_sp->FindProcesses (match_info, process_infos);
- const uint32_t num_matches = process_infos.GetSize();
- if (num_matches == 1)
- {
- attach_pid = process_infos.GetProcessIDAtIndex(0);
- // Fall through and attach using the above process ID
- }
- else
- {
- match_info.GetProcessInfo().GetExecutableFile().GetPath (process_name, sizeof(process_name));
- if (num_matches > 1)
- {
- StreamString s;
- ProcessInstanceInfo::DumpTableHeader (s, platform_sp.get(), true, false);
- for (size_t i = 0; i < num_matches; i++)
- {
- process_infos.GetProcessInfoAtIndex(i).DumpAsTableRow(s, platform_sp.get(), true, false);
- }
- error.SetErrorStringWithFormat ("more than one process named %s:\n%s",
- process_name,
- s.GetData());
- }
- else
- error.SetErrorStringWithFormat ("could not find a process named %s", process_name);
- }
- }
- else
- {
- error.SetErrorString ("invalid platform, can't find processes by name");
- return error;
- }
- }
- }
- else
- {
- error.SetErrorString ("invalid process name");
- }
- }
-
- if (attach_pid != LLDB_INVALID_PROCESS_ID)
- {
- error = WillAttachToProcessWithID(attach_pid);
- if (error.Success())
- {
-
- if (m_public_run_lock.TrySetRunning())
- {
- // Now attach using these arguments.
- m_should_detach = true;
- const bool restarted = false;
- SetPublicState (eStateAttaching, restarted);
- error = DoAttachToProcessWithID (attach_pid, attach_info);
- }
- else
- {
- // This shouldn't happen
- error.SetErrorString("failed to acquire process run lock");
- }
-
- if (error.Success())
- {
- SetNextEventAction(new Process::AttachCompletionHandler(this, attach_info.GetResumeCount()));
- StartPrivateStateThread();
- }
- else
- {
- if (GetID() != LLDB_INVALID_PROCESS_ID)
- SetID (LLDB_INVALID_PROCESS_ID);
-
- const char *error_string = error.AsCString();
- if (error_string == nullptr)
- error_string = "attach failed";
-
- SetExitStatus(-1, error_string);
- }
- }
- }
- return error;
-}
-
-void
-Process::CompleteAttach ()
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS | LIBLLDB_LOG_TARGET));
- if (log)
- log->Printf ("Process::%s()", __FUNCTION__);
-
- // Let the process subclass figure out at much as it can about the process
- // before we go looking for a dynamic loader plug-in.
- ArchSpec process_arch;
- DidAttach(process_arch);
-
- if (process_arch.IsValid())
- {
- GetTarget().SetArchitecture(process_arch);
- if (log)
- {
- const char *triple_str = process_arch.GetTriple().getTriple().c_str ();
- log->Printf ("Process::%s replacing process architecture with DidAttach() architecture: %s",
- __FUNCTION__,
- triple_str ? triple_str : "<null>");
- }
- }
-
- // We just attached. If we have a platform, ask it for the process architecture, and if it isn't
- // the same as the one we've already set, switch architectures.
- PlatformSP platform_sp (GetTarget().GetPlatform ());
- assert(platform_sp);
- if (platform_sp)
- {
- const ArchSpec &target_arch = GetTarget().GetArchitecture();
- if (target_arch.IsValid() && !platform_sp->IsCompatibleArchitecture(target_arch, false, nullptr))
- {
- ArchSpec platform_arch;
- platform_sp = platform_sp->GetPlatformForArchitecture (target_arch, &platform_arch);
- if (platform_sp)
- {
- GetTarget().SetPlatform (platform_sp);
- GetTarget().SetArchitecture(platform_arch);
- if (log)
- log->Printf ("Process::%s switching platform to %s and architecture to %s based on info from attach", __FUNCTION__, platform_sp->GetName().AsCString (""), platform_arch.GetTriple().getTriple().c_str ());
- }
- }
- else if (!process_arch.IsValid())
- {
- ProcessInstanceInfo process_info;
- GetProcessInfo(process_info);
- const ArchSpec &process_arch = process_info.GetArchitecture();
- if (process_arch.IsValid() && !GetTarget().GetArchitecture().IsExactMatch(process_arch))
- {
- GetTarget().SetArchitecture (process_arch);
- if (log)
- log->Printf ("Process::%s switching architecture to %s based on info the platform retrieved for pid %" PRIu64, __FUNCTION__, process_arch.GetTriple().getTriple().c_str (), GetID ());
- }
- }
- }
-
- // We have completed the attach, now it is time to find the dynamic loader
- // plug-in
- DynamicLoader *dyld = GetDynamicLoader ();
- if (dyld)
- {
- dyld->DidAttach();
- if (log)
- {
- ModuleSP exe_module_sp = GetTarget().GetExecutableModule ();
- log->Printf ("Process::%s after DynamicLoader::DidAttach(), target executable is %s (using %s plugin)",
- __FUNCTION__,
- exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>",
- dyld->GetPluginName().AsCString ("<unnamed>"));
- }
- }
-
- GetJITLoaders().DidAttach();
-
- SystemRuntime *system_runtime = GetSystemRuntime ();
- if (system_runtime)
- {
- system_runtime->DidAttach();
- if (log)
- {
- ModuleSP exe_module_sp = GetTarget().GetExecutableModule ();
- log->Printf ("Process::%s after SystemRuntime::DidAttach(), target executable is %s (using %s plugin)",
- __FUNCTION__,
- exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>",
- system_runtime->GetPluginName().AsCString("<unnamed>"));
- }
- }
-
- m_os_ap.reset(OperatingSystem::FindPlugin(this, nullptr));
- // Figure out which one is the executable, and set that in our target:
- const ModuleList &target_modules = GetTarget().GetImages();
- std::lock_guard<std::recursive_mutex> guard(target_modules.GetMutex());
- size_t num_modules = target_modules.GetSize();
- ModuleSP new_executable_module_sp;
-
- for (size_t i = 0; i < num_modules; i++)
- {
- ModuleSP module_sp (target_modules.GetModuleAtIndexUnlocked (i));
- if (module_sp && module_sp->IsExecutable())
- {
- if (GetTarget().GetExecutableModulePointer() != module_sp.get())
- new_executable_module_sp = module_sp;
- break;
- }
- }
- if (new_executable_module_sp)
- {
- GetTarget().SetExecutableModule (new_executable_module_sp, false);
- if (log)
- {
- ModuleSP exe_module_sp = GetTarget().GetExecutableModule ();
- log->Printf ("Process::%s after looping through modules, target executable is %s",
- __FUNCTION__,
- exe_module_sp ? exe_module_sp->GetFileSpec().GetPath().c_str () : "<none>");
- }
- }
-
- m_stop_info_override_callback = process_arch.GetStopInfoOverrideCallback();
-}
-
-Error
-Process::ConnectRemote (Stream *strm, const char *remote_url)
-{
- m_abi_sp.reset();
- m_process_input_reader.reset();
-
- // Find the process and its architecture. Make sure it matches the architecture
- // of the current Target, and if not adjust it.
-
- Error error (DoConnectRemote (strm, remote_url));
- if (error.Success())
- {
- if (GetID() != LLDB_INVALID_PROCESS_ID)
- {
- EventSP event_sp;
- StateType state = WaitForProcessStopPrivate(std::chrono::microseconds(0), event_sp);
-
- if (state == eStateStopped || state == eStateCrashed)
- {
- // If we attached and actually have a process on the other end, then
- // this ended up being the equivalent of an attach.
- CompleteAttach ();
-
- // This delays passing the stopped event to listeners till
- // CompleteAttach gets a chance to complete...
- HandlePrivateEvent (event_sp);
- }
- }
-
- if (PrivateStateThreadIsValid ())
- ResumePrivateStateThread ();
- else
- StartPrivateStateThread ();
- }
- return error;
-}
-
-Error
-Process::PrivateResume ()
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS|LIBLLDB_LOG_STEP));
- if (log)
- log->Printf("Process::PrivateResume() m_stop_id = %u, public state: %s private state: %s",
- m_mod_id.GetStopID(),
- StateAsCString(m_public_state.GetValue()),
- StateAsCString(m_private_state.GetValue()));
-
- Error error (WillResume());
- // Tell the process it is about to resume before the thread list
- if (error.Success())
- {
- // Now let the thread list know we are about to resume so it
- // can let all of our threads know that they are about to be
- // resumed. Threads will each be called with
- // Thread::WillResume(StateType) where StateType contains the state
- // that they are supposed to have when the process is resumed
- // (suspended/running/stepping). Threads should also check
- // their resume signal in lldb::Thread::GetResumeSignal()
- // to see if they are supposed to start back up with a signal.
- if (m_thread_list.WillResume())
- {
- // Last thing, do the PreResumeActions.
- if (!RunPreResumeActions())
- {
- error.SetErrorStringWithFormat ("Process::PrivateResume PreResumeActions failed, not resuming.");
- }
- else
- {
- m_mod_id.BumpResumeID();
- error = DoResume();
- if (error.Success())
- {
- DidResume();
- m_thread_list.DidResume();
- if (log)
- log->Printf ("Process thinks the process has resumed.");
- }
- }
- }
- else
- {
- // Somebody wanted to run without running (e.g. we were faking a step from one frame of a set of inlined
- // frames that share the same PC to another.) So generate a continue & a stopped event,
- // and let the world handle them.
- if (log)
- log->Printf ("Process::PrivateResume() asked to simulate a start & stop.");
-
- SetPrivateState(eStateRunning);
- SetPrivateState(eStateStopped);
- }
- }
- else if (log)
- log->Printf ("Process::PrivateResume() got an error \"%s\".", error.AsCString("<unknown error>"));
- return error;
-}
-
-Error
-Process::Halt (bool clear_thread_plans, bool use_run_lock)
-{
- if (! StateIsRunningState(m_public_state.GetValue()))
- return Error("Process is not running.");
-
- // Don't clear the m_clear_thread_plans_on_stop, only set it to true if
- // in case it was already set and some thread plan logic calls halt on its
- // own.
- m_clear_thread_plans_on_stop |= clear_thread_plans;
-
- ListenerSP halt_listener_sp (Listener::MakeListener("lldb.process.halt_listener"));
- HijackProcessEvents(halt_listener_sp);
-
- EventSP event_sp;
-
- SendAsyncInterrupt();
-
- if (m_public_state.GetValue() == eStateAttaching)
- {
- // Don't hijack and eat the eStateExited as the code that was doing
- // the attach will be waiting for this event...
- RestoreProcessEvents();
- SetExitStatus(SIGKILL, "Cancelled async attach.");
- Destroy (false);
- return Error();
- }
-
- // Wait for 10 second for the process to stop.
- StateType state =
- WaitForProcessToStop(std::chrono::seconds(10), &event_sp, true, halt_listener_sp, nullptr, use_run_lock);
- RestoreProcessEvents();
-
- if (state == eStateInvalid || ! event_sp)
- {
- // We timed out and didn't get a stop event...
- return Error("Halt timed out. State = %s", StateAsCString(GetState()));
- }
-
- BroadcastEvent(event_sp);
-
- return Error();
-}
-
-Error
-Process::StopForDestroyOrDetach(lldb::EventSP &exit_event_sp)
-{
- Error error;
-
- // Check both the public & private states here. If we're hung evaluating an expression, for instance, then
- // the public state will be stopped, but we still need to interrupt.
- if (m_public_state.GetValue() == eStateRunning || m_private_state.GetValue() == eStateRunning)
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::%s() About to stop.", __FUNCTION__);
-
- ListenerSP listener_sp (Listener::MakeListener("lldb.Process.StopForDestroyOrDetach.hijack"));
- HijackProcessEvents(listener_sp);
-
- SendAsyncInterrupt();
-
- // Consume the interrupt event.
- StateType state = WaitForProcessToStop(std::chrono::seconds(10), &exit_event_sp, true, listener_sp);
-
- RestoreProcessEvents();
-
- // If the process exited while we were waiting for it to stop, put the exited event into
- // the shared pointer passed in and return. Our caller doesn't need to do anything else, since
- // they don't have a process anymore...
-
- if (state == eStateExited || m_private_state.GetValue() == eStateExited)
- {
- if (log)
- log->Printf("Process::%s() Process exited while waiting to stop.", __FUNCTION__);
- return error;
- }
- else
- exit_event_sp.reset(); // It is ok to consume any non-exit stop events
-
- if (state != eStateStopped)
- {
- if (log)
- log->Printf("Process::%s() failed to stop, state is: %s", __FUNCTION__, StateAsCString(state));
- // If we really couldn't stop the process then we should just error out here, but if the
- // lower levels just bobbled sending the event and we really are stopped, then continue on.
- StateType private_state = m_private_state.GetValue();
- if (private_state != eStateStopped)
- {
- return Error("Attempt to stop the target in order to detach timed out. State = %s", StateAsCString(GetState()));
- }
- }
- }
- return error;
-}
-
-Error
-Process::Detach (bool keep_stopped)
-{
- EventSP exit_event_sp;
- Error error;
- m_destroy_in_process = true;
-
- error = WillDetach();
-
- if (error.Success())
- {
- if (DetachRequiresHalt())
- {
- error = StopForDestroyOrDetach (exit_event_sp);
- if (!error.Success())
- {
- m_destroy_in_process = false;
- return error;
- }
- else if (exit_event_sp)
- {
- // We shouldn't need to do anything else here. There's no process left to detach from...
- StopPrivateStateThread();
- m_destroy_in_process = false;
- return error;
- }
- }
-
- m_thread_list.DiscardThreadPlans();
- DisableAllBreakpointSites();
-
- error = DoDetach(keep_stopped);
- if (error.Success())
- {
- DidDetach();
- StopPrivateStateThread();
- }
- else
- {
- return error;
- }
- }
- m_destroy_in_process = false;
-
- // If we exited when we were waiting for a process to stop, then
- // forward the event here so we don't lose the event
- if (exit_event_sp)
- {
- // Directly broadcast our exited event because we shut down our
- // private state thread above
- BroadcastEvent(exit_event_sp);
- }
-
- // If we have been interrupted (to kill us) in the middle of running, we may not end up propagating
- // the last events through the event system, in which case we might strand the write lock. Unlock
- // it here so when we do to tear down the process we don't get an error destroying the lock.
-
- m_public_run_lock.SetStopped();
- return error;
-}
-
-Error
-Process::Destroy (bool force_kill)
-{
-
- // Tell ourselves we are in the process of destroying the process, so that we don't do any unnecessary work
- // that might hinder the destruction. Remember to set this back to false when we are done. That way if the attempt
- // failed and the process stays around for some reason it won't be in a confused state.
-
- if (force_kill)
- m_should_detach = false;
-
- if (GetShouldDetach())
- {
- // FIXME: This will have to be a process setting:
- bool keep_stopped = false;
- Detach(keep_stopped);
- }
-
- m_destroy_in_process = true;
-
- Error error (WillDestroy());
- if (error.Success())
- {
- EventSP exit_event_sp;
- if (DestroyRequiresHalt())
- {
- error = StopForDestroyOrDetach(exit_event_sp);
- }
-
- if (m_public_state.GetValue() != eStateRunning)
- {
- // Ditch all thread plans, and remove all our breakpoints: in case we have to restart the target to
- // kill it, we don't want it hitting a breakpoint...
- // Only do this if we've stopped, however, since if we didn't manage to halt it above, then
- // we're not going to have much luck doing this now.
- m_thread_list.DiscardThreadPlans();
- DisableAllBreakpointSites();
- }
-
- error = DoDestroy();
- if (error.Success())
- {
- DidDestroy();
- StopPrivateStateThread();
- }
- m_stdio_communication.Disconnect();
- m_stdio_communication.StopReadThread();
- m_stdin_forward = false;
-
- if (m_process_input_reader)
- {
- m_process_input_reader->SetIsDone(true);
- m_process_input_reader->Cancel();
- m_process_input_reader.reset();
- }
-
- // If we exited when we were waiting for a process to stop, then
- // forward the event here so we don't lose the event
- if (exit_event_sp)
- {
- // Directly broadcast our exited event because we shut down our
- // private state thread above
- BroadcastEvent(exit_event_sp);
- }
-
- // If we have been interrupted (to kill us) in the middle of running, we may not end up propagating
- // the last events through the event system, in which case we might strand the write lock. Unlock
- // it here so when we do to tear down the process we don't get an error destroying the lock.
- m_public_run_lock.SetStopped();
- }
-
- m_destroy_in_process = false;
-
- return error;
-}
-
-Error
-Process::Signal (int signal)
-{
- Error error (WillSignal());
- if (error.Success())
- {
- error = DoSignal(signal);
- if (error.Success())
- DidSignal();
- }
- return error;
-}
-
-void
-Process::SetUnixSignals(UnixSignalsSP &&signals_sp)
-{
- assert (signals_sp && "null signals_sp");
- m_unix_signals_sp = signals_sp;
-}
-
-const lldb::UnixSignalsSP &
-Process::GetUnixSignals ()
-{
- assert (m_unix_signals_sp && "null m_unix_signals_sp");
- return m_unix_signals_sp;
-}
-
-lldb::ByteOrder
-Process::GetByteOrder () const
-{
- return GetTarget().GetArchitecture().GetByteOrder();
-}
-
-uint32_t
-Process::GetAddressByteSize () const
-{
- return GetTarget().GetArchitecture().GetAddressByteSize();
-}
-
-bool
-Process::ShouldBroadcastEvent (Event *event_ptr)
-{
- const StateType state = Process::ProcessEventData::GetStateFromEvent (event_ptr);
- bool return_value = true;
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS | LIBLLDB_LOG_PROCESS));
-
- switch (state)
- {
- case eStateDetached:
- case eStateExited:
- case eStateUnloaded:
- m_stdio_communication.SynchronizeWithReadThread();
- m_stdio_communication.Disconnect();
- m_stdio_communication.StopReadThread();
- m_stdin_forward = false;
-
- LLVM_FALLTHROUGH;
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
- // These events indicate changes in the state of the debugging session, always report them.
- return_value = true;
- break;
- case eStateInvalid:
- // We stopped for no apparent reason, don't report it.
- return_value = false;
- break;
- case eStateRunning:
- case eStateStepping:
- // If we've started the target running, we handle the cases where we
- // are already running and where there is a transition from stopped to
- // running differently.
- // running -> running: Automatically suppress extra running events
- // stopped -> running: Report except when there is one or more no votes
- // and no yes votes.
- SynchronouslyNotifyStateChanged (state);
- if (m_force_next_event_delivery)
- return_value = true;
- else
- {
- switch (m_last_broadcast_state)
- {
- case eStateRunning:
- case eStateStepping:
- // We always suppress multiple runnings with no PUBLIC stop in between.
- return_value = false;
- break;
- default:
- // TODO: make this work correctly. For now always report
- // run if we aren't running so we don't miss any running
- // events. If I run the lldb/test/thread/a.out file and
- // break at main.cpp:58, run and hit the breakpoints on
- // multiple threads, then somehow during the stepping over
- // of all breakpoints no run gets reported.
-
- // This is a transition from stop to run.
- switch (m_thread_list.ShouldReportRun (event_ptr))
- {
- case eVoteYes:
- case eVoteNoOpinion:
- return_value = true;
- break;
- case eVoteNo:
- return_value = false;
- break;
- }
- break;
- }
- }
- break;
- case eStateStopped:
- case eStateCrashed:
- case eStateSuspended:
- // We've stopped. First see if we're going to restart the target.
- // If we are going to stop, then we always broadcast the event.
- // If we aren't going to stop, let the thread plans decide if we're going to report this event.
- // If no thread has an opinion, we don't report it.
-
- m_stdio_communication.SynchronizeWithReadThread();
- RefreshStateAfterStop ();
- if (ProcessEventData::GetInterruptedFromEvent (event_ptr))
- {
- if (log)
- log->Printf ("Process::ShouldBroadcastEvent (%p) stopped due to an interrupt, state: %s",
- static_cast<void*>(event_ptr),
- StateAsCString(state));
- // Even though we know we are going to stop, we should let the threads have a look at the stop,
- // so they can properly set their state.
- m_thread_list.ShouldStop (event_ptr);
- return_value = true;
- }
- else
- {
- bool was_restarted = ProcessEventData::GetRestartedFromEvent (event_ptr);
- bool should_resume = false;
-
- // It makes no sense to ask "ShouldStop" if we've already been restarted...
- // Asking the thread list is also not likely to go well, since we are running again.
- // So in that case just report the event.
-
- if (!was_restarted)
- should_resume = !m_thread_list.ShouldStop(event_ptr);
-
- if (was_restarted || should_resume || m_resume_requested)
- {
- Vote stop_vote = m_thread_list.ShouldReportStop (event_ptr);
- if (log)
- log->Printf ("Process::ShouldBroadcastEvent: should_resume: %i state: %s was_restarted: %i stop_vote: %d.",
- should_resume, StateAsCString(state),
- was_restarted, stop_vote);
-
- switch (stop_vote)
- {
- case eVoteYes:
- return_value = true;
- break;
- case eVoteNoOpinion:
- case eVoteNo:
- return_value = false;
- break;
- }
-
- if (!was_restarted)
- {
- if (log)
- log->Printf ("Process::ShouldBroadcastEvent (%p) Restarting process from state: %s",
- static_cast<void*>(event_ptr),
- StateAsCString(state));
- ProcessEventData::SetRestartedInEvent(event_ptr, true);
- PrivateResume ();
- }
- }
- else
- {
- return_value = true;
- SynchronouslyNotifyStateChanged (state);
- }
- }
- break;
- }
-
- // Forcing the next event delivery is a one shot deal. So reset it here.
- m_force_next_event_delivery = false;
-
- // We do some coalescing of events (for instance two consecutive running events get coalesced.)
- // But we only coalesce against events we actually broadcast. So we use m_last_broadcast_state
- // to track that. NB - you can't use "m_public_state.GetValue()" for that purpose, as was originally done,
- // because the PublicState reflects the last event pulled off the queue, and there may be several
- // events stacked up on the queue unserviced. So the PublicState may not reflect the last broadcasted event
- // yet. m_last_broadcast_state gets updated here.
-
- if (return_value)
- m_last_broadcast_state = state;
-
- if (log)
- log->Printf ("Process::ShouldBroadcastEvent (%p) => new state: %s, last broadcast state: %s - %s",
- static_cast<void*>(event_ptr), StateAsCString(state),
- StateAsCString(m_last_broadcast_state),
- return_value ? "YES" : "NO");
- return return_value;
-}
-
-bool
-Process::StartPrivateStateThread (bool is_secondary_thread)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
-
- bool already_running = PrivateStateThreadIsValid ();
- if (log)
- log->Printf ("Process::%s()%s ", __FUNCTION__, already_running ? " already running" : " starting private state thread");
-
- if (!is_secondary_thread && already_running)
- return true;
-
- // Create a thread that watches our internal state and controls which
- // events make it to clients (into the DCProcess event queue).
- char thread_name[1024];
-
- if (HostInfo::GetMaxThreadNameLength() <= 30)
- {
- // On platforms with abbreviated thread name lengths, choose thread names that fit within the limit.
- if (already_running)
- snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
- else
- snprintf(thread_name, sizeof(thread_name), "intern-state");
- }
- else
- {
- if (already_running)
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state-override(pid=%" PRIu64 ")>", GetID());
- else
- snprintf(thread_name, sizeof(thread_name), "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
- }
-
- // Create the private state thread, and start it running.
- PrivateStateThreadArgs *args_ptr = new PrivateStateThreadArgs(this, is_secondary_thread);
- m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, (void *) args_ptr, nullptr, 8 * 1024 * 1024);
- if (m_private_state_thread.IsJoinable())
- {
- ResumePrivateStateThread();
- return true;
- }
- else
- return false;
-}
-
-void
-Process::PausePrivateStateThread ()
-{
- ControlPrivateStateThread (eBroadcastInternalStateControlPause);
-}
-
-void
-Process::ResumePrivateStateThread ()
-{
- ControlPrivateStateThread (eBroadcastInternalStateControlResume);
-}
-
-void
-Process::StopPrivateStateThread ()
-{
- if (m_private_state_thread.IsJoinable ())
- ControlPrivateStateThread (eBroadcastInternalStateControlStop);
- else
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Went to stop the private state thread, but it was already invalid.");
- }
-}
-
-void
-Process::ControlPrivateStateThread (uint32_t signal)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
-
- assert (signal == eBroadcastInternalStateControlStop ||
- signal == eBroadcastInternalStateControlPause ||
- signal == eBroadcastInternalStateControlResume);
-
- if (log)
- log->Printf ("Process::%s (signal = %d)", __FUNCTION__, signal);
-
- // Signal the private state thread
- if (m_private_state_thread.IsJoinable())
- {
- // Broadcast the event.
- // It is important to do this outside of the if below, because
- // it's possible that the thread state is invalid but that the
- // thread is waiting on a control event instead of simply being
- // on its way out (this should not happen, but it apparently can).
- if (log)
- log->Printf ("Sending control event of type: %d.", signal);
- std::shared_ptr<EventDataReceipt> event_receipt_sp(new EventDataReceipt());
- m_private_state_control_broadcaster.BroadcastEvent(signal, event_receipt_sp);
-
- // Wait for the event receipt or for the private state thread to exit
- bool receipt_received = false;
- if (PrivateStateThreadIsValid())
- {
- while (!receipt_received)
- {
- bool timed_out = false;
- // Check for a receipt for 2 seconds and then check if the private state
- // thread is still around.
- receipt_received = event_receipt_sp->WaitForEventReceived(std::chrono::seconds(2), &timed_out);
- if (!receipt_received)
- {
- // Check if the private state thread is still around. If it isn't then we are done waiting
- if (!PrivateStateThreadIsValid())
- break; // Private state thread exited or is exiting, we are done
- }
- }
- }
-
- if (signal == eBroadcastInternalStateControlStop)
- {
- thread_result_t result = NULL;
- m_private_state_thread.Join(&result);
- m_private_state_thread.Reset();
- }
- }
- else
- {
- if (log)
- log->Printf("Private state thread already dead, no need to signal it to stop.");
- }
-}
-
-void
-Process::SendAsyncInterrupt ()
-{
- if (PrivateStateThreadIsValid())
- m_private_state_broadcaster.BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
- else
- BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
-}
-
-void
-Process::HandlePrivateEvent (EventSP &event_sp)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- m_resume_requested = false;
-
- const StateType new_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
-
- // First check to see if anybody wants a shot at this event:
- if (m_next_event_action_ap)
- {
- NextEventAction::EventActionResult action_result = m_next_event_action_ap->PerformAction(event_sp);
- if (log)
- log->Printf ("Ran next event action, result was %d.", action_result);
-
- switch (action_result)
- {
- case NextEventAction::eEventActionSuccess:
- SetNextEventAction(nullptr);
- break;
-
- case NextEventAction::eEventActionRetry:
- break;
-
- case NextEventAction::eEventActionExit:
- // Handle Exiting Here. If we already got an exited event,
- // we should just propagate it. Otherwise, swallow this event,
- // and set our state to exit so the next event will kill us.
- if (new_state != eStateExited)
- {
- // FIXME: should cons up an exited event, and discard this one.
- SetExitStatus(0, m_next_event_action_ap->GetExitString());
- SetNextEventAction(nullptr);
- return;
- }
- SetNextEventAction(nullptr);
- break;
- }
- }
-
- // See if we should broadcast this state to external clients?
- const bool should_broadcast = ShouldBroadcastEvent (event_sp.get());
-
- if (should_broadcast)
- {
- const bool is_hijacked = IsHijackedForEvent(eBroadcastBitStateChanged);
- if (log)
- {
- log->Printf ("Process::%s (pid = %" PRIu64 ") broadcasting new state %s (old state %s) to %s",
- __FUNCTION__,
- GetID(),
- StateAsCString(new_state),
- StateAsCString (GetState ()),
- is_hijacked ? "hijacked" : "public");
- }
- Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
- if (StateIsRunningState (new_state))
- {
- // Only push the input handler if we aren't fowarding events,
- // as this means the curses GUI is in use...
- // Or don't push it if we are launching since it will come up stopped.
- if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching &&
- new_state != eStateAttaching)
- {
- PushProcessIOHandler ();
- m_iohandler_sync.SetValue(m_iohandler_sync.GetValue()+1, eBroadcastAlways);
- if (log)
- log->Printf("Process::%s updated m_iohandler_sync to %d", __FUNCTION__, m_iohandler_sync.GetValue());
- }
- }
- else if (StateIsStoppedState(new_state, false))
- {
- if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
- {
- // If the lldb_private::Debugger is handling the events, we don't
- // want to pop the process IOHandler here, we want to do it when
- // we receive the stopped event so we can carefully control when
- // the process IOHandler is popped because when we stop we want to
- // display some text stating how and why we stopped, then maybe some
- // process/thread/frame info, and then we want the "(lldb) " prompt
- // to show up. If we pop the process IOHandler here, then we will
- // cause the command interpreter to become the top IOHandler after
- // the process pops off and it will update its prompt right away...
- // See the Debugger.cpp file where it calls the function as
- // "process_sp->PopProcessIOHandler()" to see where I am talking about.
- // Otherwise we end up getting overlapping "(lldb) " prompts and
- // garbled output.
- //
- // If we aren't handling the events in the debugger (which is indicated
- // by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we
- // are hijacked, then we always pop the process IO handler manually.
- // Hijacking happens when the internal process state thread is running
- // thread plans, or when commands want to run in synchronous mode
- // and they call "process->WaitForProcessToStop()". An example of something
- // that will hijack the events is a simple expression:
- //
- // (lldb) expr (int)puts("hello")
- //
- // This will cause the internal process state thread to resume and halt
- // the process (and _it_ will hijack the eBroadcastBitStateChanged
- // events) and we do need the IO handler to be pushed and popped
- // correctly.
-
- if (is_hijacked || !GetTarget().GetDebugger().IsHandlingEvents())
- PopProcessIOHandler ();
- }
- }
-
- BroadcastEvent (event_sp);
- }
- else
- {
- if (log)
- {
- log->Printf ("Process::%s (pid = %" PRIu64 ") suppressing state %s (old state %s): should_broadcast == false",
- __FUNCTION__,
- GetID(),
- StateAsCString(new_state),
- StateAsCString (GetState ()));
- }
- }
-}
-
-Error
-Process::HaltPrivate()
-{
- EventSP event_sp;
- Error error (WillHalt());
- if (error.Fail())
- return error;
-
- // Ask the process subclass to actually halt our process
- bool caused_stop;
- error = DoHalt(caused_stop);
-
- DidHalt();
- return error;
-}
-
-thread_result_t
-Process::PrivateStateThread (void *arg)
-{
- std::unique_ptr<PrivateStateThreadArgs> args_up(static_cast<PrivateStateThreadArgs *>(arg));
- thread_result_t result = args_up->process->RunPrivateStateThread(args_up->is_secondary_thread);
- return result;
-}
-
-thread_result_t
-Process::RunPrivateStateThread (bool is_secondary_thread)
-{
- bool control_only = true;
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...",
- __FUNCTION__, static_cast<void*>(this), GetID());
-
- bool exit_now = false;
- bool interrupt_requested = false;
- while (!exit_now)
- {
- EventSP event_sp;
- WaitForEventsPrivate(std::chrono::microseconds(0), event_sp, control_only);
- if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster))
- {
- if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") got a control event: %d",
- __FUNCTION__, static_cast<void*>(this), GetID(),
- event_sp->GetType());
-
- switch (event_sp->GetType())
- {
- case eBroadcastInternalStateControlStop:
- exit_now = true;
- break; // doing any internal state management below
-
- case eBroadcastInternalStateControlPause:
- control_only = true;
- break;
-
- case eBroadcastInternalStateControlResume:
- control_only = false;
- break;
- }
-
- continue;
- }
- else if (event_sp->GetType() == eBroadcastBitInterrupt)
- {
- if (m_public_state.GetValue() == eStateAttaching)
- {
- if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt while attaching - forwarding interrupt.",
- __FUNCTION__, static_cast<void*>(this),
- GetID());
- BroadcastEvent(eBroadcastBitInterrupt, nullptr);
- }
- else if(StateIsRunningState(m_last_broadcast_state))
- {
- if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") woke up with an interrupt - Halting.",
- __FUNCTION__, static_cast<void*>(this),
- GetID());
- Error error = HaltPrivate();
- if (error.Fail() && log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") failed to halt the process: %s",
- __FUNCTION__, static_cast<void*>(this),
- GetID(), error.AsCString());
- // Halt should generate a stopped event. Make a note of the fact that we were
- // doing the interrupt, so we can set the interrupted flag after we receive the
- // event. We deliberately set this to true even if HaltPrivate failed, so that we
- // can interrupt on the next natural stop.
- interrupt_requested = true;
- }
- else
- {
- // This can happen when someone (e.g. Process::Halt) sees that we are running and
- // sends an interrupt request, but the process actually stops before we receive
- // it. In that case, we can just ignore the request. We use
- // m_last_broadcast_state, because the Stopped event may not have been popped of
- // the event queue yet, which is when the public state gets updated.
- if (log)
- log->Printf("Process::%s ignoring interrupt as we have already stopped.", __FUNCTION__);
- }
- continue;
- }
-
- const StateType internal_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
-
- if (internal_state != eStateInvalid)
- {
- if (m_clear_thread_plans_on_stop &&
- StateIsStoppedState(internal_state, true))
- {
- m_clear_thread_plans_on_stop = false;
- m_thread_list.DiscardThreadPlans();
- }
-
- if (interrupt_requested)
- {
- if (StateIsStoppedState (internal_state, true))
- {
- // We requested the interrupt, so mark this as such in the stop event so
- // clients can tell an interrupted process from a natural stop
- ProcessEventData::SetInterruptedInEvent (event_sp.get(), true);
- interrupt_requested = false;
- }
- else if (log)
- {
- log->Printf("Process::%s interrupt_requested, but a non-stopped state '%s' received.",
- __FUNCTION__, StateAsCString(internal_state));
- }
- }
-
- HandlePrivateEvent (event_sp);
- }
-
- if (internal_state == eStateInvalid ||
- internal_state == eStateExited ||
- internal_state == eStateDetached )
- {
- if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") about to exit with internal state %s...",
- __FUNCTION__, static_cast<void*>(this), GetID(),
- StateAsCString(internal_state));
-
- break;
- }
- }
+ // If we have been interrupted (to kill us) in the middle of running, we may
+ // not end up propagating
+ // the last events through the event system, in which case we might strand
+ // the write lock. Unlock
+ // it here so when we do to tear down the process we don't get an error
+ // destroying the lock.
+ m_public_run_lock.SetStopped();
+ }
- // Verify log is still enabled before attempting to write to it...
- if (log)
- log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...",
- __FUNCTION__, static_cast<void*>(this), GetID());
+ m_destroy_in_process = false;
- // If we are a secondary thread, then the primary thread we are working for will have already
- // acquired the public_run_lock, and isn't done with what it was doing yet, so don't
- // try to change it on the way out.
- if (!is_secondary_thread)
- m_public_run_lock.SetStopped();
- return NULL;
+ return error;
}
-//------------------------------------------------------------------
-// Process Event Data
-//------------------------------------------------------------------
+Error Process::Signal(int signal) {
+ Error error(WillSignal());
+ if (error.Success()) {
+ error = DoSignal(signal);
+ if (error.Success())
+ DidSignal();
+ }
+ return error;
+}
+
+void Process::SetUnixSignals(UnixSignalsSP &&signals_sp) {
+ assert(signals_sp && "null signals_sp");
+ m_unix_signals_sp = signals_sp;
+}
+
+const lldb::UnixSignalsSP &Process::GetUnixSignals() {
+ assert(m_unix_signals_sp && "null m_unix_signals_sp");
+ return m_unix_signals_sp;
+}
+
+lldb::ByteOrder Process::GetByteOrder() const {
+ return GetTarget().GetArchitecture().GetByteOrder();
+}
+
+uint32_t Process::GetAddressByteSize() const {
+ return GetTarget().GetArchitecture().GetAddressByteSize();
+}
+
+bool Process::ShouldBroadcastEvent(Event *event_ptr) {
+ const StateType state =
+ Process::ProcessEventData::GetStateFromEvent(event_ptr);
+ bool return_value = true;
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_EVENTS |
+ LIBLLDB_LOG_PROCESS));
+
+ switch (state) {
+ case eStateDetached:
+ case eStateExited:
+ case eStateUnloaded:
+ m_stdio_communication.SynchronizeWithReadThread();
+ m_stdio_communication.Disconnect();
+ m_stdio_communication.StopReadThread();
+ m_stdin_forward = false;
+
+ LLVM_FALLTHROUGH;
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
+ // These events indicate changes in the state of the debugging session,
+ // always report them.
+ return_value = true;
+ break;
+ case eStateInvalid:
+ // We stopped for no apparent reason, don't report it.
+ return_value = false;
+ break;
+ case eStateRunning:
+ case eStateStepping:
+ // If we've started the target running, we handle the cases where we
+ // are already running and where there is a transition from stopped to
+ // running differently.
+ // running -> running: Automatically suppress extra running events
+ // stopped -> running: Report except when there is one or more no votes
+ // and no yes votes.
+ SynchronouslyNotifyStateChanged(state);
+ if (m_force_next_event_delivery)
+ return_value = true;
+ else {
+ switch (m_last_broadcast_state) {
+ case eStateRunning:
+ case eStateStepping:
+ // We always suppress multiple runnings with no PUBLIC stop in between.
+ return_value = false;
+ break;
+ default:
+ // TODO: make this work correctly. For now always report
+ // run if we aren't running so we don't miss any running
+ // events. If I run the lldb/test/thread/a.out file and
+ // break at main.cpp:58, run and hit the breakpoints on
+ // multiple threads, then somehow during the stepping over
+ // of all breakpoints no run gets reported.
+
+ // This is a transition from stop to run.
+ switch (m_thread_list.ShouldReportRun(event_ptr)) {
+ case eVoteYes:
+ case eVoteNoOpinion:
+ return_value = true;
+ break;
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+ break;
+ }
+ }
+ break;
+ case eStateStopped:
+ case eStateCrashed:
+ case eStateSuspended:
+ // We've stopped. First see if we're going to restart the target.
+ // If we are going to stop, then we always broadcast the event.
+ // If we aren't going to stop, let the thread plans decide if we're going to
+ // report this event.
+ // If no thread has an opinion, we don't report it.
+
+ m_stdio_communication.SynchronizeWithReadThread();
+ RefreshStateAfterStop();
+ if (ProcessEventData::GetInterruptedFromEvent(event_ptr)) {
+ if (log)
+ log->Printf("Process::ShouldBroadcastEvent (%p) stopped due to an "
+ "interrupt, state: %s",
+ static_cast<void *>(event_ptr), StateAsCString(state));
+ // Even though we know we are going to stop, we should let the threads
+ // have a look at the stop,
+ // so they can properly set their state.
+ m_thread_list.ShouldStop(event_ptr);
+ return_value = true;
+ } else {
+ bool was_restarted = ProcessEventData::GetRestartedFromEvent(event_ptr);
+ bool should_resume = false;
+
+ // It makes no sense to ask "ShouldStop" if we've already been
+ // restarted...
+ // Asking the thread list is also not likely to go well, since we are
+ // running again.
+ // So in that case just report the event.
-Process::ProcessEventData::ProcessEventData () :
- EventData (),
- m_process_wp (),
- m_state (eStateInvalid),
- m_restarted (false),
- m_update_state (0),
- m_interrupted (false)
-{
-}
+ if (!was_restarted)
+ should_resume = !m_thread_list.ShouldStop(event_ptr);
-Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) :
- EventData (),
- m_process_wp (),
- m_state (state),
- m_restarted (false),
- m_update_state (0),
- m_interrupted (false)
-{
- if (process_sp)
- m_process_wp = process_sp;
-}
+ if (was_restarted || should_resume || m_resume_requested) {
+ Vote stop_vote = m_thread_list.ShouldReportStop(event_ptr);
+ if (log)
+ log->Printf("Process::ShouldBroadcastEvent: should_resume: %i state: "
+ "%s was_restarted: %i stop_vote: %d.",
+ should_resume, StateAsCString(state), was_restarted,
+ stop_vote);
+
+ switch (stop_vote) {
+ case eVoteYes:
+ return_value = true;
+ break;
+ case eVoteNoOpinion:
+ case eVoteNo:
+ return_value = false;
+ break;
+ }
+
+ if (!was_restarted) {
+ if (log)
+ log->Printf("Process::ShouldBroadcastEvent (%p) Restarting process "
+ "from state: %s",
+ static_cast<void *>(event_ptr), StateAsCString(state));
+ ProcessEventData::SetRestartedInEvent(event_ptr, true);
+ PrivateResume();
+ }
+ } else {
+ return_value = true;
+ SynchronouslyNotifyStateChanged(state);
+ }
+ }
+ break;
+ }
+
+ // Forcing the next event delivery is a one shot deal. So reset it here.
+ m_force_next_event_delivery = false;
+
+ // We do some coalescing of events (for instance two consecutive running
+ // events get coalesced.)
+ // But we only coalesce against events we actually broadcast. So we use
+ // m_last_broadcast_state
+ // to track that. NB - you can't use "m_public_state.GetValue()" for that
+ // purpose, as was originally done,
+ // because the PublicState reflects the last event pulled off the queue, and
+ // there may be several
+ // events stacked up on the queue unserviced. So the PublicState may not
+ // reflect the last broadcasted event
+ // yet. m_last_broadcast_state gets updated here.
+
+ if (return_value)
+ m_last_broadcast_state = state;
+
+ if (log)
+ log->Printf("Process::ShouldBroadcastEvent (%p) => new state: %s, last "
+ "broadcast state: %s - %s",
+ static_cast<void *>(event_ptr), StateAsCString(state),
+ StateAsCString(m_last_broadcast_state),
+ return_value ? "YES" : "NO");
+ return return_value;
+}
+
+bool Process::StartPrivateStateThread(bool is_secondary_thread) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
+
+ bool already_running = PrivateStateThreadIsValid();
+ if (log)
+ log->Printf("Process::%s()%s ", __FUNCTION__,
+ already_running ? " already running"
+ : " starting private state thread");
-Process::ProcessEventData::~ProcessEventData() = default;
+ if (!is_secondary_thread && already_running)
+ return true;
-const ConstString &
-Process::ProcessEventData::GetFlavorString ()
-{
- static ConstString g_flavor ("Process::ProcessEventData");
- return g_flavor;
+ // Create a thread that watches our internal state and controls which
+ // events make it to clients (into the DCProcess event queue).
+ char thread_name[1024];
+
+ if (HostInfo::GetMaxThreadNameLength() <= 30) {
+ // On platforms with abbreviated thread name lengths, choose thread names
+ // that fit within the limit.
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name), "intern-state-OV");
+ else
+ snprintf(thread_name, sizeof(thread_name), "intern-state");
+ } else {
+ if (already_running)
+ snprintf(thread_name, sizeof(thread_name),
+ "<lldb.process.internal-state-override(pid=%" PRIu64 ")>",
+ GetID());
+ else
+ snprintf(thread_name, sizeof(thread_name),
+ "<lldb.process.internal-state(pid=%" PRIu64 ")>", GetID());
+ }
+
+ // Create the private state thread, and start it running.
+ PrivateStateThreadArgs *args_ptr =
+ new PrivateStateThreadArgs(this, is_secondary_thread);
+ m_private_state_thread =
+ ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread,
+ (void *)args_ptr, nullptr, 8 * 1024 * 1024);
+ if (m_private_state_thread.IsJoinable()) {
+ ResumePrivateStateThread();
+ return true;
+ } else
+ return false;
}
-const ConstString &
-Process::ProcessEventData::GetFlavor () const
-{
- return ProcessEventData::GetFlavorString ();
+void Process::PausePrivateStateThread() {
+ ControlPrivateStateThread(eBroadcastInternalStateControlPause);
}
-void
-Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
-{
- ProcessSP process_sp(m_process_wp.lock());
-
- if (!process_sp)
- return;
-
- // This function gets called twice for each event, once when the event gets pulled
- // off of the private process event queue, and then any number of times, first when it gets pulled off of
- // the public event queue, then other times when we're pretending that this is where we stopped at the
- // end of expression evaluation. m_update_state is used to distinguish these
- // three cases; it is 0 when we're just pulling it off for private handling,
- // and > 1 for expression evaluation, and we don't want to do the breakpoint command handling then.
- if (m_update_state != 1)
- return;
-
- process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
-
- // If this is a halt event, even if the halt stopped with some reason other than a plain interrupt (e.g. we had
- // already stopped for a breakpoint when the halt request came through) don't do the StopInfo actions, as they may
- // end up restarting the process.
- if (m_interrupted)
+void Process::ResumePrivateStateThread() {
+ ControlPrivateStateThread(eBroadcastInternalStateControlResume);
+}
+
+void Process::StopPrivateStateThread() {
+ if (m_private_state_thread.IsJoinable())
+ ControlPrivateStateThread(eBroadcastInternalStateControlStop);
+ else {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf(
+ "Went to stop the private state thread, but it was already invalid.");
+ }
+}
+
+void Process::ControlPrivateStateThread(uint32_t signal) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ assert(signal == eBroadcastInternalStateControlStop ||
+ signal == eBroadcastInternalStateControlPause ||
+ signal == eBroadcastInternalStateControlResume);
+
+ if (log)
+ log->Printf("Process::%s (signal = %d)", __FUNCTION__, signal);
+
+ // Signal the private state thread
+ if (m_private_state_thread.IsJoinable()) {
+ // Broadcast the event.
+ // It is important to do this outside of the if below, because
+ // it's possible that the thread state is invalid but that the
+ // thread is waiting on a control event instead of simply being
+ // on its way out (this should not happen, but it apparently can).
+ if (log)
+ log->Printf("Sending control event of type: %d.", signal);
+ std::shared_ptr<EventDataReceipt> event_receipt_sp(new EventDataReceipt());
+ m_private_state_control_broadcaster.BroadcastEvent(signal,
+ event_receipt_sp);
+
+ // Wait for the event receipt or for the private state thread to exit
+ bool receipt_received = false;
+ if (PrivateStateThreadIsValid()) {
+ while (!receipt_received) {
+ bool timed_out = false;
+ // Check for a receipt for 2 seconds and then check if the private state
+ // thread is still around.
+ receipt_received = event_receipt_sp->WaitForEventReceived(
+ std::chrono::seconds(2), &timed_out);
+ if (!receipt_received) {
+ // Check if the private state thread is still around. If it isn't then
+ // we are done waiting
+ if (!PrivateStateThreadIsValid())
+ break; // Private state thread exited or is exiting, we are done
+ }
+ }
+ }
+
+ if (signal == eBroadcastInternalStateControlStop) {
+ thread_result_t result = NULL;
+ m_private_state_thread.Join(&result);
+ m_private_state_thread.Reset();
+ }
+ } else {
+ if (log)
+ log->Printf(
+ "Private state thread already dead, no need to signal it to stop.");
+ }
+}
+
+void Process::SendAsyncInterrupt() {
+ if (PrivateStateThreadIsValid())
+ m_private_state_broadcaster.BroadcastEvent(Process::eBroadcastBitInterrupt,
+ nullptr);
+ else
+ BroadcastEvent(Process::eBroadcastBitInterrupt, nullptr);
+}
+
+void Process::HandlePrivateEvent(EventSP &event_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ m_resume_requested = false;
+
+ const StateType new_state =
+ Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ // First check to see if anybody wants a shot at this event:
+ if (m_next_event_action_ap) {
+ NextEventAction::EventActionResult action_result =
+ m_next_event_action_ap->PerformAction(event_sp);
+ if (log)
+ log->Printf("Ran next event action, result was %d.", action_result);
+
+ switch (action_result) {
+ case NextEventAction::eEventActionSuccess:
+ SetNextEventAction(nullptr);
+ break;
+
+ case NextEventAction::eEventActionRetry:
+ break;
+
+ case NextEventAction::eEventActionExit:
+ // Handle Exiting Here. If we already got an exited event,
+ // we should just propagate it. Otherwise, swallow this event,
+ // and set our state to exit so the next event will kill us.
+ if (new_state != eStateExited) {
+ // FIXME: should cons up an exited event, and discard this one.
+ SetExitStatus(0, m_next_event_action_ap->GetExitString());
+ SetNextEventAction(nullptr);
return;
-
- // If we're stopped and haven't restarted, then do the StopInfo actions here:
- if (m_state == eStateStopped && ! m_restarted)
- {
- // Let process subclasses know we are about to do a public stop and
- // do anything they might need to in order to speed up register and
- // memory accesses.
- process_sp->WillPublicStop();
-
- ThreadList &curr_thread_list = process_sp->GetThreadList();
- uint32_t num_threads = curr_thread_list.GetSize();
- uint32_t idx;
-
- // The actions might change one of the thread's stop_info's opinions about whether we should
- // stop the process, so we need to query that as we go.
-
- // One other complication here, is that we try to catch any case where the target has run (except for expressions)
- // and immediately exit, but if we get that wrong (which is possible) then the thread list might have changed, and
- // that would cause our iteration here to crash. We could make a copy of the thread list, but we'd really like
- // to also know if it has changed at all, so we make up a vector of the thread ID's and check what we get back
- // against this list & bag out if anything differs.
- std::vector<uint32_t> thread_index_array(num_threads);
- for (idx = 0; idx < num_threads; ++idx)
- thread_index_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetIndexID();
-
- // Use this to track whether we should continue from here. We will only continue the target running if
- // no thread says we should stop. Of course if some thread's PerformAction actually sets the target running,
- // then it doesn't matter what the other threads say...
-
- bool still_should_stop = false;
-
- // Sometimes - for instance if we have a bug in the stub we are talking to, we stop but no thread has a
- // valid stop reason. In that case we should just stop, because we have no way of telling what the right
- // thing to do is, and it's better to let the user decide than continue behind their backs.
-
- bool does_anybody_have_an_opinion = false;
-
- for (idx = 0; idx < num_threads; ++idx)
- {
- curr_thread_list = process_sp->GetThreadList();
- if (curr_thread_list.GetSize() != num_threads)
- {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Number of threads changed from %u to %u while processing event.", num_threads, curr_thread_list.GetSize());
- break;
- }
-
- lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx);
-
- if (thread_sp->GetIndexID() != thread_index_array[idx])
- {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("The thread at position %u changed from %u to %u while processing event.",
- idx,
- thread_index_array[idx],
- thread_sp->GetIndexID());
- break;
- }
-
- StopInfoSP stop_info_sp = thread_sp->GetStopInfo ();
- if (stop_info_sp && stop_info_sp->IsValid())
- {
- does_anybody_have_an_opinion = true;
- bool this_thread_wants_to_stop;
- if (stop_info_sp->GetOverrideShouldStop())
- {
- this_thread_wants_to_stop = stop_info_sp->GetOverriddenShouldStopValue();
- }
- else
- {
- stop_info_sp->PerformAction(event_ptr);
- // The stop action might restart the target. If it does, then we want to mark that in the
- // event so that whoever is receiving it will know to wait for the running event and reflect
- // that state appropriately.
- // We also need to stop processing actions, since they aren't expecting the target to be running.
-
- // FIXME: we might have run.
- if (stop_info_sp->HasTargetRunSinceMe())
- {
- SetRestarted (true);
- break;
- }
-
- this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
- }
-
- if (!still_should_stop)
- still_should_stop = this_thread_wants_to_stop;
- }
- }
-
- if (!GetRestarted())
- {
- if (!still_should_stop && does_anybody_have_an_opinion)
- {
- // We've been asked to continue, so do that here.
- SetRestarted(true);
- // Use the public resume method here, since this is just
- // extending a public resume.
- process_sp->PrivateResume();
- }
- else
- {
- // If we didn't restart, run the Stop Hooks here:
- // They might also restart the target, so watch for that.
- process_sp->GetTarget().RunStopHooks();
- if (process_sp->GetPrivateState() == eStateRunning)
- SetRestarted(true);
- }
- }
+ }
+ SetNextEventAction(nullptr);
+ break;
+ }
+ }
+
+ // See if we should broadcast this state to external clients?
+ const bool should_broadcast = ShouldBroadcastEvent(event_sp.get());
+
+ if (should_broadcast) {
+ const bool is_hijacked = IsHijackedForEvent(eBroadcastBitStateChanged);
+ if (log) {
+ log->Printf("Process::%s (pid = %" PRIu64
+ ") broadcasting new state %s (old state %s) to %s",
+ __FUNCTION__, GetID(), StateAsCString(new_state),
+ StateAsCString(GetState()),
+ is_hijacked ? "hijacked" : "public");
+ }
+ Process::ProcessEventData::SetUpdateStateOnRemoval(event_sp.get());
+ if (StateIsRunningState(new_state)) {
+ // Only push the input handler if we aren't fowarding events,
+ // as this means the curses GUI is in use...
+ // Or don't push it if we are launching since it will come up stopped.
+ if (!GetTarget().GetDebugger().IsForwardingEvents() &&
+ new_state != eStateLaunching && new_state != eStateAttaching) {
+ PushProcessIOHandler();
+ m_iohandler_sync.SetValue(m_iohandler_sync.GetValue() + 1,
+ eBroadcastAlways);
+ if (log)
+ log->Printf("Process::%s updated m_iohandler_sync to %d",
+ __FUNCTION__, m_iohandler_sync.GetValue());
+ }
+ } else if (StateIsStoppedState(new_state, false)) {
+ if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get())) {
+ // If the lldb_private::Debugger is handling the events, we don't
+ // want to pop the process IOHandler here, we want to do it when
+ // we receive the stopped event so we can carefully control when
+ // the process IOHandler is popped because when we stop we want to
+ // display some text stating how and why we stopped, then maybe some
+ // process/thread/frame info, and then we want the "(lldb) " prompt
+ // to show up. If we pop the process IOHandler here, then we will
+ // cause the command interpreter to become the top IOHandler after
+ // the process pops off and it will update its prompt right away...
+ // See the Debugger.cpp file where it calls the function as
+ // "process_sp->PopProcessIOHandler()" to see where I am talking about.
+ // Otherwise we end up getting overlapping "(lldb) " prompts and
+ // garbled output.
+ //
+ // If we aren't handling the events in the debugger (which is indicated
+ // by "m_target.GetDebugger().IsHandlingEvents()" returning false) or we
+ // are hijacked, then we always pop the process IO handler manually.
+ // Hijacking happens when the internal process state thread is running
+ // thread plans, or when commands want to run in synchronous mode
+ // and they call "process->WaitForProcessToStop()". An example of
+ // something
+ // that will hijack the events is a simple expression:
+ //
+ // (lldb) expr (int)puts("hello")
+ //
+ // This will cause the internal process state thread to resume and halt
+ // the process (and _it_ will hijack the eBroadcastBitStateChanged
+ // events) and we do need the IO handler to be pushed and popped
+ // correctly.
+
+ if (is_hijacked || !GetTarget().GetDebugger().IsHandlingEvents())
+ PopProcessIOHandler();
+ }
}
+
+ BroadcastEvent(event_sp);
+ } else {
+ if (log) {
+ log->Printf(
+ "Process::%s (pid = %" PRIu64
+ ") suppressing state %s (old state %s): should_broadcast == false",
+ __FUNCTION__, GetID(), StateAsCString(new_state),
+ StateAsCString(GetState()));
+ }
+ }
}
-void
-Process::ProcessEventData::Dump (Stream *s) const
-{
- ProcessSP process_sp(m_process_wp.lock());
+Error Process::HaltPrivate() {
+ EventSP event_sp;
+ Error error(WillHalt());
+ if (error.Fail())
+ return error;
- if (process_sp)
- s->Printf(" process = %p (pid = %" PRIu64 "), ",
- static_cast<void*>(process_sp.get()), process_sp->GetID());
- else
- s->PutCString(" process = NULL, ");
+ // Ask the process subclass to actually halt our process
+ bool caused_stop;
+ error = DoHalt(caused_stop);
- s->Printf("state = %s", StateAsCString(GetState()));
+ DidHalt();
+ return error;
}
-const Process::ProcessEventData *
-Process::ProcessEventData::GetEventDataFromEvent (const Event *event_ptr)
-{
- if (event_ptr)
- {
- const EventData *event_data = event_ptr->GetData();
- if (event_data && event_data->GetFlavor() == ProcessEventData::GetFlavorString())
- return static_cast <const ProcessEventData *> (event_ptr->GetData());
- }
- return nullptr;
+thread_result_t Process::PrivateStateThread(void *arg) {
+ std::unique_ptr<PrivateStateThreadArgs> args_up(
+ static_cast<PrivateStateThreadArgs *>(arg));
+ thread_result_t result =
+ args_up->process->RunPrivateStateThread(args_up->is_secondary_thread);
+ return result;
}
-ProcessSP
-Process::ProcessEventData::GetProcessFromEvent (const Event *event_ptr)
-{
- ProcessSP process_sp;
- const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
- if (data)
- process_sp = data->GetProcessSP();
- return process_sp;
+thread_result_t Process::RunPrivateStateThread(bool is_secondary_thread) {
+ bool control_only = true;
+
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64 ") thread starting...",
+ __FUNCTION__, static_cast<void *>(this), GetID());
+
+ bool exit_now = false;
+ bool interrupt_requested = false;
+ while (!exit_now) {
+ EventSP event_sp;
+ WaitForEventsPrivate(std::chrono::microseconds(0), event_sp, control_only);
+ if (event_sp->BroadcasterIs(&m_private_state_control_broadcaster)) {
+ if (log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64
+ ") got a control event: %d",
+ __FUNCTION__, static_cast<void *>(this), GetID(),
+ event_sp->GetType());
+
+ switch (event_sp->GetType()) {
+ case eBroadcastInternalStateControlStop:
+ exit_now = true;
+ break; // doing any internal state management below
+
+ case eBroadcastInternalStateControlPause:
+ control_only = true;
+ break;
+
+ case eBroadcastInternalStateControlResume:
+ control_only = false;
+ break;
+ }
+
+ continue;
+ } else if (event_sp->GetType() == eBroadcastBitInterrupt) {
+ if (m_public_state.GetValue() == eStateAttaching) {
+ if (log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64
+ ") woke up with an interrupt while attaching - "
+ "forwarding interrupt.",
+ __FUNCTION__, static_cast<void *>(this), GetID());
+ BroadcastEvent(eBroadcastBitInterrupt, nullptr);
+ } else if (StateIsRunningState(m_last_broadcast_state)) {
+ if (log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64
+ ") woke up with an interrupt - Halting.",
+ __FUNCTION__, static_cast<void *>(this), GetID());
+ Error error = HaltPrivate();
+ if (error.Fail() && log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64
+ ") failed to halt the process: %s",
+ __FUNCTION__, static_cast<void *>(this), GetID(),
+ error.AsCString());
+ // Halt should generate a stopped event. Make a note of the fact that we
+ // were
+ // doing the interrupt, so we can set the interrupted flag after we
+ // receive the
+ // event. We deliberately set this to true even if HaltPrivate failed,
+ // so that we
+ // can interrupt on the next natural stop.
+ interrupt_requested = true;
+ } else {
+ // This can happen when someone (e.g. Process::Halt) sees that we are
+ // running and
+ // sends an interrupt request, but the process actually stops before we
+ // receive
+ // it. In that case, we can just ignore the request. We use
+ // m_last_broadcast_state, because the Stopped event may not have been
+ // popped of
+ // the event queue yet, which is when the public state gets updated.
+ if (log)
+ log->Printf(
+ "Process::%s ignoring interrupt as we have already stopped.",
+ __FUNCTION__);
+ }
+ continue;
+ }
+
+ const StateType internal_state =
+ Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+
+ if (internal_state != eStateInvalid) {
+ if (m_clear_thread_plans_on_stop &&
+ StateIsStoppedState(internal_state, true)) {
+ m_clear_thread_plans_on_stop = false;
+ m_thread_list.DiscardThreadPlans();
+ }
+
+ if (interrupt_requested) {
+ if (StateIsStoppedState(internal_state, true)) {
+ // We requested the interrupt, so mark this as such in the stop event
+ // so
+ // clients can tell an interrupted process from a natural stop
+ ProcessEventData::SetInterruptedInEvent(event_sp.get(), true);
+ interrupt_requested = false;
+ } else if (log) {
+ log->Printf("Process::%s interrupt_requested, but a non-stopped "
+ "state '%s' received.",
+ __FUNCTION__, StateAsCString(internal_state));
+ }
+ }
+
+ HandlePrivateEvent(event_sp);
+ }
+
+ if (internal_state == eStateInvalid || internal_state == eStateExited ||
+ internal_state == eStateDetached) {
+ if (log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64
+ ") about to exit with internal state %s...",
+ __FUNCTION__, static_cast<void *>(this), GetID(),
+ StateAsCString(internal_state));
+
+ break;
+ }
+ }
+
+ // Verify log is still enabled before attempting to write to it...
+ if (log)
+ log->Printf("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...",
+ __FUNCTION__, static_cast<void *>(this), GetID());
+
+ // If we are a secondary thread, then the primary thread we are working for
+ // will have already
+ // acquired the public_run_lock, and isn't done with what it was doing yet, so
+ // don't
+ // try to change it on the way out.
+ if (!is_secondary_thread)
+ m_public_run_lock.SetStopped();
+ return NULL;
}
-StateType
-Process::ProcessEventData::GetStateFromEvent (const Event *event_ptr)
-{
- const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
- if (data == nullptr)
- return eStateInvalid;
- else
- return data->GetState();
+//------------------------------------------------------------------
+// Process Event Data
+//------------------------------------------------------------------
+
+Process::ProcessEventData::ProcessEventData()
+ : EventData(), m_process_wp(), m_state(eStateInvalid), m_restarted(false),
+ m_update_state(0), m_interrupted(false) {}
+
+Process::ProcessEventData::ProcessEventData(const ProcessSP &process_sp,
+ StateType state)
+ : EventData(), m_process_wp(), m_state(state), m_restarted(false),
+ m_update_state(0), m_interrupted(false) {
+ if (process_sp)
+ m_process_wp = process_sp;
}
-bool
-Process::ProcessEventData::GetRestartedFromEvent (const Event *event_ptr)
-{
- const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
- if (data == nullptr)
- return false;
- else
- return data->GetRestarted();
+Process::ProcessEventData::~ProcessEventData() = default;
+
+const ConstString &Process::ProcessEventData::GetFlavorString() {
+ static ConstString g_flavor("Process::ProcessEventData");
+ return g_flavor;
+}
+
+const ConstString &Process::ProcessEventData::GetFlavor() const {
+ return ProcessEventData::GetFlavorString();
+}
+
+void Process::ProcessEventData::DoOnRemoval(Event *event_ptr) {
+ ProcessSP process_sp(m_process_wp.lock());
+
+ if (!process_sp)
+ return;
+
+ // This function gets called twice for each event, once when the event gets
+ // pulled
+ // off of the private process event queue, and then any number of times, first
+ // when it gets pulled off of
+ // the public event queue, then other times when we're pretending that this is
+ // where we stopped at the
+ // end of expression evaluation. m_update_state is used to distinguish these
+ // three cases; it is 0 when we're just pulling it off for private handling,
+ // and > 1 for expression evaluation, and we don't want to do the breakpoint
+ // command handling then.
+ if (m_update_state != 1)
+ return;
+
+ process_sp->SetPublicState(
+ m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
+
+ // If this is a halt event, even if the halt stopped with some reason other
+ // than a plain interrupt (e.g. we had
+ // already stopped for a breakpoint when the halt request came through) don't
+ // do the StopInfo actions, as they may
+ // end up restarting the process.
+ if (m_interrupted)
+ return;
+
+ // If we're stopped and haven't restarted, then do the StopInfo actions here:
+ if (m_state == eStateStopped && !m_restarted) {
+ // Let process subclasses know we are about to do a public stop and
+ // do anything they might need to in order to speed up register and
+ // memory accesses.
+ process_sp->WillPublicStop();
+
+ ThreadList &curr_thread_list = process_sp->GetThreadList();
+ uint32_t num_threads = curr_thread_list.GetSize();
+ uint32_t idx;
+
+ // The actions might change one of the thread's stop_info's opinions about
+ // whether we should
+ // stop the process, so we need to query that as we go.
+
+ // One other complication here, is that we try to catch any case where the
+ // target has run (except for expressions)
+ // and immediately exit, but if we get that wrong (which is possible) then
+ // the thread list might have changed, and
+ // that would cause our iteration here to crash. We could make a copy of
+ // the thread list, but we'd really like
+ // to also know if it has changed at all, so we make up a vector of the
+ // thread ID's and check what we get back
+ // against this list & bag out if anything differs.
+ std::vector<uint32_t> thread_index_array(num_threads);
+ for (idx = 0; idx < num_threads; ++idx)
+ thread_index_array[idx] =
+ curr_thread_list.GetThreadAtIndex(idx)->GetIndexID();
+
+ // Use this to track whether we should continue from here. We will only
+ // continue the target running if
+ // no thread says we should stop. Of course if some thread's PerformAction
+ // actually sets the target running,
+ // then it doesn't matter what the other threads say...
+
+ bool still_should_stop = false;
+
+ // Sometimes - for instance if we have a bug in the stub we are talking to,
+ // we stop but no thread has a
+ // valid stop reason. In that case we should just stop, because we have no
+ // way of telling what the right
+ // thing to do is, and it's better to let the user decide than continue
+ // behind their backs.
+
+ bool does_anybody_have_an_opinion = false;
+
+ for (idx = 0; idx < num_threads; ++idx) {
+ curr_thread_list = process_sp->GetThreadList();
+ if (curr_thread_list.GetSize() != num_threads) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
+ LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf(
+ "Number of threads changed from %u to %u while processing event.",
+ num_threads, curr_thread_list.GetSize());
+ break;
+ }
+
+ lldb::ThreadSP thread_sp = curr_thread_list.GetThreadAtIndex(idx);
+
+ if (thread_sp->GetIndexID() != thread_index_array[idx]) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
+ LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("The thread at position %u changed from %u to %u while "
+ "processing event.",
+ idx, thread_index_array[idx], thread_sp->GetIndexID());
+ break;
+ }
+
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
+ if (stop_info_sp && stop_info_sp->IsValid()) {
+ does_anybody_have_an_opinion = true;
+ bool this_thread_wants_to_stop;
+ if (stop_info_sp->GetOverrideShouldStop()) {
+ this_thread_wants_to_stop =
+ stop_info_sp->GetOverriddenShouldStopValue();
+ } else {
+ stop_info_sp->PerformAction(event_ptr);
+ // The stop action might restart the target. If it does, then we want
+ // to mark that in the
+ // event so that whoever is receiving it will know to wait for the
+ // running event and reflect
+ // that state appropriately.
+ // We also need to stop processing actions, since they aren't
+ // expecting the target to be running.
+
+ // FIXME: we might have run.
+ if (stop_info_sp->HasTargetRunSinceMe()) {
+ SetRestarted(true);
+ break;
+ }
+
+ this_thread_wants_to_stop = stop_info_sp->ShouldStop(event_ptr);
+ }
+
+ if (!still_should_stop)
+ still_should_stop = this_thread_wants_to_stop;
+ }
+ }
+
+ if (!GetRestarted()) {
+ if (!still_should_stop && does_anybody_have_an_opinion) {
+ // We've been asked to continue, so do that here.
+ SetRestarted(true);
+ // Use the public resume method here, since this is just
+ // extending a public resume.
+ process_sp->PrivateResume();
+ } else {
+ // If we didn't restart, run the Stop Hooks here:
+ // They might also restart the target, so watch for that.
+ process_sp->GetTarget().RunStopHooks();
+ if (process_sp->GetPrivateState() == eStateRunning)
+ SetRestarted(true);
+ }
+ }
+ }
+}
+
+void Process::ProcessEventData::Dump(Stream *s) const {
+ ProcessSP process_sp(m_process_wp.lock());
+
+ if (process_sp)
+ s->Printf(" process = %p (pid = %" PRIu64 "), ",
+ static_cast<void *>(process_sp.get()), process_sp->GetID());
+ else
+ s->PutCString(" process = NULL, ");
+
+ s->Printf("state = %s", StateAsCString(GetState()));
}
-void
-Process::ProcessEventData::SetRestartedInEvent (Event *event_ptr, bool new_value)
-{
- ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
- if (data != nullptr)
- data->SetRestarted(new_value);
+const Process::ProcessEventData *
+Process::ProcessEventData::GetEventDataFromEvent(const Event *event_ptr) {
+ if (event_ptr) {
+ const EventData *event_data = event_ptr->GetData();
+ if (event_data &&
+ event_data->GetFlavor() == ProcessEventData::GetFlavorString())
+ return static_cast<const ProcessEventData *>(event_ptr->GetData());
+ }
+ return nullptr;
}
-size_t
-Process::ProcessEventData::GetNumRestartedReasons(const Event *event_ptr)
-{
- ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
- if (data != nullptr)
- return data->GetNumRestartedReasons();
- else
- return 0;
+ProcessSP
+Process::ProcessEventData::GetProcessFromEvent(const Event *event_ptr) {
+ ProcessSP process_sp;
+ const ProcessEventData *data = GetEventDataFromEvent(event_ptr);
+ if (data)
+ process_sp = data->GetProcessSP();
+ return process_sp;
+}
+
+StateType Process::ProcessEventData::GetStateFromEvent(const Event *event_ptr) {
+ const ProcessEventData *data = GetEventDataFromEvent(event_ptr);
+ if (data == nullptr)
+ return eStateInvalid;
+ else
+ return data->GetState();
+}
+
+bool Process::ProcessEventData::GetRestartedFromEvent(const Event *event_ptr) {
+ const ProcessEventData *data = GetEventDataFromEvent(event_ptr);
+ if (data == nullptr)
+ return false;
+ else
+ return data->GetRestarted();
}
-const char *
-Process::ProcessEventData::GetRestartedReasonAtIndex(const Event *event_ptr, size_t idx)
-{
- ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
- if (data != nullptr)
- return data->GetRestartedReasonAtIndex(idx);
- else
- return nullptr;
+void Process::ProcessEventData::SetRestartedInEvent(Event *event_ptr,
+ bool new_value) {
+ ProcessEventData *data =
+ const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr));
+ if (data != nullptr)
+ data->SetRestarted(new_value);
}
-void
-Process::ProcessEventData::AddRestartedReason (Event *event_ptr, const char *reason)
-{
- ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
- if (data != nullptr)
- data->AddRestartedReason(reason);
+size_t
+Process::ProcessEventData::GetNumRestartedReasons(const Event *event_ptr) {
+ ProcessEventData *data =
+ const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr));
+ if (data != nullptr)
+ return data->GetNumRestartedReasons();
+ else
+ return 0;
}
-bool
-Process::ProcessEventData::GetInterruptedFromEvent (const Event *event_ptr)
-{
- const ProcessEventData *data = GetEventDataFromEvent (event_ptr);
- if (data == nullptr)
- return false;
- else
- return data->GetInterrupted ();
+const char *
+Process::ProcessEventData::GetRestartedReasonAtIndex(const Event *event_ptr,
+ size_t idx) {
+ ProcessEventData *data =
+ const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr));
+ if (data != nullptr)
+ return data->GetRestartedReasonAtIndex(idx);
+ else
+ return nullptr;
}
-void
-Process::ProcessEventData::SetInterruptedInEvent (Event *event_ptr, bool new_value)
-{
- ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
- if (data != nullptr)
- data->SetInterrupted(new_value);
+void Process::ProcessEventData::AddRestartedReason(Event *event_ptr,
+ const char *reason) {
+ ProcessEventData *data =
+ const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr));
+ if (data != nullptr)
+ data->AddRestartedReason(reason);
}
-bool
-Process::ProcessEventData::SetUpdateStateOnRemoval (Event *event_ptr)
-{
- ProcessEventData *data = const_cast<ProcessEventData *>(GetEventDataFromEvent (event_ptr));
- if (data)
- {
- data->SetUpdateStateOnRemoval();
- return true;
- }
+bool Process::ProcessEventData::GetInterruptedFromEvent(
+ const Event *event_ptr) {
+ const ProcessEventData *data = GetEventDataFromEvent(event_ptr);
+ if (data == nullptr)
return false;
+ else
+ return data->GetInterrupted();
}
-lldb::TargetSP
-Process::CalculateTarget ()
-{
- return m_target_sp.lock();
+void Process::ProcessEventData::SetInterruptedInEvent(Event *event_ptr,
+ bool new_value) {
+ ProcessEventData *data =
+ const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr));
+ if (data != nullptr)
+ data->SetInterrupted(new_value);
+}
+
+bool Process::ProcessEventData::SetUpdateStateOnRemoval(Event *event_ptr) {
+ ProcessEventData *data =
+ const_cast<ProcessEventData *>(GetEventDataFromEvent(event_ptr));
+ if (data) {
+ data->SetUpdateStateOnRemoval();
+ return true;
+ }
+ return false;
}
-void
-Process::CalculateExecutionContext (ExecutionContext &exe_ctx)
-{
- exe_ctx.SetTargetPtr (&GetTarget());
- exe_ctx.SetProcessPtr (this);
- exe_ctx.SetThreadPtr(nullptr);
- exe_ctx.SetFramePtr(nullptr);
+lldb::TargetSP Process::CalculateTarget() { return m_target_sp.lock(); }
+
+void Process::CalculateExecutionContext(ExecutionContext &exe_ctx) {
+ exe_ctx.SetTargetPtr(&GetTarget());
+ exe_ctx.SetProcessPtr(this);
+ exe_ctx.SetThreadPtr(nullptr);
+ exe_ctx.SetFramePtr(nullptr);
}
-//uint32_t
-//Process::ListProcessesMatchingName (const char *name, StringList &matches, std::vector<lldb::pid_t> &pids)
+// uint32_t
+// Process::ListProcessesMatchingName (const char *name, StringList &matches,
+// std::vector<lldb::pid_t> &pids)
//{
// return 0;
//}
-//
-//ArchSpec
-//Process::GetArchSpecForExistingProcess (lldb::pid_t pid)
+//
+// ArchSpec
+// Process::GetArchSpecForExistingProcess (lldb::pid_t pid)
//{
// return Host::GetArchSpecForExistingProcess (pid);
//}
//
-//ArchSpec
-//Process::GetArchSpecForExistingProcess (const char *process_name)
+// ArchSpec
+// Process::GetArchSpecForExistingProcess (const char *process_name)
//{
// return Host::GetArchSpecForExistingProcess (process_name);
//}
-void
-Process::AppendSTDOUT (const char * s, size_t len)
-{
- std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
- m_stdout_data.append (s, len);
- BroadcastEventIfUnique (eBroadcastBitSTDOUT, new ProcessEventData (shared_from_this(), GetState()));
-}
-
-void
-Process::AppendSTDERR (const char * s, size_t len)
-{
- std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
- m_stderr_data.append (s, len);
- BroadcastEventIfUnique (eBroadcastBitSTDERR, new ProcessEventData (shared_from_this(), GetState()));
-}
-
-void
-Process::BroadcastAsyncProfileData(const std::string &one_profile_data)
-{
- std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex);
- m_profile_data.push_back(one_profile_data);
- BroadcastEventIfUnique (eBroadcastBitProfileData, new ProcessEventData (shared_from_this(), GetState()));
-}
-
-void
-Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp,
- const StructuredDataPluginSP &plugin_sp)
-{
- BroadcastEvent(eBroadcastBitStructuredData,
- new EventDataStructuredData(shared_from_this(),
- object_sp, plugin_sp));
+void Process::AppendSTDOUT(const char *s, size_t len) {
+ std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
+ m_stdout_data.append(s, len);
+ BroadcastEventIfUnique(eBroadcastBitSTDOUT,
+ new ProcessEventData(shared_from_this(), GetState()));
+}
+
+void Process::AppendSTDERR(const char *s, size_t len) {
+ std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
+ m_stderr_data.append(s, len);
+ BroadcastEventIfUnique(eBroadcastBitSTDERR,
+ new ProcessEventData(shared_from_this(), GetState()));
+}
+
+void Process::BroadcastAsyncProfileData(const std::string &one_profile_data) {
+ std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex);
+ m_profile_data.push_back(one_profile_data);
+ BroadcastEventIfUnique(eBroadcastBitProfileData,
+ new ProcessEventData(shared_from_this(), GetState()));
+}
+
+void Process::BroadcastStructuredData(const StructuredData::ObjectSP &object_sp,
+ const StructuredDataPluginSP &plugin_sp) {
+ BroadcastEvent(
+ eBroadcastBitStructuredData,
+ new EventDataStructuredData(shared_from_this(), object_sp, plugin_sp));
}
StructuredDataPluginSP
-Process::GetStructuredDataPlugin(const ConstString &type_name) const
-{
- auto find_it = m_structured_data_plugin_map.find(type_name);
- if (find_it != m_structured_data_plugin_map.end())
- return find_it->second;
- else
- return StructuredDataPluginSP();
+Process::GetStructuredDataPlugin(const ConstString &type_name) const {
+ auto find_it = m_structured_data_plugin_map.find(type_name);
+ if (find_it != m_structured_data_plugin_map.end())
+ return find_it->second;
+ else
+ return StructuredDataPluginSP();
}
-size_t
-Process::GetAsyncProfileData (char *buf, size_t buf_size, Error &error)
-{
- std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex);
- if (m_profile_data.empty())
- return 0;
-
- std::string &one_profile_data = m_profile_data.front();
- size_t bytes_available = one_profile_data.size();
- if (bytes_available > 0)
- {
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Process::GetProfileData (buf = %p, size = %" PRIu64 ")",
- static_cast<void*>(buf),
- static_cast<uint64_t>(buf_size));
- if (bytes_available > buf_size)
- {
- memcpy(buf, one_profile_data.c_str(), buf_size);
- one_profile_data.erase(0, buf_size);
- bytes_available = buf_size;
- }
- else
- {
- memcpy(buf, one_profile_data.c_str(), bytes_available);
- m_profile_data.erase(m_profile_data.begin());
- }
+size_t Process::GetAsyncProfileData(char *buf, size_t buf_size, Error &error) {
+ std::lock_guard<std::recursive_mutex> guard(m_profile_data_comm_mutex);
+ if (m_profile_data.empty())
+ return 0;
+
+ std::string &one_profile_data = m_profile_data.front();
+ size_t bytes_available = one_profile_data.size();
+ if (bytes_available > 0) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::GetProfileData (buf = %p, size = %" PRIu64 ")",
+ static_cast<void *>(buf), static_cast<uint64_t>(buf_size));
+ if (bytes_available > buf_size) {
+ memcpy(buf, one_profile_data.c_str(), buf_size);
+ one_profile_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ } else {
+ memcpy(buf, one_profile_data.c_str(), bytes_available);
+ m_profile_data.erase(m_profile_data.begin());
}
- return bytes_available;
+ }
+ return bytes_available;
}
//------------------------------------------------------------------
// Process STDIO
//------------------------------------------------------------------
-size_t
-Process::GetSTDOUT (char *buf, size_t buf_size, Error &error)
-{
- std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
- size_t bytes_available = m_stdout_data.size();
- if (bytes_available > 0)
- {
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")",
- static_cast<void*>(buf),
- static_cast<uint64_t>(buf_size));
- if (bytes_available > buf_size)
- {
- memcpy(buf, m_stdout_data.c_str(), buf_size);
- m_stdout_data.erase(0, buf_size);
- bytes_available = buf_size;
- }
- else
- {
- memcpy(buf, m_stdout_data.c_str(), bytes_available);
- m_stdout_data.clear();
- }
- }
- return bytes_available;
-}
-
-size_t
-Process::GetSTDERR (char *buf, size_t buf_size, Error &error)
-{
- std::lock_guard<std::recursive_mutex> gaurd(m_stdio_communication_mutex);
- size_t bytes_available = m_stderr_data.size();
- if (bytes_available > 0)
- {
- Log *log (lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")",
- static_cast<void*>(buf),
- static_cast<uint64_t>(buf_size));
- if (bytes_available > buf_size)
- {
- memcpy(buf, m_stderr_data.c_str(), buf_size);
- m_stderr_data.erase(0, buf_size);
- bytes_available = buf_size;
- }
- else
- {
- memcpy(buf, m_stderr_data.c_str(), bytes_available);
- m_stderr_data.clear();
- }
- }
- return bytes_available;
-}
-
-void
-Process::STDIOReadThreadBytesReceived (void *baton, const void *src, size_t src_len)
-{
- Process *process = (Process *) baton;
- process->AppendSTDOUT (static_cast<const char *>(src), src_len);
+size_t Process::GetSTDOUT(char *buf, size_t buf_size, Error &error) {
+ std::lock_guard<std::recursive_mutex> guard(m_stdio_communication_mutex);
+ size_t bytes_available = m_stdout_data.size();
+ if (bytes_available > 0) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::GetSTDOUT (buf = %p, size = %" PRIu64 ")",
+ static_cast<void *>(buf), static_cast<uint64_t>(buf_size));
+ if (bytes_available > buf_size) {
+ memcpy(buf, m_stdout_data.c_str(), buf_size);
+ m_stdout_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ } else {
+ memcpy(buf, m_stdout_data.c_str(), bytes_available);
+ m_stdout_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+size_t Process::GetSTDERR(char *buf, size_t buf_size, Error &error) {
+ std::lock_guard<std::recursive_mutex> gaurd(m_stdio_communication_mutex);
+ size_t bytes_available = m_stderr_data.size();
+ if (bytes_available > 0) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::GetSTDERR (buf = %p, size = %" PRIu64 ")",
+ static_cast<void *>(buf), static_cast<uint64_t>(buf_size));
+ if (bytes_available > buf_size) {
+ memcpy(buf, m_stderr_data.c_str(), buf_size);
+ m_stderr_data.erase(0, buf_size);
+ bytes_available = buf_size;
+ } else {
+ memcpy(buf, m_stderr_data.c_str(), bytes_available);
+ m_stderr_data.clear();
+ }
+ }
+ return bytes_available;
+}
+
+void Process::STDIOReadThreadBytesReceived(void *baton, const void *src,
+ size_t src_len) {
+ Process *process = (Process *)baton;
+ process->AppendSTDOUT(static_cast<const char *>(src), src_len);
}
-class IOHandlerProcessSTDIO :
- public IOHandler
-{
+class IOHandlerProcessSTDIO : public IOHandler {
public:
- IOHandlerProcessSTDIO (Process *process,
- int write_fd) :
- IOHandler(process->GetTarget().GetDebugger(), IOHandler::Type::ProcessIO),
- m_process (process),
- m_read_file (),
- m_write_file (write_fd, false),
- m_pipe ()
- {
- m_pipe.CreateNew(false);
- m_read_file.SetDescriptor(GetInputFD(), false);
- }
-
- ~IOHandlerProcessSTDIO() override = default;
-
- // Each IOHandler gets to run until it is done. It should read data
- // from the "in" and place output into "out" and "err and return
- // when done.
- void
- Run () override
- {
- if (!m_read_file.IsValid() || !m_write_file.IsValid() || !m_pipe.CanRead() || !m_pipe.CanWrite())
- {
- SetIsDone(true);
- return;
- }
-
- SetIsDone(false);
- const int read_fd = m_read_file.GetDescriptor();
- TerminalState terminal_state;
- terminal_state.Save (read_fd, false);
- Terminal terminal(read_fd);
- terminal.SetCanonical(false);
- terminal.SetEcho(false);
+ IOHandlerProcessSTDIO(Process *process, int write_fd)
+ : IOHandler(process->GetTarget().GetDebugger(),
+ IOHandler::Type::ProcessIO),
+ m_process(process), m_read_file(), m_write_file(write_fd, false),
+ m_pipe() {
+ m_pipe.CreateNew(false);
+ m_read_file.SetDescriptor(GetInputFD(), false);
+ }
+
+ ~IOHandlerProcessSTDIO() override = default;
+
+ // Each IOHandler gets to run until it is done. It should read data
+ // from the "in" and place output into "out" and "err and return
+ // when done.
+ void Run() override {
+ if (!m_read_file.IsValid() || !m_write_file.IsValid() ||
+ !m_pipe.CanRead() || !m_pipe.CanWrite()) {
+ SetIsDone(true);
+ return;
+ }
+
+ SetIsDone(false);
+ const int read_fd = m_read_file.GetDescriptor();
+ TerminalState terminal_state;
+ terminal_state.Save(read_fd, false);
+ Terminal terminal(read_fd);
+ terminal.SetCanonical(false);
+ terminal.SetEcho(false);
// FD_ZERO, FD_SET are not supported on windows
#ifndef _WIN32
- const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
- m_is_running = true;
- while (!GetIsDone())
- {
- SelectHelper select_helper;
- select_helper.FDSetRead(read_fd);
- select_helper.FDSetRead(pipe_read_fd);
- Error error = select_helper.Select();
-
- if (error.Fail())
- {
- SetIsDone(true);
- }
- else
- {
- char ch = 0;
- size_t n;
- if (select_helper.FDIsSetRead(read_fd))
- {
- n = 1;
- if (m_read_file.Read(&ch, n).Success() && n == 1)
- {
- if (m_write_file.Write(&ch, n).Fail() || n != 1)
- SetIsDone(true);
- }
- else
- SetIsDone(true);
- }
- if (select_helper.FDIsSetRead(pipe_read_fd))
- {
- size_t bytes_read;
- // Consume the interrupt byte
- Error error = m_pipe.Read(&ch, 1, bytes_read);
- if (error.Success())
- {
- switch (ch)
- {
- case 'q':
- SetIsDone(true);
- break;
- case 'i':
- if (StateIsRunningState(m_process->GetState()))
- m_process->SendAsyncInterrupt();
- break;
- }
- }
- }
- }
- }
- m_is_running = false;
-#endif
- terminal_state.Restore();
- }
-
- void
- Cancel () override
- {
- SetIsDone(true);
- // Only write to our pipe to cancel if we are in IOHandlerProcessSTDIO::Run().
- // We can end up with a python command that is being run from the command
- // interpreter:
- //
- // (lldb) step_process_thousands_of_times
- //
- // In this case the command interpreter will be in the middle of handling
- // the command and if the process pushes and pops the IOHandler thousands
- // of times, we can end up writing to m_pipe without ever consuming the
- // bytes from the pipe in IOHandlerProcessSTDIO::Run() and end up
- // deadlocking when the pipe gets fed up and blocks until data is consumed.
- if (m_is_running)
- {
- char ch = 'q'; // Send 'q' for quit
- size_t bytes_written = 0;
- m_pipe.Write(&ch, 1, bytes_written);
- }
- }
+ const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
+ m_is_running = true;
+ while (!GetIsDone()) {
+ SelectHelper select_helper;
+ select_helper.FDSetRead(read_fd);
+ select_helper.FDSetRead(pipe_read_fd);
+ Error error = select_helper.Select();
- bool
- Interrupt () override
- {
- // Do only things that are safe to do in an interrupt context (like in
- // a SIGINT handler), like write 1 byte to a file descriptor. This will
- // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte
- // that was written to the pipe and then call m_process->SendAsyncInterrupt()
- // from a much safer location in code.
- if (m_active)
- {
- char ch = 'i'; // Send 'i' for interrupt
- size_t bytes_written = 0;
- Error result = m_pipe.Write(&ch, 1, bytes_written);
- return result.Success();
+ if (error.Fail()) {
+ SetIsDone(true);
+ } else {
+ char ch = 0;
+ size_t n;
+ if (select_helper.FDIsSetRead(read_fd)) {
+ n = 1;
+ if (m_read_file.Read(&ch, n).Success() && n == 1) {
+ if (m_write_file.Write(&ch, n).Fail() || n != 1)
+ SetIsDone(true);
+ } else
+ SetIsDone(true);
}
- else
- {
- // This IOHandler might be pushed on the stack, but not being run currently
- // so do the right thing if we aren't actively watching for STDIN by sending
- // the interrupt to the process. Otherwise the write to the pipe above would
- // do nothing. This can happen when the command interpreter is running and
- // gets a "expression ...". It will be on the IOHandler thread and sending
- // the input is complete to the delegate which will cause the expression to
- // run, which will push the process IO handler, but not run it.
-
- if (StateIsRunningState(m_process->GetState()))
- {
+ if (select_helper.FDIsSetRead(pipe_read_fd)) {
+ size_t bytes_read;
+ // Consume the interrupt byte
+ Error error = m_pipe.Read(&ch, 1, bytes_read);
+ if (error.Success()) {
+ switch (ch) {
+ case 'q':
+ SetIsDone(true);
+ break;
+ case 'i':
+ if (StateIsRunningState(m_process->GetState()))
m_process->SendAsyncInterrupt();
- return true;
+ break;
}
+ }
}
- return false;
+ }
}
-
- void
- GotEOF() override
- {
- }
-
-protected:
- Process *m_process;
- File m_read_file; // Read from this file (usually actual STDIN for LLDB
- File m_write_file; // Write to this file (usually the master pty for getting io to debuggee)
- Pipe m_pipe;
- std::atomic<bool> m_is_running;
-};
-
-void
-Process::SetSTDIOFileDescriptor (int fd)
-{
- // First set up the Read Thread for reading/handling process I/O
-
- std::unique_ptr<ConnectionFileDescriptor> conn_ap (new ConnectionFileDescriptor (fd, true));
-
- if (conn_ap)
- {
- m_stdio_communication.SetConnection (conn_ap.release());
- if (m_stdio_communication.IsConnected())
- {
- m_stdio_communication.SetReadThreadBytesReceivedCallback (STDIOReadThreadBytesReceived, this);
- m_stdio_communication.StartReadThread();
-
- // Now read thread is set up, set up input reader.
-
- if (!m_process_input_reader)
- m_process_input_reader.reset (new IOHandlerProcessSTDIO (this, fd));
- }
- }
-}
+ m_is_running = false;
+#endif
+ terminal_state.Restore();
+ }
-bool
-Process::ProcessIOHandlerIsActive ()
-{
- IOHandlerSP io_handler_sp (m_process_input_reader);
- if (io_handler_sp)
- return GetTarget().GetDebugger().IsTopIOHandler (io_handler_sp);
- return false;
-}
-bool
-Process::PushProcessIOHandler ()
-{
- IOHandlerSP io_handler_sp (m_process_input_reader);
- if (io_handler_sp)
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::%s pushing IO handler", __FUNCTION__);
+ void Cancel() override {
+ SetIsDone(true);
+ // Only write to our pipe to cancel if we are in
+ // IOHandlerProcessSTDIO::Run().
+ // We can end up with a python command that is being run from the command
+ // interpreter:
+ //
+ // (lldb) step_process_thousands_of_times
+ //
+ // In this case the command interpreter will be in the middle of handling
+ // the command and if the process pushes and pops the IOHandler thousands
+ // of times, we can end up writing to m_pipe without ever consuming the
+ // bytes from the pipe in IOHandlerProcessSTDIO::Run() and end up
+ // deadlocking when the pipe gets fed up and blocks until data is consumed.
+ if (m_is_running) {
+ char ch = 'q'; // Send 'q' for quit
+ size_t bytes_written = 0;
+ m_pipe.Write(&ch, 1, bytes_written);
+ }
+ }
+
+ bool Interrupt() override {
+ // Do only things that are safe to do in an interrupt context (like in
+ // a SIGINT handler), like write 1 byte to a file descriptor. This will
+ // interrupt the IOHandlerProcessSTDIO::Run() and we can look at the byte
+ // that was written to the pipe and then call
+ // m_process->SendAsyncInterrupt()
+ // from a much safer location in code.
+ if (m_active) {
+ char ch = 'i'; // Send 'i' for interrupt
+ size_t bytes_written = 0;
+ Error result = m_pipe.Write(&ch, 1, bytes_written);
+ return result.Success();
+ } else {
+ // This IOHandler might be pushed on the stack, but not being run
+ // currently
+ // so do the right thing if we aren't actively watching for STDIN by
+ // sending
+ // the interrupt to the process. Otherwise the write to the pipe above
+ // would
+ // do nothing. This can happen when the command interpreter is running and
+ // gets a "expression ...". It will be on the IOHandler thread and sending
+ // the input is complete to the delegate which will cause the expression
+ // to
+ // run, which will push the process IO handler, but not run it.
- io_handler_sp->SetIsDone(false);
- GetTarget().GetDebugger().PushIOHandler (io_handler_sp);
+ if (StateIsRunningState(m_process->GetState())) {
+ m_process->SendAsyncInterrupt();
return true;
+ }
}
return false;
-}
-
-bool
-Process::PopProcessIOHandler ()
-{
- IOHandlerSP io_handler_sp (m_process_input_reader);
- if (io_handler_sp)
- return GetTarget().GetDebugger().PopIOHandler (io_handler_sp);
- return false;
-}
-
-// The process needs to know about installed plug-ins
-void
-Process::SettingsInitialize ()
-{
- Thread::SettingsInitialize ();
-}
-
-void
-Process::SettingsTerminate ()
-{
- Thread::SettingsTerminate ();
-}
-
-namespace
-{
- // RestorePlanState is used to record the "is private", "is master" and "okay to discard" fields of
- // the plan we are running, and reset it on Clean or on destruction.
- // It will only reset the state once, so you can call Clean and then monkey with the state and it
- // won't get reset on you again.
-
- class RestorePlanState
- {
- public:
- RestorePlanState (lldb::ThreadPlanSP thread_plan_sp) :
- m_thread_plan_sp(thread_plan_sp),
- m_already_reset(false)
- {
- if (m_thread_plan_sp)
- {
- m_private = m_thread_plan_sp->GetPrivate();
- m_is_master = m_thread_plan_sp->IsMasterPlan();
- m_okay_to_discard = m_thread_plan_sp->OkayToDiscard();
- }
- }
-
- ~RestorePlanState()
- {
- Clean();
- }
-
- void
- Clean ()
- {
- if (!m_already_reset && m_thread_plan_sp)
- {
- m_already_reset = true;
- m_thread_plan_sp->SetPrivate(m_private);
- m_thread_plan_sp->SetIsMasterPlan (m_is_master);
- m_thread_plan_sp->SetOkayToDiscard(m_okay_to_discard);
- }
- }
-
- private:
- lldb::ThreadPlanSP m_thread_plan_sp;
- bool m_already_reset;
- bool m_private;
- bool m_is_master;
- bool m_okay_to_discard;
- };
-} // anonymous namespace
-
-ExpressionResults
-Process::RunThreadPlan(ExecutionContext &exe_ctx, lldb::ThreadPlanSP &thread_plan_sp,
- const EvaluateExpressionOptions &options, DiagnosticManager &diagnostic_manager)
-{
- ExpressionResults return_value = eExpressionSetupError;
-
- std::lock_guard<std::mutex> run_thread_plan_locker(m_run_thread_plan_lock);
-
- if (!thread_plan_sp)
- {
- diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called with empty thread plan.");
- return eExpressionSetupError;
- }
-
- if (!thread_plan_sp->ValidatePlan(nullptr))
- {
- diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called with an invalid thread plan.");
- return eExpressionSetupError;
- }
-
- if (exe_ctx.GetProcessPtr() != this)
- {
- diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called on wrong process.");
- return eExpressionSetupError;
- }
-
- Thread *thread = exe_ctx.GetThreadPtr();
- if (thread == nullptr)
- {
- diagnostic_manager.PutCString(eDiagnosticSeverityError, "RunThreadPlan called with invalid thread.");
- return eExpressionSetupError;
- }
-
- // We need to change some of the thread plan attributes for the thread plan runner. This will restore them
- // when we are done:
-
- RestorePlanState thread_plan_restorer(thread_plan_sp);
-
- // We rely on the thread plan we are running returning "PlanCompleted" if when it successfully completes.
- // For that to be true the plan can't be private - since private plans suppress themselves in the
- // GetCompletedPlan call.
-
- thread_plan_sp->SetPrivate(false);
-
- // The plans run with RunThreadPlan also need to be terminal master plans or when they are done we will end
- // up asking the plan above us whether we should stop, which may give the wrong answer.
-
- thread_plan_sp->SetIsMasterPlan (true);
- thread_plan_sp->SetOkayToDiscard(false);
-
- if (m_private_state.GetValue() != eStateStopped)
- {
- diagnostic_manager.PutCString(eDiagnosticSeverityError,
- "RunThreadPlan called while the private state was not stopped.");
- return eExpressionSetupError;
- }
-
- // Save the thread & frame from the exe_ctx for restoration after we run
- const uint32_t thread_idx_id = thread->GetIndexID();
- StackFrameSP selected_frame_sp = thread->GetSelectedFrame();
- if (!selected_frame_sp)
- {
- thread->SetSelectedFrame(nullptr);
- selected_frame_sp = thread->GetSelectedFrame();
- if (!selected_frame_sp)
- {
- diagnostic_manager.Printf(eDiagnosticSeverityError,
- "RunThreadPlan called without a selected frame on thread %d", thread_idx_id);
- return eExpressionSetupError;
- }
- }
-
- StackID ctx_frame_id = selected_frame_sp->GetStackID();
-
- // N.B. Running the target may unset the currently selected thread and frame. We don't want to do that either,
- // so we should arrange to reset them as well.
-
- lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread();
-
- uint32_t selected_tid;
- StackID selected_stack_id;
- if (selected_thread_sp)
- {
- selected_tid = selected_thread_sp->GetIndexID();
- selected_stack_id = selected_thread_sp->GetSelectedFrame()->GetStackID();
- }
- else
- {
- selected_tid = LLDB_INVALID_THREAD_ID;
- }
+ }
- HostThread backup_private_state_thread;
- lldb::StateType old_state = eStateInvalid;
- lldb::ThreadPlanSP stopper_base_plan_sp;
-
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
- if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
- {
- // Yikes, we are running on the private state thread! So we can't wait for public events on this thread, since
- // we are the thread that is generating public events.
- // The simplest thing to do is to spin up a temporary thread to handle private state thread events while
- // we are fielding public events here.
- if (log)
- log->Printf ("Running thread plan on private state thread, spinning up another state thread to handle the events.");
-
- backup_private_state_thread = m_private_state_thread;
-
- // One other bit of business: we want to run just this thread plan and anything it pushes, and then stop,
- // returning control here.
- // But in the normal course of things, the plan above us on the stack would be given a shot at the stop
- // event before deciding to stop, and we don't want that. So we insert a "stopper" base plan on the stack
- // before the plan we want to run. Since base plans always stop and return control to the user, that will
- // do just what we want.
- stopper_base_plan_sp.reset(new ThreadPlanBase (*thread));
- thread->QueueThreadPlan (stopper_base_plan_sp, false);
- // Have to make sure our public state is stopped, since otherwise the reporting logic below doesn't work correctly.
- old_state = m_public_state.GetValue();
- m_public_state.SetValueNoLock(eStateStopped);
-
- // Now spin up the private state thread:
- StartPrivateStateThread(true);
- }
-
- thread->QueueThreadPlan(thread_plan_sp, false); // This used to pass "true" does that make sense?
-
- if (options.GetDebug())
- {
- // In this case, we aren't actually going to run, we just want to stop right away.
- // Flush this thread so we will refetch the stacks and show the correct backtrace.
- // FIXME: To make this prettier we should invent some stop reason for this, but that
- // is only cosmetic, and this functionality is only of use to lldb developers who can
- // live with not pretty...
- thread->Flush();
- return eExpressionStoppedForDebug;
- }
-
- ListenerSP listener_sp(Listener::MakeListener("lldb.process.listener.run-thread-plan"));
-
- lldb::EventSP event_to_broadcast_sp;
-
- {
- // This process event hijacker Hijacks the Public events and its destructor makes sure that the process events get
- // restored on exit to the function.
- //
- // If the event needs to propagate beyond the hijacker (e.g., the process exits during execution), then the event
- // is put into event_to_broadcast_sp for rebroadcasting.
-
- ProcessEventHijacker run_thread_plan_hijacker (*this, listener_sp);
-
- if (log)
- {
- StreamString s;
- thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
- log->Printf ("Process::RunThreadPlan(): Resuming thread %u - 0x%4.4" PRIx64 " to run thread plan \"%s\".",
- thread->GetIndexID(),
- thread->GetID(),
- s.GetData());
- }
-
- bool got_event;
- lldb::EventSP event_sp;
- lldb::StateType stop_state = lldb::eStateInvalid;
-
- bool before_first_timeout = true; // This is set to false the first time that we have to halt the target.
- bool do_resume = true;
- bool handle_running_event = true;
- const uint64_t default_one_thread_timeout_usec = 250000;
-
- // This is just for accounting:
- uint32_t num_resumes = 0;
-
- uint32_t timeout_usec = options.GetTimeoutUsec();
- uint32_t one_thread_timeout_usec;
- uint32_t all_threads_timeout_usec = 0;
-
- // If we are going to run all threads the whole time, or if we are only going to run one thread,
- // then we don't need the first timeout. So we set the final timeout, and pretend we are after the
- // first timeout already.
-
- if (!options.GetStopOthers() || !options.GetTryAllThreads())
- {
- before_first_timeout = false;
- one_thread_timeout_usec = 0;
- all_threads_timeout_usec = timeout_usec;
- }
- else
- {
- uint32_t option_one_thread_timeout = options.GetOneThreadTimeoutUsec();
-
- // If the overall wait is forever, then we only need to set the one thread timeout:
- if (timeout_usec == 0)
- {
- if (option_one_thread_timeout != 0)
- one_thread_timeout_usec = option_one_thread_timeout;
- else
- one_thread_timeout_usec = default_one_thread_timeout_usec;
- }
- else
- {
- // Otherwise, if the one thread timeout is set, make sure it isn't longer than the overall timeout,
- // and use it, otherwise use half the total timeout, bounded by the default_one_thread_timeout_usec.
- uint64_t computed_one_thread_timeout;
- if (option_one_thread_timeout != 0)
- {
- if (timeout_usec < option_one_thread_timeout)
- {
- diagnostic_manager.PutCString(
- eDiagnosticSeverityError,
- "RunThreadPlan called without one thread timeout greater than total timeout");
- return eExpressionSetupError;
- }
- computed_one_thread_timeout = option_one_thread_timeout;
- }
- else
- {
- computed_one_thread_timeout = timeout_usec / 2;
- if (computed_one_thread_timeout > default_one_thread_timeout_usec)
- computed_one_thread_timeout = default_one_thread_timeout_usec;
- }
- one_thread_timeout_usec = computed_one_thread_timeout;
- all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec;
- }
- }
-
- if (log)
- log->Printf ("Stop others: %u, try all: %u, before_first: %u, one thread: %" PRIu32 " - all threads: %" PRIu32 ".\n",
- options.GetStopOthers(),
- options.GetTryAllThreads(),
- before_first_timeout,
- one_thread_timeout_usec,
- all_threads_timeout_usec);
-
- // This isn't going to work if there are unfetched events on the queue.
- // Are there cases where we might want to run the remaining events here, and then try to
- // call the function? That's probably being too tricky for our own good.
-
- Event *other_events = listener_sp->PeekAtNextEvent();
- if (other_events != nullptr)
- {
- diagnostic_manager.PutCString(eDiagnosticSeverityError,
- "RunThreadPlan called with pending events on the queue.");
- return eExpressionSetupError;
- }
+ void GotEOF() override {}
- // We also need to make sure that the next event is delivered. We might be calling a function as part of
- // a thread plan, in which case the last delivered event could be the running event, and we don't want
- // event coalescing to cause us to lose OUR running event...
- ForceNextEventDelivery();
-
- // This while loop must exit out the bottom, there's cleanup that we need to do when we are done.
- // So don't call return anywhere within it.
-
-#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
- // It's pretty much impossible to write test cases for things like:
- // One thread timeout expires, I go to halt, but the process already stopped
- // on the function call stop breakpoint. Turning on this define will make us not
- // fetch the first event till after the halt. So if you run a quick function, it will have
- // completed, and the completion event will be waiting, when you interrupt for halt.
- // The expression evaluation should still succeed.
- bool miss_first_event = true;
-#endif
- TimeValue one_thread_timeout;
- TimeValue final_timeout;
- std::chrono::microseconds timeout = std::chrono::microseconds(0);
-
- while (true)
- {
- // We usually want to resume the process if we get to the top of the loop.
- // The only exception is if we get two running events with no intervening
- // stop, which can happen, we will just wait for then next stop event.
- if (log)
- log->Printf ("Top of while loop: do_resume: %i handle_running_event: %i before_first_timeout: %i.",
- do_resume,
- handle_running_event,
- before_first_timeout);
-
- if (do_resume || handle_running_event)
- {
- // Do the initial resume and wait for the running event before going further.
-
- if (do_resume)
- {
- num_resumes++;
- Error resume_error = PrivateResume();
- if (!resume_error.Success())
- {
- diagnostic_manager.Printf(eDiagnosticSeverityError,
- "couldn't resume inferior the %d time: \"%s\".", num_resumes,
- resume_error.AsCString());
- return_value = eExpressionSetupError;
- break;
- }
- }
+protected:
+ Process *m_process;
+ File m_read_file; // Read from this file (usually actual STDIN for LLDB
+ File m_write_file; // Write to this file (usually the master pty for getting
+ // io to debuggee)
+ Pipe m_pipe;
+ std::atomic<bool> m_is_running;
+};
- got_event = listener_sp->WaitForEvent(std::chrono::microseconds(500000), event_sp);
- if (!got_event)
- {
- if (log)
- log->Printf("Process::RunThreadPlan(): didn't get any event after resume %" PRIu32 ", exiting.",
- num_resumes);
+void Process::SetSTDIOFileDescriptor(int fd) {
+ // First set up the Read Thread for reading/handling process I/O
- diagnostic_manager.Printf(eDiagnosticSeverityError,
- "didn't get any event after resume %" PRIu32 ", exiting.", num_resumes);
- return_value = eExpressionSetupError;
- break;
- }
+ std::unique_ptr<ConnectionFileDescriptor> conn_ap(
+ new ConnectionFileDescriptor(fd, true));
- stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (conn_ap) {
+ m_stdio_communication.SetConnection(conn_ap.release());
+ if (m_stdio_communication.IsConnected()) {
+ m_stdio_communication.SetReadThreadBytesReceivedCallback(
+ STDIOReadThreadBytesReceived, this);
+ m_stdio_communication.StartReadThread();
- if (stop_state != eStateRunning)
- {
- bool restarted = false;
-
- if (stop_state == eStateStopped)
- {
- restarted = Process::ProcessEventData::GetRestartedFromEvent(event_sp.get());
- if (log)
- log->Printf("Process::RunThreadPlan(): didn't get running event after "
- "resume %d, got %s instead (restarted: %i, do_resume: %i, handle_running_event: %i).",
- num_resumes,
- StateAsCString(stop_state),
- restarted,
- do_resume,
- handle_running_event);
- }
+ // Now read thread is set up, set up input reader.
- if (restarted)
- {
- // This is probably an overabundance of caution, I don't think I should ever get a stopped & restarted
- // event here. But if I do, the best thing is to Halt and then get out of here.
- const bool clear_thread_plans = false;
- const bool use_run_lock = false;
- Halt(clear_thread_plans, use_run_lock);
- }
+ if (!m_process_input_reader)
+ m_process_input_reader.reset(new IOHandlerProcessSTDIO(this, fd));
+ }
+ }
+}
- diagnostic_manager.Printf(eDiagnosticSeverityError,
- "didn't get running event after initial resume, got %s instead.",
- StateAsCString(stop_state));
- return_value = eExpressionSetupError;
- break;
- }
+bool Process::ProcessIOHandlerIsActive() {
+ IOHandlerSP io_handler_sp(m_process_input_reader);
+ if (io_handler_sp)
+ return GetTarget().GetDebugger().IsTopIOHandler(io_handler_sp);
+ return false;
+}
+bool Process::PushProcessIOHandler() {
+ IOHandlerSP io_handler_sp(m_process_input_reader);
+ if (io_handler_sp) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s pushing IO handler", __FUNCTION__);
- if (log)
- log->PutCString ("Process::RunThreadPlan(): resuming succeeded.");
- // We need to call the function synchronously, so spin waiting for it to return.
- // If we get interrupted while executing, we're going to lose our context, and
- // won't be able to gather the result at this point.
- // We set the timeout AFTER the resume, since the resume takes some time and we
- // don't want to charge that to the timeout.
- }
- else
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): waiting for next event.");
- }
+ io_handler_sp->SetIsDone(false);
+ GetTarget().GetDebugger().PushIOHandler(io_handler_sp);
+ return true;
+ }
+ return false;
+}
- if (before_first_timeout)
- {
- if (options.GetTryAllThreads())
- timeout = std::chrono::microseconds(one_thread_timeout_usec);
- else
- timeout = std::chrono::microseconds(timeout_usec);
- }
- else
- {
- if (timeout_usec == 0)
- timeout = std::chrono::microseconds(0);
- else
- timeout = std::chrono::microseconds(all_threads_timeout_usec);
- }
+bool Process::PopProcessIOHandler() {
+ IOHandlerSP io_handler_sp(m_process_input_reader);
+ if (io_handler_sp)
+ return GetTarget().GetDebugger().PopIOHandler(io_handler_sp);
+ return false;
+}
- do_resume = true;
- handle_running_event = true;
+// The process needs to know about installed plug-ins
+void Process::SettingsInitialize() { Thread::SettingsInitialize(); }
- // Now wait for the process to stop again:
- event_sp.reset();
+void Process::SettingsTerminate() { Thread::SettingsTerminate(); }
- if (log)
- {
- if (timeout.count())
- {
- log->Printf(
- "Process::RunThreadPlan(): about to wait - now is %llu - endpoint is %llu",
- static_cast<unsigned long long>(std::chrono::system_clock::now().time_since_epoch().count()),
- static_cast<unsigned long long>(
- std::chrono::time_point<std::chrono::system_clock, std::chrono::microseconds>(timeout)
- .time_since_epoch()
- .count()));
- }
- else
- {
- log->Printf ("Process::RunThreadPlan(): about to wait forever.");
- }
- }
-
-#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
- // See comment above...
- if (miss_first_event)
- {
- usleep(1000);
- miss_first_event = false;
- got_event = false;
- }
- else
-#endif
- got_event = listener_sp->WaitForEvent(timeout, event_sp);
+namespace {
+// RestorePlanState is used to record the "is private", "is master" and "okay to
+// discard" fields of
+// the plan we are running, and reset it on Clean or on destruction.
+// It will only reset the state once, so you can call Clean and then monkey with
+// the state and it
+// won't get reset on you again.
- if (got_event)
- {
- if (event_sp)
- {
- bool keep_going = false;
- if (event_sp->GetType() == eBroadcastBitInterrupt)
- {
- const bool clear_thread_plans = false;
- const bool use_run_lock = false;
- Halt(clear_thread_plans, use_run_lock);
- return_value = eExpressionInterrupted;
- diagnostic_manager.PutCString(eDiagnosticSeverityRemark, "execution halted by user interrupt.");
- if (log)
- log->Printf(
- "Process::RunThreadPlan(): Got interrupted by eBroadcastBitInterrupted, exiting.");
- break;
- }
- else
- {
- stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- if (log)
- log->Printf("Process::RunThreadPlan(): in while loop, got event: %s.", StateAsCString(stop_state));
-
- switch (stop_state)
- {
- case lldb::eStateStopped:
- {
- // We stopped, figure out what we are going to do now.
- ThreadSP thread_sp = GetThreadList().FindThreadByIndexID (thread_idx_id);
- if (!thread_sp)
- {
- // Ooh, our thread has vanished. Unlikely that this was successful execution...
- if (log)
- log->Printf ("Process::RunThreadPlan(): execution completed but our thread (index-id=%u) has vanished.", thread_idx_id);
- return_value = eExpressionInterrupted;
- }
- else
- {
- // If we were restarted, we just need to go back up to fetch another event.
- if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
- {
- if (log)
- {
- log->Printf ("Process::RunThreadPlan(): Got a stop and restart, so we'll continue waiting.");
- }
- keep_going = true;
- do_resume = false;
- handle_running_event = true;
- }
- else
- {
- StopInfoSP stop_info_sp (thread_sp->GetStopInfo ());
- StopReason stop_reason = eStopReasonInvalid;
- if (stop_info_sp)
- stop_reason = stop_info_sp->GetStopReason();
-
- // FIXME: We only check if the stop reason is plan complete, should we make sure that
- // it is OUR plan that is complete?
- if (stop_reason == eStopReasonPlanComplete)
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): execution completed successfully.");
-
- // Restore the plan state so it will get reported as intended when we are done.
- thread_plan_restorer.Clean();
-
- return_value = eExpressionCompleted;
- }
- else
- {
- // Something restarted the target, so just wait for it to stop for real.
- if (stop_reason == eStopReasonBreakpoint)
- {
- if (log)
- log->Printf ("Process::RunThreadPlan() stopped for breakpoint: %s.", stop_info_sp->GetDescription());
- return_value = eExpressionHitBreakpoint;
- if (!options.DoesIgnoreBreakpoints())
- {
- // Restore the plan state and then force Private to false. We are
- // going to stop because of this plan so we need it to become a public
- // plan or it won't report correctly when we continue to its termination
- // later on.
- thread_plan_restorer.Clean();
- if (thread_plan_sp)
- thread_plan_sp->SetPrivate(false);
- event_to_broadcast_sp = event_sp;
- }
- }
- else
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): thread plan didn't successfully complete.");
- if (!options.DoesUnwindOnError())
- event_to_broadcast_sp = event_sp;
- return_value = eExpressionInterrupted;
- }
- }
- }
- }
- }
- break;
-
- case lldb::eStateRunning:
- // This shouldn't really happen, but sometimes we do get two running events without an
- // intervening stop, and in that case we should just go back to waiting for the stop.
- do_resume = false;
- keep_going = true;
- handle_running_event = false;
- break;
-
- default:
- if (log)
- log->Printf("Process::RunThreadPlan(): execution stopped with unexpected state: %s.", StateAsCString(stop_state));
-
- if (stop_state == eStateExited)
- event_to_broadcast_sp = event_sp;
-
- diagnostic_manager.PutCString(eDiagnosticSeverityError,
- "execution stopped with unexpected state.");
- return_value = eExpressionInterrupted;
- break;
- }
- }
+class RestorePlanState {
+public:
+ RestorePlanState(lldb::ThreadPlanSP thread_plan_sp)
+ : m_thread_plan_sp(thread_plan_sp), m_already_reset(false) {
+ if (m_thread_plan_sp) {
+ m_private = m_thread_plan_sp->GetPrivate();
+ m_is_master = m_thread_plan_sp->IsMasterPlan();
+ m_okay_to_discard = m_thread_plan_sp->OkayToDiscard();
+ }
+ }
+
+ ~RestorePlanState() { Clean(); }
+
+ void Clean() {
+ if (!m_already_reset && m_thread_plan_sp) {
+ m_already_reset = true;
+ m_thread_plan_sp->SetPrivate(m_private);
+ m_thread_plan_sp->SetIsMasterPlan(m_is_master);
+ m_thread_plan_sp->SetOkayToDiscard(m_okay_to_discard);
+ }
+ }
+
+private:
+ lldb::ThreadPlanSP m_thread_plan_sp;
+ bool m_already_reset;
+ bool m_private;
+ bool m_is_master;
+ bool m_okay_to_discard;
+};
+} // anonymous namespace
- if (keep_going)
- continue;
- else
- break;
- }
- else
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): got_event was true, but the event pointer was null. How odd...");
- return_value = eExpressionInterrupted;
- break;
- }
- }
- else
- {
- // If we didn't get an event that means we've timed out...
- // We will interrupt the process here. Depending on what we were asked to do we will
- // either exit, or try with all threads running for the same timeout.
-
- if (log) {
- if (options.GetTryAllThreads())
- {
- if (before_first_timeout)
- {
- if (timeout_usec != 0)
- {
- log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
- "running for %" PRIu32 " usec with all threads enabled.",
- all_threads_timeout_usec);
- }
- else
- {
- log->Printf ("Process::RunThreadPlan(): Running function with one thread timeout timed out, "
- "running forever with all threads enabled.");
- }
- }
- else
- log->Printf ("Process::RunThreadPlan(): Restarting function with all threads enabled "
- "and timeout: %u timed out, abandoning execution.",
- timeout_usec);
- }
- else
- log->Printf ("Process::RunThreadPlan(): Running function with timeout: %u timed out, "
- "abandoning execution.",
- timeout_usec);
- }
+ExpressionResults
+Process::RunThreadPlan(ExecutionContext &exe_ctx,
+ lldb::ThreadPlanSP &thread_plan_sp,
+ const EvaluateExpressionOptions &options,
+ DiagnosticManager &diagnostic_manager) {
+ ExpressionResults return_value = eExpressionSetupError;
+
+ std::lock_guard<std::mutex> run_thread_plan_locker(m_run_thread_plan_lock);
+
+ if (!thread_plan_sp) {
+ diagnostic_manager.PutCString(
+ eDiagnosticSeverityError,
+ "RunThreadPlan called with empty thread plan.");
+ return eExpressionSetupError;
+ }
+
+ if (!thread_plan_sp->ValidatePlan(nullptr)) {
+ diagnostic_manager.PutCString(
+ eDiagnosticSeverityError,
+ "RunThreadPlan called with an invalid thread plan.");
+ return eExpressionSetupError;
+ }
+
+ if (exe_ctx.GetProcessPtr() != this) {
+ diagnostic_manager.PutCString(eDiagnosticSeverityError,
+ "RunThreadPlan called on wrong process.");
+ return eExpressionSetupError;
+ }
+
+ Thread *thread = exe_ctx.GetThreadPtr();
+ if (thread == nullptr) {
+ diagnostic_manager.PutCString(eDiagnosticSeverityError,
+ "RunThreadPlan called with invalid thread.");
+ return eExpressionSetupError;
+ }
+
+ // We need to change some of the thread plan attributes for the thread plan
+ // runner. This will restore them
+ // when we are done:
+
+ RestorePlanState thread_plan_restorer(thread_plan_sp);
+
+ // We rely on the thread plan we are running returning "PlanCompleted" if when
+ // it successfully completes.
+ // For that to be true the plan can't be private - since private plans
+ // suppress themselves in the
+ // GetCompletedPlan call.
+
+ thread_plan_sp->SetPrivate(false);
+
+ // The plans run with RunThreadPlan also need to be terminal master plans or
+ // when they are done we will end
+ // up asking the plan above us whether we should stop, which may give the
+ // wrong answer.
+
+ thread_plan_sp->SetIsMasterPlan(true);
+ thread_plan_sp->SetOkayToDiscard(false);
+
+ if (m_private_state.GetValue() != eStateStopped) {
+ diagnostic_manager.PutCString(
+ eDiagnosticSeverityError,
+ "RunThreadPlan called while the private state was not stopped.");
+ return eExpressionSetupError;
+ }
+
+ // Save the thread & frame from the exe_ctx for restoration after we run
+ const uint32_t thread_idx_id = thread->GetIndexID();
+ StackFrameSP selected_frame_sp = thread->GetSelectedFrame();
+ if (!selected_frame_sp) {
+ thread->SetSelectedFrame(nullptr);
+ selected_frame_sp = thread->GetSelectedFrame();
+ if (!selected_frame_sp) {
+ diagnostic_manager.Printf(
+ eDiagnosticSeverityError,
+ "RunThreadPlan called without a selected frame on thread %d",
+ thread_idx_id);
+ return eExpressionSetupError;
+ }
+ }
+
+ StackID ctx_frame_id = selected_frame_sp->GetStackID();
+
+ // N.B. Running the target may unset the currently selected thread and frame.
+ // We don't want to do that either,
+ // so we should arrange to reset them as well.
+
+ lldb::ThreadSP selected_thread_sp = GetThreadList().GetSelectedThread();
+
+ uint32_t selected_tid;
+ StackID selected_stack_id;
+ if (selected_thread_sp) {
+ selected_tid = selected_thread_sp->GetIndexID();
+ selected_stack_id = selected_thread_sp->GetSelectedFrame()->GetStackID();
+ } else {
+ selected_tid = LLDB_INVALID_THREAD_ID;
+ }
+
+ HostThread backup_private_state_thread;
+ lldb::StateType old_state = eStateInvalid;
+ lldb::ThreadPlanSP stopper_base_plan_sp;
+
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STEP |
+ LIBLLDB_LOG_PROCESS));
+ if (m_private_state_thread.EqualsThread(Host::GetCurrentThread())) {
+ // Yikes, we are running on the private state thread! So we can't wait for
+ // public events on this thread, since
+ // we are the thread that is generating public events.
+ // The simplest thing to do is to spin up a temporary thread to handle
+ // private state thread events while
+ // we are fielding public events here.
+ if (log)
+ log->Printf("Running thread plan on private state thread, spinning up "
+ "another state thread to handle the events.");
- // It is possible that between the time we issued the Halt, and we get around to calling Halt the target
- // could have stopped. That's fine, Halt will figure that out and send the appropriate Stopped event.
- // BUT it is also possible that we stopped & restarted (e.g. hit a signal with "stop" set to false.) In
- // that case, we'll get the stopped & restarted event, and we should go back to waiting for the Halt's
- // stopped event. That's what this while loop does.
-
- bool back_to_top = true;
- uint32_t try_halt_again = 0;
- bool do_halt = true;
- const uint32_t num_retries = 5;
- while (try_halt_again < num_retries)
- {
- Error halt_error;
- if (do_halt)
- {
- if (log)
- log->Printf ("Process::RunThreadPlan(): Running Halt.");
- const bool clear_thread_plans = false;
- const bool use_run_lock = false;
- Halt(clear_thread_plans, use_run_lock);
- }
- if (halt_error.Success())
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): Halt succeeded.");
-
- got_event = listener_sp->WaitForEvent(std::chrono::microseconds(500000), event_sp);
-
- if (got_event)
- {
- stop_state = Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- if (log)
- {
- log->Printf ("Process::RunThreadPlan(): Stopped with event: %s", StateAsCString(stop_state));
- if (stop_state == lldb::eStateStopped
- && Process::ProcessEventData::GetInterruptedFromEvent(event_sp.get()))
- log->PutCString (" Event was the Halt interruption event.");
- }
-
- if (stop_state == lldb::eStateStopped)
- {
- // Between the time we initiated the Halt and the time we delivered it, the process could have
- // already finished its job. Check that here:
-
- if (thread->IsThreadPlanDone (thread_plan_sp.get()))
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): Even though we timed out, the call plan was done. "
- "Exiting wait loop.");
- return_value = eExpressionCompleted;
- back_to_top = false;
- break;
- }
-
- if (Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): Went to halt but got a restarted event, there must be an un-restarted stopped event so try again... "
- "Exiting wait loop.");
- try_halt_again++;
- do_halt = false;
- continue;
- }
-
- if (!options.GetTryAllThreads())
- {
- if (log)
- log->PutCString ("Process::RunThreadPlan(): try_all_threads was false, we stopped so now we're quitting.");
- return_value = eExpressionInterrupted;
- back_to_top = false;
- break;
- }
-
- if (before_first_timeout)
- {
- // Set all the other threads to run, and return to the top of the loop, which will continue;
- before_first_timeout = false;
- thread_plan_sp->SetStopOthers (false);
- if (log)
- log->PutCString ("Process::RunThreadPlan(): about to resume.");
-
- back_to_top = true;
- break;
- }
- else
- {
- // Running all threads failed, so return Interrupted.
- if (log)
- log->PutCString("Process::RunThreadPlan(): running all threads timed out.");
- return_value = eExpressionInterrupted;
- back_to_top = false;
- break;
- }
- }
- }
- else
- { if (log)
- log->PutCString("Process::RunThreadPlan(): halt said it succeeded, but I got no event. "
- "I'm getting out of here passing Interrupted.");
- return_value = eExpressionInterrupted;
- back_to_top = false;
- break;
- }
- }
- else
- {
- try_halt_again++;
- continue;
- }
- }
+ backup_private_state_thread = m_private_state_thread;
- if (!back_to_top || try_halt_again > num_retries)
- break;
- else
- continue;
- }
- } // END WAIT LOOP
+ // One other bit of business: we want to run just this thread plan and
+ // anything it pushes, and then stop,
+ // returning control here.
+ // But in the normal course of things, the plan above us on the stack would
+ // be given a shot at the stop
+ // event before deciding to stop, and we don't want that. So we insert a
+ // "stopper" base plan on the stack
+ // before the plan we want to run. Since base plans always stop and return
+ // control to the user, that will
+ // do just what we want.
+ stopper_base_plan_sp.reset(new ThreadPlanBase(*thread));
+ thread->QueueThreadPlan(stopper_base_plan_sp, false);
+ // Have to make sure our public state is stopped, since otherwise the
+ // reporting logic below doesn't work correctly.
+ old_state = m_public_state.GetValue();
+ m_public_state.SetValueNoLock(eStateStopped);
+
+ // Now spin up the private state thread:
+ StartPrivateStateThread(true);
+ }
+
+ thread->QueueThreadPlan(
+ thread_plan_sp, false); // This used to pass "true" does that make sense?
+
+ if (options.GetDebug()) {
+ // In this case, we aren't actually going to run, we just want to stop right
+ // away.
+ // Flush this thread so we will refetch the stacks and show the correct
+ // backtrace.
+ // FIXME: To make this prettier we should invent some stop reason for this,
+ // but that
+ // is only cosmetic, and this functionality is only of use to lldb
+ // developers who can
+ // live with not pretty...
+ thread->Flush();
+ return eExpressionStoppedForDebug;
+ }
+
+ ListenerSP listener_sp(
+ Listener::MakeListener("lldb.process.listener.run-thread-plan"));
+
+ lldb::EventSP event_to_broadcast_sp;
+
+ {
+ // This process event hijacker Hijacks the Public events and its destructor
+ // makes sure that the process events get
+ // restored on exit to the function.
+ //
+ // If the event needs to propagate beyond the hijacker (e.g., the process
+ // exits during execution), then the event
+ // is put into event_to_broadcast_sp for rebroadcasting.
+
+ ProcessEventHijacker run_thread_plan_hijacker(*this, listener_sp);
+
+ if (log) {
+ StreamString s;
+ thread_plan_sp->GetDescription(&s, lldb::eDescriptionLevelVerbose);
+ log->Printf("Process::RunThreadPlan(): Resuming thread %u - 0x%4.4" PRIx64
+ " to run thread plan \"%s\".",
+ thread->GetIndexID(), thread->GetID(), s.GetData());
+ }
+
+ bool got_event;
+ lldb::EventSP event_sp;
+ lldb::StateType stop_state = lldb::eStateInvalid;
+
+ bool before_first_timeout = true; // This is set to false the first time
+ // that we have to halt the target.
+ bool do_resume = true;
+ bool handle_running_event = true;
+ const uint64_t default_one_thread_timeout_usec = 250000;
+
+ // This is just for accounting:
+ uint32_t num_resumes = 0;
+
+ uint32_t timeout_usec = options.GetTimeoutUsec();
+ uint32_t one_thread_timeout_usec;
+ uint32_t all_threads_timeout_usec = 0;
+
+ // If we are going to run all threads the whole time, or if we are only
+ // going to run one thread,
+ // then we don't need the first timeout. So we set the final timeout, and
+ // pretend we are after the
+ // first timeout already.
+
+ if (!options.GetStopOthers() || !options.GetTryAllThreads()) {
+ before_first_timeout = false;
+ one_thread_timeout_usec = 0;
+ all_threads_timeout_usec = timeout_usec;
+ } else {
+ uint32_t option_one_thread_timeout = options.GetOneThreadTimeoutUsec();
+
+ // If the overall wait is forever, then we only need to set the one thread
+ // timeout:
+ if (timeout_usec == 0) {
+ if (option_one_thread_timeout != 0)
+ one_thread_timeout_usec = option_one_thread_timeout;
+ else
+ one_thread_timeout_usec = default_one_thread_timeout_usec;
+ } else {
+ // Otherwise, if the one thread timeout is set, make sure it isn't
+ // longer than the overall timeout,
+ // and use it, otherwise use half the total timeout, bounded by the
+ // default_one_thread_timeout_usec.
+ uint64_t computed_one_thread_timeout;
+ if (option_one_thread_timeout != 0) {
+ if (timeout_usec < option_one_thread_timeout) {
+ diagnostic_manager.PutCString(eDiagnosticSeverityError,
+ "RunThreadPlan called without one "
+ "thread timeout greater than total "
+ "timeout");
+ return eExpressionSetupError;
+ }
+ computed_one_thread_timeout = option_one_thread_timeout;
+ } else {
+ computed_one_thread_timeout = timeout_usec / 2;
+ if (computed_one_thread_timeout > default_one_thread_timeout_usec)
+ computed_one_thread_timeout = default_one_thread_timeout_usec;
+ }
+ one_thread_timeout_usec = computed_one_thread_timeout;
+ all_threads_timeout_usec = timeout_usec - one_thread_timeout_usec;
+ }
+ }
- // If we had to start up a temporary private state thread to run this thread plan, shut it down now.
- if (backup_private_state_thread.IsJoinable())
- {
- StopPrivateStateThread();
- Error error;
- m_private_state_thread = backup_private_state_thread;
- if (stopper_base_plan_sp)
- {
- thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp);
- }
- if (old_state != eStateInvalid)
- m_public_state.SetValueNoLock(old_state);
+ if (log)
+ log->Printf(
+ "Stop others: %u, try all: %u, before_first: %u, one thread: %" PRIu32
+ " - all threads: %" PRIu32 ".\n",
+ options.GetStopOthers(), options.GetTryAllThreads(),
+ before_first_timeout, one_thread_timeout_usec,
+ all_threads_timeout_usec);
+
+ // This isn't going to work if there are unfetched events on the queue.
+ // Are there cases where we might want to run the remaining events here, and
+ // then try to
+ // call the function? That's probably being too tricky for our own good.
+
+ Event *other_events = listener_sp->PeekAtNextEvent();
+ if (other_events != nullptr) {
+ diagnostic_manager.PutCString(
+ eDiagnosticSeverityError,
+ "RunThreadPlan called with pending events on the queue.");
+ return eExpressionSetupError;
+ }
+
+ // We also need to make sure that the next event is delivered. We might be
+ // calling a function as part of
+ // a thread plan, in which case the last delivered event could be the
+ // running event, and we don't want
+ // event coalescing to cause us to lose OUR running event...
+ ForceNextEventDelivery();
+
+// This while loop must exit out the bottom, there's cleanup that we need to do
+// when we are done.
+// So don't call return anywhere within it.
+
+#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
+ // It's pretty much impossible to write test cases for things like:
+ // One thread timeout expires, I go to halt, but the process already stopped
+ // on the function call stop breakpoint. Turning on this define will make
+ // us not
+ // fetch the first event till after the halt. So if you run a quick
+ // function, it will have
+ // completed, and the completion event will be waiting, when you interrupt
+ // for halt.
+ // The expression evaluation should still succeed.
+ bool miss_first_event = true;
+#endif
+ TimeValue one_thread_timeout;
+ TimeValue final_timeout;
+ std::chrono::microseconds timeout = std::chrono::microseconds(0);
+
+ while (true) {
+ // We usually want to resume the process if we get to the top of the loop.
+ // The only exception is if we get two running events with no intervening
+ // stop, which can happen, we will just wait for then next stop event.
+ if (log)
+ log->Printf("Top of while loop: do_resume: %i handle_running_event: %i "
+ "before_first_timeout: %i.",
+ do_resume, handle_running_event, before_first_timeout);
+
+ if (do_resume || handle_running_event) {
+ // Do the initial resume and wait for the running event before going
+ // further.
+
+ if (do_resume) {
+ num_resumes++;
+ Error resume_error = PrivateResume();
+ if (!resume_error.Success()) {
+ diagnostic_manager.Printf(
+ eDiagnosticSeverityError,
+ "couldn't resume inferior the %d time: \"%s\".", num_resumes,
+ resume_error.AsCString());
+ return_value = eExpressionSetupError;
+ break;
+ }
+ }
+
+ got_event = listener_sp->WaitForEvent(std::chrono::microseconds(500000),
+ event_sp);
+ if (!got_event) {
+ if (log)
+ log->Printf("Process::RunThreadPlan(): didn't get any event after "
+ "resume %" PRIu32 ", exiting.",
+ num_resumes);
+
+ diagnostic_manager.Printf(eDiagnosticSeverityError,
+ "didn't get any event after resume %" PRIu32
+ ", exiting.",
+ num_resumes);
+ return_value = eExpressionSetupError;
+ break;
}
- if (return_value != eExpressionCompleted && log)
- {
- // Print a backtrace into the log so we can figure out where we are:
- StreamString s;
- s.PutCString("Thread state after unsuccessful completion: \n");
- thread->GetStackFrameStatus (s,
- 0,
- UINT32_MAX,
- true,
- UINT32_MAX);
- log->PutCString(s.GetData());
+ stop_state =
+ Process::ProcessEventData::GetStateFromEvent(event_sp.get());
- }
- // Restore the thread state if we are going to discard the plan execution. There are three cases where this
- // could happen:
- // 1) The execution successfully completed
- // 2) We hit a breakpoint, and ignore_breakpoints was true
- // 3) We got some other error, and discard_on_error was true
- bool should_unwind = (return_value == eExpressionInterrupted && options.DoesUnwindOnError())
- || (return_value == eExpressionHitBreakpoint && options.DoesIgnoreBreakpoints());
-
- if (return_value == eExpressionCompleted
- || should_unwind)
- {
- thread_plan_sp->RestoreThreadState();
- }
+ if (stop_state != eStateRunning) {
+ bool restarted = false;
- // Now do some processing on the results of the run:
- if (return_value == eExpressionInterrupted || return_value == eExpressionHitBreakpoint)
- {
+ if (stop_state == eStateStopped) {
+ restarted = Process::ProcessEventData::GetRestartedFromEvent(
+ event_sp.get());
if (log)
- {
- StreamString s;
- if (event_sp)
- event_sp->Dump (&s);
- else
- {
- log->PutCString ("Process::RunThreadPlan(): Stop event that interrupted us is NULL.");
- }
-
- StreamString ts;
+ log->Printf(
+ "Process::RunThreadPlan(): didn't get running event after "
+ "resume %d, got %s instead (restarted: %i, do_resume: %i, "
+ "handle_running_event: %i).",
+ num_resumes, StateAsCString(stop_state), restarted, do_resume,
+ handle_running_event);
+ }
+
+ if (restarted) {
+ // This is probably an overabundance of caution, I don't think I
+ // should ever get a stopped & restarted
+ // event here. But if I do, the best thing is to Halt and then get
+ // out of here.
+ const bool clear_thread_plans = false;
+ const bool use_run_lock = false;
+ Halt(clear_thread_plans, use_run_lock);
+ }
+
+ diagnostic_manager.Printf(
+ eDiagnosticSeverityError,
+ "didn't get running event after initial resume, got %s instead.",
+ StateAsCString(stop_state));
+ return_value = eExpressionSetupError;
+ break;
+ }
- const char *event_explanation = nullptr;
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): resuming succeeded.");
+ // We need to call the function synchronously, so spin waiting for it to
+ // return.
+ // If we get interrupted while executing, we're going to lose our
+ // context, and
+ // won't be able to gather the result at this point.
+ // We set the timeout AFTER the resume, since the resume takes some time
+ // and we
+ // don't want to charge that to the timeout.
+ } else {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): waiting for next event.");
+ }
- do
- {
- if (!event_sp)
- {
- event_explanation = "<no event>";
- break;
- }
- else if (event_sp->GetType() == eBroadcastBitInterrupt)
- {
- event_explanation = "<user interrupt>";
- break;
- }
- else
- {
- const Process::ProcessEventData *event_data = Process::ProcessEventData::GetEventDataFromEvent (event_sp.get());
-
- if (!event_data)
- {
- event_explanation = "<no event data>";
- break;
- }
-
- Process *process = event_data->GetProcessSP().get();
-
- if (!process)
- {
- event_explanation = "<no process>";
- break;
- }
-
- ThreadList &thread_list = process->GetThreadList();
-
- uint32_t num_threads = thread_list.GetSize();
- uint32_t thread_index;
-
- ts.Printf("<%u threads> ", num_threads);
-
- for (thread_index = 0;
- thread_index < num_threads;
- ++thread_index)
- {
- Thread *thread = thread_list.GetThreadAtIndex(thread_index).get();
-
- if (!thread)
- {
- ts.Printf("<?> ");
- continue;
- }
-
- ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID());
- RegisterContext *register_context = thread->GetRegisterContext().get();
-
- if (register_context)
- ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC());
- else
- ts.Printf("[ip unknown] ");
-
- // Show the private stop info here, the public stop info will be from the last natural stop.
- lldb::StopInfoSP stop_info_sp = thread->GetPrivateStopInfo();
- if (stop_info_sp)
- {
- const char *stop_desc = stop_info_sp->GetDescription();
- if (stop_desc)
- ts.PutCString (stop_desc);
- }
- ts.Printf(">");
- }
+ if (before_first_timeout) {
+ if (options.GetTryAllThreads())
+ timeout = std::chrono::microseconds(one_thread_timeout_usec);
+ else
+ timeout = std::chrono::microseconds(timeout_usec);
+ } else {
+ if (timeout_usec == 0)
+ timeout = std::chrono::microseconds(0);
+ else
+ timeout = std::chrono::microseconds(all_threads_timeout_usec);
+ }
- event_explanation = ts.GetData();
- }
- } while (0);
+ do_resume = true;
+ handle_running_event = true;
- if (event_explanation)
- log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s", s.GetData(), event_explanation);
- else
- log->Printf("Process::RunThreadPlan(): execution interrupted: %s", s.GetData());
- }
+ // Now wait for the process to stop again:
+ event_sp.reset();
- if (should_unwind)
- {
- if (log)
- log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - discarding thread plans up to %p.",
- static_cast<void*>(thread_plan_sp.get()));
- thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
- }
- else
- {
- if (log)
- log->Printf ("Process::RunThreadPlan: ExecutionInterrupted - for plan: %p not discarding.",
- static_cast<void*>(thread_plan_sp.get()));
- }
+ if (log) {
+ if (timeout.count()) {
+ log->Printf(
+ "Process::RunThreadPlan(): about to wait - now is %llu - "
+ "endpoint is %llu",
+ static_cast<unsigned long long>(
+ std::chrono::system_clock::now().time_since_epoch().count()),
+ static_cast<unsigned long long>(
+ std::chrono::time_point<std::chrono::system_clock,
+ std::chrono::microseconds>(timeout)
+ .time_since_epoch()
+ .count()));
+ } else {
+ log->Printf("Process::RunThreadPlan(): about to wait forever.");
}
- else if (return_value == eExpressionSetupError)
- {
- if (log)
- log->PutCString("Process::RunThreadPlan(): execution set up error.");
+ }
- if (options.DoesUnwindOnError())
- {
- thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
- }
- }
- else
- {
- if (thread->IsThreadPlanDone (thread_plan_sp.get()))
- {
- if (log)
- log->PutCString("Process::RunThreadPlan(): thread plan is done");
- return_value = eExpressionCompleted;
- }
- else if (thread->WasThreadPlanDiscarded (thread_plan_sp.get()))
- {
- if (log)
- log->PutCString("Process::RunThreadPlan(): thread plan was discarded");
- return_value = eExpressionDiscarded;
- }
- else
- {
+#ifdef LLDB_RUN_THREAD_HALT_WITH_EVENT
+ // See comment above...
+ if (miss_first_event) {
+ usleep(1000);
+ miss_first_event = false;
+ got_event = false;
+ } else
+#endif
+ got_event = listener_sp->WaitForEvent(timeout, event_sp);
+
+ if (got_event) {
+ if (event_sp) {
+ bool keep_going = false;
+ if (event_sp->GetType() == eBroadcastBitInterrupt) {
+ const bool clear_thread_plans = false;
+ const bool use_run_lock = false;
+ Halt(clear_thread_plans, use_run_lock);
+ return_value = eExpressionInterrupted;
+ diagnostic_manager.PutCString(
+ eDiagnosticSeverityRemark,
+ "execution halted by user interrupt.");
+ if (log)
+ log->Printf("Process::RunThreadPlan(): Got interrupted by "
+ "eBroadcastBitInterrupted, exiting.");
+ break;
+ } else {
+ stop_state =
+ Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (log)
+ log->Printf(
+ "Process::RunThreadPlan(): in while loop, got event: %s.",
+ StateAsCString(stop_state));
+
+ switch (stop_state) {
+ case lldb::eStateStopped: {
+ // We stopped, figure out what we are going to do now.
+ ThreadSP thread_sp =
+ GetThreadList().FindThreadByIndexID(thread_idx_id);
+ if (!thread_sp) {
+ // Ooh, our thread has vanished. Unlikely that this was
+ // successful execution...
if (log)
- log->PutCString("Process::RunThreadPlan(): thread plan stopped in mid course");
- if (options.DoesUnwindOnError() && thread_plan_sp)
- {
+ log->Printf("Process::RunThreadPlan(): execution completed "
+ "but our thread (index-id=%u) has vanished.",
+ thread_idx_id);
+ return_value = eExpressionInterrupted;
+ } else {
+ // If we were restarted, we just need to go back up to fetch
+ // another event.
+ if (Process::ProcessEventData::GetRestartedFromEvent(
+ event_sp.get())) {
+ if (log) {
+ log->Printf("Process::RunThreadPlan(): Got a stop and "
+ "restart, so we'll continue waiting.");
+ }
+ keep_going = true;
+ do_resume = false;
+ handle_running_event = true;
+ } else {
+ StopInfoSP stop_info_sp(thread_sp->GetStopInfo());
+ StopReason stop_reason = eStopReasonInvalid;
+ if (stop_info_sp)
+ stop_reason = stop_info_sp->GetStopReason();
+
+ // FIXME: We only check if the stop reason is plan complete,
+ // should we make sure that
+ // it is OUR plan that is complete?
+ if (stop_reason == eStopReasonPlanComplete) {
if (log)
- log->PutCString("Process::RunThreadPlan(): discarding thread plan 'cause unwind_on_error is set.");
- thread->DiscardThreadPlansUpToPlan (thread_plan_sp);
+ log->PutCString("Process::RunThreadPlan(): execution "
+ "completed successfully.");
+
+ // Restore the plan state so it will get reported as
+ // intended when we are done.
+ thread_plan_restorer.Clean();
+
+ return_value = eExpressionCompleted;
+ } else {
+ // Something restarted the target, so just wait for it to
+ // stop for real.
+ if (stop_reason == eStopReasonBreakpoint) {
+ if (log)
+ log->Printf("Process::RunThreadPlan() stopped for "
+ "breakpoint: %s.",
+ stop_info_sp->GetDescription());
+ return_value = eExpressionHitBreakpoint;
+ if (!options.DoesIgnoreBreakpoints()) {
+ // Restore the plan state and then force Private to
+ // false. We are
+ // going to stop because of this plan so we need it to
+ // become a public
+ // plan or it won't report correctly when we continue to
+ // its termination
+ // later on.
+ thread_plan_restorer.Clean();
+ if (thread_plan_sp)
+ thread_plan_sp->SetPrivate(false);
+ event_to_broadcast_sp = event_sp;
+ }
+ } else {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): thread plan "
+ "didn't successfully complete.");
+ if (!options.DoesUnwindOnError())
+ event_to_broadcast_sp = event_sp;
+ return_value = eExpressionInterrupted;
+ }
+ }
}
+ }
+ } break;
+
+ case lldb::eStateRunning:
+ // This shouldn't really happen, but sometimes we do get two
+ // running events without an
+ // intervening stop, and in that case we should just go back to
+ // waiting for the stop.
+ do_resume = false;
+ keep_going = true;
+ handle_running_event = false;
+ break;
+
+ default:
+ if (log)
+ log->Printf("Process::RunThreadPlan(): execution stopped with "
+ "unexpected state: %s.",
+ StateAsCString(stop_state));
+
+ if (stop_state == eStateExited)
+ event_to_broadcast_sp = event_sp;
+
+ diagnostic_manager.PutCString(
+ eDiagnosticSeverityError,
+ "execution stopped with unexpected state.");
+ return_value = eExpressionInterrupted;
+ break;
}
- }
+ }
- // Thread we ran the function in may have gone away because we ran the target
- // Check that it's still there, and if it is put it back in the context. Also restore the
- // frame in the context if it is still present.
- thread = GetThreadList().FindThreadByIndexID(thread_idx_id, true).get();
- if (thread)
- {
- exe_ctx.SetFrameSP (thread->GetFrameWithStackID (ctx_frame_id));
- }
+ if (keep_going)
+ continue;
+ else
+ break;
+ } else {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): got_event was true, but "
+ "the event pointer was null. How odd...");
+ return_value = eExpressionInterrupted;
+ break;
+ }
+ } else {
+ // If we didn't get an event that means we've timed out...
+ // We will interrupt the process here. Depending on what we were asked
+ // to do we will
+ // either exit, or try with all threads running for the same timeout.
+
+ if (log) {
+ if (options.GetTryAllThreads()) {
+ if (before_first_timeout) {
+ if (timeout_usec != 0) {
+ log->Printf("Process::RunThreadPlan(): Running function with "
+ "one thread timeout timed out, "
+ "running for %" PRIu32
+ " usec with all threads enabled.",
+ all_threads_timeout_usec);
+ } else {
+ log->Printf("Process::RunThreadPlan(): Running function with "
+ "one thread timeout timed out, "
+ "running forever with all threads enabled.");
+ }
+ } else
+ log->Printf("Process::RunThreadPlan(): Restarting function with "
+ "all threads enabled "
+ "and timeout: %u timed out, abandoning execution.",
+ timeout_usec);
+ } else
+ log->Printf("Process::RunThreadPlan(): Running function with "
+ "timeout: %u timed out, "
+ "abandoning execution.",
+ timeout_usec);
+ }
+
+ // It is possible that between the time we issued the Halt, and we get
+ // around to calling Halt the target
+ // could have stopped. That's fine, Halt will figure that out and send
+ // the appropriate Stopped event.
+ // BUT it is also possible that we stopped & restarted (e.g. hit a
+ // signal with "stop" set to false.) In
+ // that case, we'll get the stopped & restarted event, and we should go
+ // back to waiting for the Halt's
+ // stopped event. That's what this while loop does.
+
+ bool back_to_top = true;
+ uint32_t try_halt_again = 0;
+ bool do_halt = true;
+ const uint32_t num_retries = 5;
+ while (try_halt_again < num_retries) {
+ Error halt_error;
+ if (do_halt) {
+ if (log)
+ log->Printf("Process::RunThreadPlan(): Running Halt.");
+ const bool clear_thread_plans = false;
+ const bool use_run_lock = false;
+ Halt(clear_thread_plans, use_run_lock);
+ }
+ if (halt_error.Success()) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): Halt succeeded.");
- // Also restore the current process'es selected frame & thread, since this function calling may
- // be done behind the user's back.
+ got_event = listener_sp->WaitForEvent(
+ std::chrono::microseconds(500000), event_sp);
- if (selected_tid != LLDB_INVALID_THREAD_ID)
- {
- if (GetThreadList().SetSelectedThreadByIndexID (selected_tid) && selected_stack_id.IsValid())
- {
- // We were able to restore the selected thread, now restore the frame:
- std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex());
- StackFrameSP old_frame_sp = GetThreadList().GetSelectedThread()->GetFrameWithStackID(selected_stack_id);
- if (old_frame_sp)
- GetThreadList().GetSelectedThread()->SetSelectedFrame(old_frame_sp.get());
+ if (got_event) {
+ stop_state =
+ Process::ProcessEventData::GetStateFromEvent(event_sp.get());
+ if (log) {
+ log->Printf("Process::RunThreadPlan(): Stopped with event: %s",
+ StateAsCString(stop_state));
+ if (stop_state == lldb::eStateStopped &&
+ Process::ProcessEventData::GetInterruptedFromEvent(
+ event_sp.get()))
+ log->PutCString(" Event was the Halt interruption event.");
+ }
+
+ if (stop_state == lldb::eStateStopped) {
+ // Between the time we initiated the Halt and the time we
+ // delivered it, the process could have
+ // already finished its job. Check that here:
+
+ if (thread->IsThreadPlanDone(thread_plan_sp.get())) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): Even though we "
+ "timed out, the call plan was done. "
+ "Exiting wait loop.");
+ return_value = eExpressionCompleted;
+ back_to_top = false;
+ break;
+ }
+
+ if (Process::ProcessEventData::GetRestartedFromEvent(
+ event_sp.get())) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): Went to halt "
+ "but got a restarted event, there must be "
+ "an un-restarted stopped event so try "
+ "again... "
+ "Exiting wait loop.");
+ try_halt_again++;
+ do_halt = false;
+ continue;
+ }
+
+ if (!options.GetTryAllThreads()) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): try_all_threads "
+ "was false, we stopped so now we're "
+ "quitting.");
+ return_value = eExpressionInterrupted;
+ back_to_top = false;
+ break;
+ }
+
+ if (before_first_timeout) {
+ // Set all the other threads to run, and return to the top of
+ // the loop, which will continue;
+ before_first_timeout = false;
+ thread_plan_sp->SetStopOthers(false);
+ if (log)
+ log->PutCString(
+ "Process::RunThreadPlan(): about to resume.");
+
+ back_to_top = true;
+ break;
+ } else {
+ // Running all threads failed, so return Interrupted.
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): running all "
+ "threads timed out.");
+ return_value = eExpressionInterrupted;
+ back_to_top = false;
+ break;
+ }
+ }
+ } else {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): halt said it "
+ "succeeded, but I got no event. "
+ "I'm getting out of here passing Interrupted.");
+ return_value = eExpressionInterrupted;
+ back_to_top = false;
+ break;
}
+ } else {
+ try_halt_again++;
+ continue;
+ }
}
- }
- // If the process exited during the run of the thread plan, notify everyone.
+ if (!back_to_top || try_halt_again > num_retries)
+ break;
+ else
+ continue;
+ }
+ } // END WAIT LOOP
+
+ // If we had to start up a temporary private state thread to run this thread
+ // plan, shut it down now.
+ if (backup_private_state_thread.IsJoinable()) {
+ StopPrivateStateThread();
+ Error error;
+ m_private_state_thread = backup_private_state_thread;
+ if (stopper_base_plan_sp) {
+ thread->DiscardThreadPlansUpToPlan(stopper_base_plan_sp);
+ }
+ if (old_state != eStateInvalid)
+ m_public_state.SetValueNoLock(old_state);
+ }
+
+ if (return_value != eExpressionCompleted && log) {
+ // Print a backtrace into the log so we can figure out where we are:
+ StreamString s;
+ s.PutCString("Thread state after unsuccessful completion: \n");
+ thread->GetStackFrameStatus(s, 0, UINT32_MAX, true, UINT32_MAX);
+ log->PutCString(s.GetData());
+ }
+ // Restore the thread state if we are going to discard the plan execution.
+ // There are three cases where this
+ // could happen:
+ // 1) The execution successfully completed
+ // 2) We hit a breakpoint, and ignore_breakpoints was true
+ // 3) We got some other error, and discard_on_error was true
+ bool should_unwind = (return_value == eExpressionInterrupted &&
+ options.DoesUnwindOnError()) ||
+ (return_value == eExpressionHitBreakpoint &&
+ options.DoesIgnoreBreakpoints());
+
+ if (return_value == eExpressionCompleted || should_unwind) {
+ thread_plan_sp->RestoreThreadState();
+ }
+
+ // Now do some processing on the results of the run:
+ if (return_value == eExpressionInterrupted ||
+ return_value == eExpressionHitBreakpoint) {
+ if (log) {
+ StreamString s;
+ if (event_sp)
+ event_sp->Dump(&s);
+ else {
+ log->PutCString("Process::RunThreadPlan(): Stop event that "
+ "interrupted us is NULL.");
+ }
- if (event_to_broadcast_sp)
- {
- if (log)
- log->PutCString("Process::RunThreadPlan(): rebroadcasting event.");
- BroadcastEvent(event_to_broadcast_sp);
- }
+ StreamString ts;
- return return_value;
-}
+ const char *event_explanation = nullptr;
-const char *
-Process::ExecutionResultAsCString (ExpressionResults result)
-{
- const char *result_name;
-
- switch (result)
- {
- case eExpressionCompleted:
- result_name = "eExpressionCompleted";
- break;
- case eExpressionDiscarded:
- result_name = "eExpressionDiscarded";
- break;
- case eExpressionInterrupted:
- result_name = "eExpressionInterrupted";
- break;
- case eExpressionHitBreakpoint:
- result_name = "eExpressionHitBreakpoint";
+ do {
+ if (!event_sp) {
+ event_explanation = "<no event>";
break;
- case eExpressionSetupError:
- result_name = "eExpressionSetupError";
+ } else if (event_sp->GetType() == eBroadcastBitInterrupt) {
+ event_explanation = "<user interrupt>";
break;
- case eExpressionParseError:
- result_name = "eExpressionParseError";
- break;
- case eExpressionResultUnavailable:
- result_name = "eExpressionResultUnavailable";
- break;
- case eExpressionTimedOut:
- result_name = "eExpressionTimedOut";
- break;
- case eExpressionStoppedForDebug:
- result_name = "eExpressionStoppedForDebug";
- break;
- }
- return result_name;
-}
-
-void
-Process::GetStatus (Stream &strm)
-{
- const StateType state = GetState();
- if (StateIsStoppedState(state, false))
- {
- if (state == eStateExited)
- {
- int exit_status = GetExitStatus();
- const char *exit_description = GetExitDescription();
- strm.Printf ("Process %" PRIu64 " exited with status = %i (0x%8.8x) %s\n",
- GetID(),
- exit_status,
- exit_status,
- exit_description ? exit_description : "");
- }
- else
- {
- if (state == eStateConnected)
- strm.Printf ("Connected to remote target.\n");
- else
- strm.Printf ("Process %" PRIu64 " %s\n", GetID(), StateAsCString (state));
- }
- }
- else
- {
- strm.Printf ("Process %" PRIu64 " is running.\n", GetID());
- }
-}
+ } else {
+ const Process::ProcessEventData *event_data =
+ Process::ProcessEventData::GetEventDataFromEvent(
+ event_sp.get());
-size_t
-Process::GetThreadStatus (Stream &strm,
- bool only_threads_with_stop_reason,
- uint32_t start_frame,
- uint32_t num_frames,
- uint32_t num_frames_with_source)
-{
- size_t num_thread_infos_dumped = 0;
-
- // You can't hold the thread list lock while calling Thread::GetStatus. That very well might run code (e.g. if we need it
- // to get return values or arguments.) For that to work the process has to be able to acquire it. So instead copy the thread
- // ID's, and look them up one by one:
-
- uint32_t num_threads;
- std::vector<lldb::tid_t> thread_id_array;
- //Scope for thread list locker;
- {
- std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex());
- ThreadList &curr_thread_list = GetThreadList();
- num_threads = curr_thread_list.GetSize();
- uint32_t idx;
- thread_id_array.resize(num_threads);
- for (idx = 0; idx < num_threads; ++idx)
- thread_id_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
- }
-
- for (uint32_t i = 0; i < num_threads; i++)
- {
- ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_id_array[i]));
- if (thread_sp)
- {
- if (only_threads_with_stop_reason)
- {
- StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
- if (!stop_info_sp || !stop_info_sp->IsValid())
- continue;
+ if (!event_data) {
+ event_explanation = "<no event data>";
+ break;
}
- thread_sp->GetStatus (strm,
- start_frame,
- num_frames,
- num_frames_with_source);
- ++num_thread_infos_dumped;
- }
- else
- {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf("Process::GetThreadStatus - thread 0x" PRIu64 " vanished while running Thread::GetStatus.");
- }
- }
- return num_thread_infos_dumped;
-}
-
-void
-Process::AddInvalidMemoryRegion (const LoadRange ®ion)
-{
- m_memory_cache.AddInvalidRange(region.GetRangeBase(), region.GetByteSize());
-}
-
-bool
-Process::RemoveInvalidMemoryRange (const LoadRange ®ion)
-{
- return m_memory_cache.RemoveInvalidRange(region.GetRangeBase(), region.GetByteSize());
-}
-void
-Process::AddPreResumeAction (PreResumeActionCallback callback, void *baton)
-{
- m_pre_resume_actions.push_back(PreResumeCallbackAndBaton (callback, baton));
-}
+ Process *process = event_data->GetProcessSP().get();
-bool
-Process::RunPreResumeActions ()
-{
- bool result = true;
- while (!m_pre_resume_actions.empty())
- {
- struct PreResumeCallbackAndBaton action = m_pre_resume_actions.back();
- m_pre_resume_actions.pop_back();
- bool this_result = action.callback (action.baton);
- if (result)
- result = this_result;
- }
- return result;
-}
+ if (!process) {
+ event_explanation = "<no process>";
+ break;
+ }
-void
-Process::ClearPreResumeActions ()
-{
- m_pre_resume_actions.clear();
-}
+ ThreadList &thread_list = process->GetThreadList();
-ProcessRunLock &
-Process::GetRunLock()
-{
- if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
- return m_private_run_lock;
- else
- return m_public_run_lock;
-}
+ uint32_t num_threads = thread_list.GetSize();
+ uint32_t thread_index;
-void
-Process::Flush ()
-{
- m_thread_list.Flush();
- m_extended_thread_list.Flush();
- m_extended_thread_stop_id = 0;
- m_queue_list.Clear();
- m_queue_list_stop_id = 0;
-}
+ ts.Printf("<%u threads> ", num_threads);
-void
-Process::DidExec ()
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log)
- log->Printf ("Process::%s()", __FUNCTION__);
+ for (thread_index = 0; thread_index < num_threads; ++thread_index) {
+ Thread *thread = thread_list.GetThreadAtIndex(thread_index).get();
- Target &target = GetTarget();
- target.CleanupProcess ();
- target.ClearModules(false);
- m_dynamic_checkers_ap.reset();
- m_abi_sp.reset();
- m_system_runtime_ap.reset();
- m_os_ap.reset();
- m_dyld_ap.reset();
- m_jit_loaders_ap.reset();
- m_image_tokens.clear();
- m_allocated_memory_cache.Clear();
- m_language_runtimes.clear();
- m_instrumentation_runtimes.clear();
- m_thread_list.DiscardThreadPlans();
- m_memory_cache.Clear(true);
- m_stop_info_override_callback = nullptr;
- DoDidExec();
- CompleteAttach ();
- // Flush the process (threads and all stack frames) after running CompleteAttach()
- // in case the dynamic loader loaded things in new locations.
- Flush();
-
- // After we figure out what was loaded/unloaded in CompleteAttach,
- // we need to let the target know so it can do any cleanup it needs to.
- target.DidExec();
-}
+ if (!thread) {
+ ts.Printf("<?> ");
+ continue;
+ }
-addr_t
-Process::ResolveIndirectFunction(const Address *address, Error &error)
-{
- if (address == nullptr)
- {
- error.SetErrorString("Invalid address argument");
- return LLDB_INVALID_ADDRESS;
- }
-
- addr_t function_addr = LLDB_INVALID_ADDRESS;
-
- addr_t addr = address->GetLoadAddress(&GetTarget());
- std::map<addr_t,addr_t>::const_iterator iter = m_resolved_indirect_addresses.find(addr);
- if (iter != m_resolved_indirect_addresses.end())
- {
- function_addr = (*iter).second;
- }
- else
- {
- if (!InferiorCall(this, address, function_addr))
- {
- Symbol *symbol = address->CalculateSymbolContextSymbol();
- error.SetErrorStringWithFormat ("Unable to call resolver for indirect function %s",
- symbol ? symbol->GetName().AsCString() : "<UNKNOWN>");
- function_addr = LLDB_INVALID_ADDRESS;
- }
+ ts.Printf("<0x%4.4" PRIx64 " ", thread->GetID());
+ RegisterContext *register_context =
+ thread->GetRegisterContext().get();
+
+ if (register_context)
+ ts.Printf("[ip 0x%" PRIx64 "] ", register_context->GetPC());
+ else
+ ts.Printf("[ip unknown] ");
+
+ // Show the private stop info here, the public stop info will be
+ // from the last natural stop.
+ lldb::StopInfoSP stop_info_sp = thread->GetPrivateStopInfo();
+ if (stop_info_sp) {
+ const char *stop_desc = stop_info_sp->GetDescription();
+ if (stop_desc)
+ ts.PutCString(stop_desc);
+ }
+ ts.Printf(">");
+ }
+
+ event_explanation = ts.GetData();
+ }
+ } while (0);
+
+ if (event_explanation)
+ log->Printf("Process::RunThreadPlan(): execution interrupted: %s %s",
+ s.GetData(), event_explanation);
else
- {
- m_resolved_indirect_addresses.insert(std::pair<addr_t, addr_t>(addr, function_addr));
- }
- }
- return function_addr;
-}
+ log->Printf("Process::RunThreadPlan(): execution interrupted: %s",
+ s.GetData());
+ }
-void
-Process::ModulesDidLoad (ModuleList &module_list)
-{
- SystemRuntime *sys_runtime = GetSystemRuntime();
- if (sys_runtime)
- {
- sys_runtime->ModulesDidLoad (module_list);
- }
-
- GetJITLoaders().ModulesDidLoad (module_list);
-
- // Give runtimes a chance to be created.
- InstrumentationRuntime::ModulesDidLoad(module_list, this, m_instrumentation_runtimes);
-
- // Tell runtimes about new modules.
- for (auto pos = m_instrumentation_runtimes.begin(); pos != m_instrumentation_runtimes.end(); ++pos)
- {
- InstrumentationRuntimeSP runtime = pos->second;
- runtime->ModulesDidLoad(module_list);
- }
-
- // Let any language runtimes we have already created know
- // about the modules that loaded.
-
- // Iterate over a copy of this language runtime list in case
- // the language runtime ModulesDidLoad somehow causes the language
- // riuntime to be unloaded.
- LanguageRuntimeCollection language_runtimes(m_language_runtimes);
- for (const auto &pair: language_runtimes)
- {
- // We must check language_runtime_sp to make sure it is not
- // nullptr as we might cache the fact that we didn't have a
- // language runtime for a language.
- LanguageRuntimeSP language_runtime_sp = pair.second;
- if (language_runtime_sp)
- language_runtime_sp->ModulesDidLoad(module_list);
- }
-
- // If we don't have an operating system plug-in, try to load one since
- // loading shared libraries might cause a new one to try and load
- if (!m_os_ap)
- LoadOperatingSystemPlugin(false);
-
- // Give structured-data plugins a chance to see the modified modules.
- for (auto pair : m_structured_data_plugin_map)
- {
- if (pair.second)
- pair.second->ModulesDidLoad(*this, module_list);
+ if (should_unwind) {
+ if (log)
+ log->Printf("Process::RunThreadPlan: ExecutionInterrupted - "
+ "discarding thread plans up to %p.",
+ static_cast<void *>(thread_plan_sp.get()));
+ thread->DiscardThreadPlansUpToPlan(thread_plan_sp);
+ } else {
+ if (log)
+ log->Printf("Process::RunThreadPlan: ExecutionInterrupted - for "
+ "plan: %p not discarding.",
+ static_cast<void *>(thread_plan_sp.get()));
+ }
+ } else if (return_value == eExpressionSetupError) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): execution set up error.");
+
+ if (options.DoesUnwindOnError()) {
+ thread->DiscardThreadPlansUpToPlan(thread_plan_sp);
+ }
+ } else {
+ if (thread->IsThreadPlanDone(thread_plan_sp.get())) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): thread plan is done");
+ return_value = eExpressionCompleted;
+ } else if (thread->WasThreadPlanDiscarded(thread_plan_sp.get())) {
+ if (log)
+ log->PutCString(
+ "Process::RunThreadPlan(): thread plan was discarded");
+ return_value = eExpressionDiscarded;
+ } else {
+ if (log)
+ log->PutCString(
+ "Process::RunThreadPlan(): thread plan stopped in mid course");
+ if (options.DoesUnwindOnError() && thread_plan_sp) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): discarding thread plan "
+ "'cause unwind_on_error is set.");
+ thread->DiscardThreadPlansUpToPlan(thread_plan_sp);
+ }
+ }
+ }
+
+ // Thread we ran the function in may have gone away because we ran the
+ // target
+ // Check that it's still there, and if it is put it back in the context.
+ // Also restore the
+ // frame in the context if it is still present.
+ thread = GetThreadList().FindThreadByIndexID(thread_idx_id, true).get();
+ if (thread) {
+ exe_ctx.SetFrameSP(thread->GetFrameWithStackID(ctx_frame_id));
+ }
+
+ // Also restore the current process'es selected frame & thread, since this
+ // function calling may
+ // be done behind the user's back.
+
+ if (selected_tid != LLDB_INVALID_THREAD_ID) {
+ if (GetThreadList().SetSelectedThreadByIndexID(selected_tid) &&
+ selected_stack_id.IsValid()) {
+ // We were able to restore the selected thread, now restore the frame:
+ std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex());
+ StackFrameSP old_frame_sp =
+ GetThreadList().GetSelectedThread()->GetFrameWithStackID(
+ selected_stack_id);
+ if (old_frame_sp)
+ GetThreadList().GetSelectedThread()->SetSelectedFrame(
+ old_frame_sp.get());
+ }
}
-}
-
-void
-Process::PrintWarning (uint64_t warning_type, const void *repeat_key, const char *fmt, ...)
-{
- bool print_warning = true;
+ }
- StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream();
- if (!stream_sp)
- return;
- if (warning_type == eWarningsOptimization
- && !GetWarningsOptimization())
- {
- return;
- }
+ // If the process exited during the run of the thread plan, notify everyone.
- if (repeat_key != nullptr)
- {
- WarningsCollection::iterator it = m_warnings_issued.find (warning_type);
- if (it == m_warnings_issued.end())
- {
- m_warnings_issued[warning_type] = WarningsPointerSet();
- m_warnings_issued[warning_type].insert (repeat_key);
- }
- else
- {
- if (it->second.find (repeat_key) != it->second.end())
- {
- print_warning = false;
- }
- else
- {
- it->second.insert (repeat_key);
- }
- }
- }
+ if (event_to_broadcast_sp) {
+ if (log)
+ log->PutCString("Process::RunThreadPlan(): rebroadcasting event.");
+ BroadcastEvent(event_to_broadcast_sp);
+ }
+
+ return return_value;
+}
+
+const char *Process::ExecutionResultAsCString(ExpressionResults result) {
+ const char *result_name;
+
+ switch (result) {
+ case eExpressionCompleted:
+ result_name = "eExpressionCompleted";
+ break;
+ case eExpressionDiscarded:
+ result_name = "eExpressionDiscarded";
+ break;
+ case eExpressionInterrupted:
+ result_name = "eExpressionInterrupted";
+ break;
+ case eExpressionHitBreakpoint:
+ result_name = "eExpressionHitBreakpoint";
+ break;
+ case eExpressionSetupError:
+ result_name = "eExpressionSetupError";
+ break;
+ case eExpressionParseError:
+ result_name = "eExpressionParseError";
+ break;
+ case eExpressionResultUnavailable:
+ result_name = "eExpressionResultUnavailable";
+ break;
+ case eExpressionTimedOut:
+ result_name = "eExpressionTimedOut";
+ break;
+ case eExpressionStoppedForDebug:
+ result_name = "eExpressionStoppedForDebug";
+ break;
+ }
+ return result_name;
+}
+
+void Process::GetStatus(Stream &strm) {
+ const StateType state = GetState();
+ if (StateIsStoppedState(state, false)) {
+ if (state == eStateExited) {
+ int exit_status = GetExitStatus();
+ const char *exit_description = GetExitDescription();
+ strm.Printf("Process %" PRIu64 " exited with status = %i (0x%8.8x) %s\n",
+ GetID(), exit_status, exit_status,
+ exit_description ? exit_description : "");
+ } else {
+ if (state == eStateConnected)
+ strm.Printf("Connected to remote target.\n");
+ else
+ strm.Printf("Process %" PRIu64 " %s\n", GetID(), StateAsCString(state));
+ }
+ } else {
+ strm.Printf("Process %" PRIu64 " is running.\n", GetID());
+ }
+}
+
+size_t Process::GetThreadStatus(Stream &strm,
+ bool only_threads_with_stop_reason,
+ uint32_t start_frame, uint32_t num_frames,
+ uint32_t num_frames_with_source) {
+ size_t num_thread_infos_dumped = 0;
+
+ // You can't hold the thread list lock while calling Thread::GetStatus. That
+ // very well might run code (e.g. if we need it
+ // to get return values or arguments.) For that to work the process has to be
+ // able to acquire it. So instead copy the thread
+ // ID's, and look them up one by one:
+
+ uint32_t num_threads;
+ std::vector<lldb::tid_t> thread_id_array;
+ // Scope for thread list locker;
+ {
+ std::lock_guard<std::recursive_mutex> guard(GetThreadList().GetMutex());
+ ThreadList &curr_thread_list = GetThreadList();
+ num_threads = curr_thread_list.GetSize();
+ uint32_t idx;
+ thread_id_array.resize(num_threads);
+ for (idx = 0; idx < num_threads; ++idx)
+ thread_id_array[idx] = curr_thread_list.GetThreadAtIndex(idx)->GetID();
+ }
+
+ for (uint32_t i = 0; i < num_threads; i++) {
+ ThreadSP thread_sp(GetThreadList().FindThreadByID(thread_id_array[i]));
+ if (thread_sp) {
+ if (only_threads_with_stop_reason) {
+ StopInfoSP stop_info_sp = thread_sp->GetStopInfo();
+ if (!stop_info_sp || !stop_info_sp->IsValid())
+ continue;
+ }
+ thread_sp->GetStatus(strm, start_frame, num_frames,
+ num_frames_with_source);
+ ++num_thread_infos_dumped;
+ } else {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::GetThreadStatus - thread 0x" PRIu64
+ " vanished while running Thread::GetStatus.");
+ }
+ }
+ return num_thread_infos_dumped;
+}
+
+void Process::AddInvalidMemoryRegion(const LoadRange ®ion) {
+ m_memory_cache.AddInvalidRange(region.GetRangeBase(), region.GetByteSize());
+}
+
+bool Process::RemoveInvalidMemoryRange(const LoadRange ®ion) {
+ return m_memory_cache.RemoveInvalidRange(region.GetRangeBase(),
+ region.GetByteSize());
+}
+
+void Process::AddPreResumeAction(PreResumeActionCallback callback,
+ void *baton) {
+ m_pre_resume_actions.push_back(PreResumeCallbackAndBaton(callback, baton));
+}
+
+bool Process::RunPreResumeActions() {
+ bool result = true;
+ while (!m_pre_resume_actions.empty()) {
+ struct PreResumeCallbackAndBaton action = m_pre_resume_actions.back();
+ m_pre_resume_actions.pop_back();
+ bool this_result = action.callback(action.baton);
+ if (result)
+ result = this_result;
+ }
+ return result;
+}
+
+void Process::ClearPreResumeActions() { m_pre_resume_actions.clear(); }
+
+ProcessRunLock &Process::GetRunLock() {
+ if (m_private_state_thread.EqualsThread(Host::GetCurrentThread()))
+ return m_private_run_lock;
+ else
+ return m_public_run_lock;
+}
+
+void Process::Flush() {
+ m_thread_list.Flush();
+ m_extended_thread_list.Flush();
+ m_extended_thread_stop_id = 0;
+ m_queue_list.Clear();
+ m_queue_list_stop_id = 0;
+}
+
+void Process::DidExec() {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s()", __FUNCTION__);
+
+ Target &target = GetTarget();
+ target.CleanupProcess();
+ target.ClearModules(false);
+ m_dynamic_checkers_ap.reset();
+ m_abi_sp.reset();
+ m_system_runtime_ap.reset();
+ m_os_ap.reset();
+ m_dyld_ap.reset();
+ m_jit_loaders_ap.reset();
+ m_image_tokens.clear();
+ m_allocated_memory_cache.Clear();
+ m_language_runtimes.clear();
+ m_instrumentation_runtimes.clear();
+ m_thread_list.DiscardThreadPlans();
+ m_memory_cache.Clear(true);
+ m_stop_info_override_callback = nullptr;
+ DoDidExec();
+ CompleteAttach();
+ // Flush the process (threads and all stack frames) after running
+ // CompleteAttach()
+ // in case the dynamic loader loaded things in new locations.
+ Flush();
+
+ // After we figure out what was loaded/unloaded in CompleteAttach,
+ // we need to let the target know so it can do any cleanup it needs to.
+ target.DidExec();
+}
+
+addr_t Process::ResolveIndirectFunction(const Address *address, Error &error) {
+ if (address == nullptr) {
+ error.SetErrorString("Invalid address argument");
+ return LLDB_INVALID_ADDRESS;
+ }
- if (print_warning)
- {
- va_list args;
- va_start (args, fmt);
- stream_sp->PrintfVarArg (fmt, args);
- va_end (args);
- }
-}
+ addr_t function_addr = LLDB_INVALID_ADDRESS;
-void
-Process::PrintWarningOptimization (const SymbolContext &sc)
-{
- if (GetWarningsOptimization()
- && sc.module_sp
- && !sc.module_sp->GetFileSpec().GetFilename().IsEmpty()
- && sc.function
- && sc.function->GetIsOptimized())
- {
- PrintWarning (Process::Warnings::eWarningsOptimization, sc.module_sp.get(), "%s was compiled with optimization - stepping may behave oddly; variables may not be available.\n", sc.module_sp->GetFileSpec().GetFilename().GetCString());
- }
+ addr_t addr = address->GetLoadAddress(&GetTarget());
+ std::map<addr_t, addr_t>::const_iterator iter =
+ m_resolved_indirect_addresses.find(addr);
+ if (iter != m_resolved_indirect_addresses.end()) {
+ function_addr = (*iter).second;
+ } else {
+ if (!InferiorCall(this, address, function_addr)) {
+ Symbol *symbol = address->CalculateSymbolContextSymbol();
+ error.SetErrorStringWithFormat(
+ "Unable to call resolver for indirect function %s",
+ symbol ? symbol->GetName().AsCString() : "<UNKNOWN>");
+ function_addr = LLDB_INVALID_ADDRESS;
+ } else {
+ m_resolved_indirect_addresses.insert(
+ std::pair<addr_t, addr_t>(addr, function_addr));
+ }
+ }
+ return function_addr;
+}
+
+void Process::ModulesDidLoad(ModuleList &module_list) {
+ SystemRuntime *sys_runtime = GetSystemRuntime();
+ if (sys_runtime) {
+ sys_runtime->ModulesDidLoad(module_list);
+ }
+
+ GetJITLoaders().ModulesDidLoad(module_list);
+
+ // Give runtimes a chance to be created.
+ InstrumentationRuntime::ModulesDidLoad(module_list, this,
+ m_instrumentation_runtimes);
+
+ // Tell runtimes about new modules.
+ for (auto pos = m_instrumentation_runtimes.begin();
+ pos != m_instrumentation_runtimes.end(); ++pos) {
+ InstrumentationRuntimeSP runtime = pos->second;
+ runtime->ModulesDidLoad(module_list);
+ }
+
+ // Let any language runtimes we have already created know
+ // about the modules that loaded.
+
+ // Iterate over a copy of this language runtime list in case
+ // the language runtime ModulesDidLoad somehow causes the language
+ // riuntime to be unloaded.
+ LanguageRuntimeCollection language_runtimes(m_language_runtimes);
+ for (const auto &pair : language_runtimes) {
+ // We must check language_runtime_sp to make sure it is not
+ // nullptr as we might cache the fact that we didn't have a
+ // language runtime for a language.
+ LanguageRuntimeSP language_runtime_sp = pair.second;
+ if (language_runtime_sp)
+ language_runtime_sp->ModulesDidLoad(module_list);
+ }
+
+ // If we don't have an operating system plug-in, try to load one since
+ // loading shared libraries might cause a new one to try and load
+ if (!m_os_ap)
+ LoadOperatingSystemPlugin(false);
+
+ // Give structured-data plugins a chance to see the modified modules.
+ for (auto pair : m_structured_data_plugin_map) {
+ if (pair.second)
+ pair.second->ModulesDidLoad(*this, module_list);
+ }
+}
+
+void Process::PrintWarning(uint64_t warning_type, const void *repeat_key,
+ const char *fmt, ...) {
+ bool print_warning = true;
+
+ StreamSP stream_sp = GetTarget().GetDebugger().GetAsyncOutputStream();
+ if (!stream_sp)
+ return;
+ if (warning_type == eWarningsOptimization && !GetWarningsOptimization()) {
+ return;
+ }
+
+ if (repeat_key != nullptr) {
+ WarningsCollection::iterator it = m_warnings_issued.find(warning_type);
+ if (it == m_warnings_issued.end()) {
+ m_warnings_issued[warning_type] = WarningsPointerSet();
+ m_warnings_issued[warning_type].insert(repeat_key);
+ } else {
+ if (it->second.find(repeat_key) != it->second.end()) {
+ print_warning = false;
+ } else {
+ it->second.insert(repeat_key);
+ }
+ }
+ }
+
+ if (print_warning) {
+ va_list args;
+ va_start(args, fmt);
+ stream_sp->PrintfVarArg(fmt, args);
+ va_end(args);
+ }
+}
+
+void Process::PrintWarningOptimization(const SymbolContext &sc) {
+ if (GetWarningsOptimization() && sc.module_sp &&
+ !sc.module_sp->GetFileSpec().GetFilename().IsEmpty() && sc.function &&
+ sc.function->GetIsOptimized()) {
+ PrintWarning(Process::Warnings::eWarningsOptimization, sc.module_sp.get(),
+ "%s was compiled with optimization - stepping may behave "
+ "oddly; variables may not be available.\n",
+ sc.module_sp->GetFileSpec().GetFilename().GetCString());
+ }
}
-bool
-Process::GetProcessInfo(ProcessInstanceInfo &info)
-{
- info.Clear();
+bool Process::GetProcessInfo(ProcessInstanceInfo &info) {
+ info.Clear();
- PlatformSP platform_sp = GetTarget().GetPlatform();
- if (! platform_sp)
- return false;
+ PlatformSP platform_sp = GetTarget().GetPlatform();
+ if (!platform_sp)
+ return false;
- return platform_sp->GetProcessInfo(GetID(), info);
+ return platform_sp->GetProcessInfo(GetID(), info);
}
-ThreadCollectionSP
-Process::GetHistoryThreads(lldb::addr_t addr)
-{
- ThreadCollectionSP threads;
+ThreadCollectionSP Process::GetHistoryThreads(lldb::addr_t addr) {
+ ThreadCollectionSP threads;
+
+ const MemoryHistorySP &memory_history =
+ MemoryHistory::FindPlugin(shared_from_this());
- const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(shared_from_this());
-
- if (!memory_history) {
- return threads;
- }
-
- threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr)));
-
+ if (!memory_history) {
return threads;
+ }
+
+ threads.reset(new ThreadCollection(memory_history->GetHistoryThreads(addr)));
+
+ return threads;
}
InstrumentationRuntimeSP
-Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type)
-{
- InstrumentationRuntimeCollection::iterator pos;
- pos = m_instrumentation_runtimes.find (type);
- if (pos == m_instrumentation_runtimes.end())
- {
- return InstrumentationRuntimeSP();
- }
- else
- return (*pos).second;
+Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type) {
+ InstrumentationRuntimeCollection::iterator pos;
+ pos = m_instrumentation_runtimes.find(type);
+ if (pos == m_instrumentation_runtimes.end()) {
+ return InstrumentationRuntimeSP();
+ } else
+ return (*pos).second;
}
-bool
-Process::GetModuleSpec(const FileSpec& module_file_spec,
- const ArchSpec& arch,
- ModuleSpec& module_spec)
-{
- module_spec.Clear();
- return false;
+bool Process::GetModuleSpec(const FileSpec &module_file_spec,
+ const ArchSpec &arch, ModuleSpec &module_spec) {
+ module_spec.Clear();
+ return false;
}
-size_t
-Process::AddImageToken(lldb::addr_t image_ptr)
-{
- m_image_tokens.push_back(image_ptr);
- return m_image_tokens.size() - 1;
+size_t Process::AddImageToken(lldb::addr_t image_ptr) {
+ m_image_tokens.push_back(image_ptr);
+ return m_image_tokens.size() - 1;
}
-lldb::addr_t
-Process::GetImagePtrFromToken(size_t token) const
-{
- if (token < m_image_tokens.size())
- return m_image_tokens[token];
- return LLDB_INVALID_IMAGE_TOKEN;
+lldb::addr_t Process::GetImagePtrFromToken(size_t token) const {
+ if (token < m_image_tokens.size())
+ return m_image_tokens[token];
+ return LLDB_INVALID_IMAGE_TOKEN;
}
-void
-Process::ResetImageToken(size_t token)
-{
- if (token < m_image_tokens.size())
- m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN;
+void Process::ResetImageToken(size_t token) {
+ if (token < m_image_tokens.size())
+ m_image_tokens[token] = LLDB_INVALID_IMAGE_TOKEN;
}
Address
-Process::AdvanceAddressToNextBranchInstruction (Address default_stop_addr, AddressRange range_bounds)
-{
- Target &target = GetTarget();
- DisassemblerSP disassembler_sp;
- InstructionList *insn_list = nullptr;
-
- Address retval = default_stop_addr;
-
- if (!target.GetUseFastStepping())
- return retval;
- if (!default_stop_addr.IsValid())
- return retval;
-
- ExecutionContext exe_ctx (this);
- const char *plugin_name = nullptr;
- const char *flavor = nullptr;
- const bool prefer_file_cache = true;
- disassembler_sp = Disassembler::DisassembleRange(target.GetArchitecture(),
- plugin_name,
- flavor,
- exe_ctx,
- range_bounds,
- prefer_file_cache);
- if (disassembler_sp)
- insn_list = &disassembler_sp->GetInstructionList();
-
- if (insn_list == nullptr)
- {
- return retval;
- }
-
- size_t insn_offset = insn_list->GetIndexOfInstructionAtAddress (default_stop_addr);
- if (insn_offset == UINT32_MAX)
- {
- return retval;
- }
-
- uint32_t branch_index = insn_list->GetIndexOfNextBranchInstruction (insn_offset, target);
- if (branch_index == UINT32_MAX)
- {
- return retval;
- }
-
- if (branch_index > insn_offset)
- {
- Address next_branch_insn_address = insn_list->GetInstructionAtIndex (branch_index)->GetAddress();
- if (next_branch_insn_address.IsValid() && range_bounds.ContainsFileAddress (next_branch_insn_address))
- {
- retval = next_branch_insn_address;
- }
- }
+Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
+ AddressRange range_bounds) {
+ Target &target = GetTarget();
+ DisassemblerSP disassembler_sp;
+ InstructionList *insn_list = nullptr;
+ Address retval = default_stop_addr;
+
+ if (!target.GetUseFastStepping())
+ return retval;
+ if (!default_stop_addr.IsValid())
return retval;
-}
-Error
-Process::GetMemoryRegions (std::vector<lldb::MemoryRegionInfoSP>& region_list)
-{
+ ExecutionContext exe_ctx(this);
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ const bool prefer_file_cache = true;
+ disassembler_sp = Disassembler::DisassembleRange(
+ target.GetArchitecture(), plugin_name, flavor, exe_ctx, range_bounds,
+ prefer_file_cache);
+ if (disassembler_sp)
+ insn_list = &disassembler_sp->GetInstructionList();
- Error error;
+ if (insn_list == nullptr) {
+ return retval;
+ }
- lldb::addr_t range_end = 0;
+ size_t insn_offset =
+ insn_list->GetIndexOfInstructionAtAddress(default_stop_addr);
+ if (insn_offset == UINT32_MAX) {
+ return retval;
+ }
- region_list.clear();
- do
- {
- lldb::MemoryRegionInfoSP region_info( new lldb_private::MemoryRegionInfo() );
- error = GetMemoryRegionInfo (range_end, *region_info);
- // GetMemoryRegionInfo should only return an error if it is unimplemented.
- if (error.Fail())
- {
- region_list.clear();
- break;
- }
+ uint32_t branch_index =
+ insn_list->GetIndexOfNextBranchInstruction(insn_offset, target);
+ if (branch_index == UINT32_MAX) {
+ return retval;
+ }
- range_end = region_info->GetRange().GetRangeEnd();
- if( region_info->GetMapped() == MemoryRegionInfo::eYes )
- {
- region_list.push_back(region_info);
- }
- } while (range_end != LLDB_INVALID_ADDRESS);
+ if (branch_index > insn_offset) {
+ Address next_branch_insn_address =
+ insn_list->GetInstructionAtIndex(branch_index)->GetAddress();
+ if (next_branch_insn_address.IsValid() &&
+ range_bounds.ContainsFileAddress(next_branch_insn_address)) {
+ retval = next_branch_insn_address;
+ }
+ }
- return error;
+ return retval;
}
-Error
-Process::ConfigureStructuredData(const ConstString &type_name,
- const StructuredData::ObjectSP &config_sp)
-{
- // If you get this, the Process-derived class needs to implement a method
- // to enable an already-reported asynchronous structured data feature.
- // See ProcessGDBRemote for an example implementation over gdb-remote.
- return Error("unimplemented");
-}
+Error Process::GetMemoryRegions(
+ std::vector<lldb::MemoryRegionInfoSP> ®ion_list) {
-void
-Process::MapSupportedStructuredDataPlugins(const StructuredData::Array
- &supported_type_names)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+ Error error;
- // Bail out early if there are no type names to map.
- if (supported_type_names.GetSize() == 0)
- {
- if (log)
- log->Printf("Process::%s(): no structured data types supported",
- __FUNCTION__);
- return;
+ lldb::addr_t range_end = 0;
+
+ region_list.clear();
+ do {
+ lldb::MemoryRegionInfoSP region_info(new lldb_private::MemoryRegionInfo());
+ error = GetMemoryRegionInfo(range_end, *region_info);
+ // GetMemoryRegionInfo should only return an error if it is unimplemented.
+ if (error.Fail()) {
+ region_list.clear();
+ break;
}
- // Convert StructuredData type names to ConstString instances.
- std::set<ConstString> const_type_names;
+ range_end = region_info->GetRange().GetRangeEnd();
+ if (region_info->GetMapped() == MemoryRegionInfo::eYes) {
+ region_list.push_back(region_info);
+ }
+ } while (range_end != LLDB_INVALID_ADDRESS);
- if (log)
- log->Printf("Process::%s(): the process supports the following async "
- "structured data types:", __FUNCTION__);
+ return error;
+}
- supported_type_names.ForEach([&const_type_names, &log]
- (StructuredData::Object *object) {
- if (!object)
- {
- // Invalid - shouldn't be null objects in the array.
- return false;
+Error Process::ConfigureStructuredData(
+ const ConstString &type_name, const StructuredData::ObjectSP &config_sp) {
+ // If you get this, the Process-derived class needs to implement a method
+ // to enable an already-reported asynchronous structured data feature.
+ // See ProcessGDBRemote for an example implementation over gdb-remote.
+ return Error("unimplemented");
+}
+
+void Process::MapSupportedStructuredDataPlugins(
+ const StructuredData::Array &supported_type_names) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // Bail out early if there are no type names to map.
+ if (supported_type_names.GetSize() == 0) {
+ if (log)
+ log->Printf("Process::%s(): no structured data types supported",
+ __FUNCTION__);
+ return;
+ }
+
+ // Convert StructuredData type names to ConstString instances.
+ std::set<ConstString> const_type_names;
+
+ if (log)
+ log->Printf("Process::%s(): the process supports the following async "
+ "structured data types:",
+ __FUNCTION__);
+
+ supported_type_names.ForEach(
+ [&const_type_names, &log](StructuredData::Object *object) {
+ if (!object) {
+ // Invalid - shouldn't be null objects in the array.
+ return false;
}
auto type_name = object->GetAsString();
- if (!type_name)
- {
- // Invalid format - all type names should be strings.
- return false;
+ if (!type_name) {
+ // Invalid format - all type names should be strings.
+ return false;
}
const_type_names.insert(ConstString(type_name->GetValue()));
if (log)
- log->Printf("- %s", type_name->GetValue().c_str());
+ log->Printf("- %s", type_name->GetValue().c_str());
return true;
- });
+ });
- // For each StructuredDataPlugin, if the plugin handles any of the
- // types in the supported_type_names, map that type name to that plugin.
- uint32_t plugin_index = 0;
- for (auto create_instance =
- PluginManager::GetStructuredDataPluginCreateCallbackAtIndex(plugin_index);
- create_instance && !const_type_names.empty();
- ++plugin_index)
- {
- // Create the plugin.
- StructuredDataPluginSP plugin_sp = (*create_instance)(*this);
- if (!plugin_sp)
- {
- // This plugin doesn't think it can work with the process.
- // Move on to the next.
- continue;
- }
+ // For each StructuredDataPlugin, if the plugin handles any of the
+ // types in the supported_type_names, map that type name to that plugin.
+ uint32_t plugin_index = 0;
+ for (auto create_instance =
+ PluginManager::GetStructuredDataPluginCreateCallbackAtIndex(
+ plugin_index);
+ create_instance && !const_type_names.empty(); ++plugin_index) {
+ // Create the plugin.
+ StructuredDataPluginSP plugin_sp = (*create_instance)(*this);
+ if (!plugin_sp) {
+ // This plugin doesn't think it can work with the process.
+ // Move on to the next.
+ continue;
+ }
+
+ // For any of the remaining type names, map any that this plugin
+ // supports.
+ std::vector<ConstString> names_to_remove;
+ for (auto &type_name : const_type_names) {
+ if (plugin_sp->SupportsStructuredDataType(type_name)) {
+ m_structured_data_plugin_map.insert(
+ std::make_pair(type_name, plugin_sp));
+ names_to_remove.push_back(type_name);
+ if (log)
+ log->Printf("Process::%s(): using plugin %s for type name "
+ "%s",
+ __FUNCTION__, plugin_sp->GetPluginName().GetCString(),
+ type_name.GetCString());
+ }
+ }
+
+ // Remove the type names that were consumed by this plugin.
+ for (auto &type_name : names_to_remove)
+ const_type_names.erase(type_name);
+ }
+}
+
+bool Process::RouteAsyncStructuredData(
+ const StructuredData::ObjectSP object_sp) {
+ // Nothing to do if there's no data.
+ if (!object_sp)
+ return false;
- // For any of the remaining type names, map any that this plugin
- // supports.
- std::vector<ConstString> names_to_remove;
- for (auto &type_name : const_type_names)
- {
- if (plugin_sp->SupportsStructuredDataType(type_name))
- {
- m_structured_data_plugin_map.insert(std::make_pair(type_name,
- plugin_sp));
- names_to_remove.push_back(type_name);
- if (log)
- log->Printf("Process::%s(): using plugin %s for type name "
- "%s", __FUNCTION__,
- plugin_sp->GetPluginName().GetCString(),
- type_name.GetCString());
- }
- }
+ // The contract is this must be a dictionary, so we can look up the
+ // routing key via the top-level 'type' string value within the dictionary.
+ StructuredData::Dictionary *dictionary = object_sp->GetAsDictionary();
+ if (!dictionary)
+ return false;
- // Remove the type names that were consumed by this plugin.
- for (auto &type_name : names_to_remove)
- const_type_names.erase(type_name);
- }
-}
+ // Grab the async structured type name (i.e. the feature/plugin name).
+ ConstString type_name;
+ if (!dictionary->GetValueForKeyAsString("type", type_name))
+ return false;
-bool
-Process::RouteAsyncStructuredData(const StructuredData::ObjectSP object_sp)
-{
- // Nothing to do if there's no data.
- if (!object_sp)
- return false;
-
- // The contract is this must be a dictionary, so we can look up the
- // routing key via the top-level 'type' string value within the dictionary.
- StructuredData::Dictionary *dictionary = object_sp->GetAsDictionary();
- if (!dictionary)
- return false;
-
- // Grab the async structured type name (i.e. the feature/plugin name).
- ConstString type_name;
- if (!dictionary->GetValueForKeyAsString("type", type_name))
- return false;
-
- // Check if there's a plugin registered for this type name.
- auto find_it = m_structured_data_plugin_map.find(type_name);
- if (find_it == m_structured_data_plugin_map.end())
- {
- // We don't have a mapping for this structured data type.
- return false;
- }
+ // Check if there's a plugin registered for this type name.
+ auto find_it = m_structured_data_plugin_map.find(type_name);
+ if (find_it == m_structured_data_plugin_map.end()) {
+ // We don't have a mapping for this structured data type.
+ return false;
+ }
- // Route the structured data to the plugin.
- find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp);
- return true;
+ // Route the structured data to the plugin.
+ find_it->second->HandleArrivalOfStructuredData(*this, type_name, object_sp);
+ return true;
}
Modified: lldb/trunk/source/Target/ProcessInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ProcessInfo.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/ProcessInfo.cpp (original)
+++ lldb/trunk/source/Target/ProcessInfo.cpp Tue Sep 6 15:57:50 2016
@@ -21,138 +21,101 @@
using namespace lldb;
using namespace lldb_private;
-ProcessInfo::ProcessInfo () :
- m_executable (),
- m_arguments (),
- m_environment (),
- m_uid (UINT32_MAX),
- m_gid (UINT32_MAX),
- m_arch(),
- m_pid (LLDB_INVALID_PROCESS_ID)
-{
-}
-
-ProcessInfo::ProcessInfo (const char *name, const ArchSpec &arch, lldb::pid_t pid) :
- m_executable (name, false),
- m_arguments (),
- m_environment(),
- m_uid (UINT32_MAX),
- m_gid (UINT32_MAX),
- m_arch (arch),
- m_pid (pid)
-{
-}
-
-void
-ProcessInfo::Clear ()
-{
- m_executable.Clear();
- m_arguments.Clear();
- m_environment.Clear();
- m_uid = UINT32_MAX;
- m_gid = UINT32_MAX;
- m_arch.Clear();
- m_pid = LLDB_INVALID_PROCESS_ID;
-}
-
-const char *
-ProcessInfo::GetName() const
-{
- return m_executable.GetFilename().GetCString();
-}
-
-size_t
-ProcessInfo::GetNameLength() const
-{
- return m_executable.GetFilename().GetLength();
-}
-
-void
-ProcessInfo::Dump (Stream &s, Platform *platform) const
-{
- s << "Executable: " << GetName() << "\n";
- s << "Triple: ";
- m_arch.DumpTriple(s);
- s << "\n";
-
- s << "Arguments:\n";
- m_arguments.Dump(s);
-
- s << "Environment:\n";
- m_environment.Dump(s, "env");
-}
-
-void
-ProcessInfo::SetExecutableFile (const FileSpec &exe_file, bool add_exe_file_as_first_arg)
-{
- if (exe_file)
- {
- m_executable = exe_file;
- if (add_exe_file_as_first_arg)
- {
- char filename[PATH_MAX];
- if (exe_file.GetPath(filename, sizeof(filename)))
- m_arguments.InsertArgumentAtIndex (0, filename);
- }
- }
- else
- {
- m_executable.Clear();
+ProcessInfo::ProcessInfo()
+ : m_executable(), m_arguments(), m_environment(), m_uid(UINT32_MAX),
+ m_gid(UINT32_MAX), m_arch(), m_pid(LLDB_INVALID_PROCESS_ID) {}
+
+ProcessInfo::ProcessInfo(const char *name, const ArchSpec &arch,
+ lldb::pid_t pid)
+ : m_executable(name, false), m_arguments(), m_environment(),
+ m_uid(UINT32_MAX), m_gid(UINT32_MAX), m_arch(arch), m_pid(pid) {}
+
+void ProcessInfo::Clear() {
+ m_executable.Clear();
+ m_arguments.Clear();
+ m_environment.Clear();
+ m_uid = UINT32_MAX;
+ m_gid = UINT32_MAX;
+ m_arch.Clear();
+ m_pid = LLDB_INVALID_PROCESS_ID;
+}
+
+const char *ProcessInfo::GetName() const {
+ return m_executable.GetFilename().GetCString();
+}
+
+size_t ProcessInfo::GetNameLength() const {
+ return m_executable.GetFilename().GetLength();
+}
+
+void ProcessInfo::Dump(Stream &s, Platform *platform) const {
+ s << "Executable: " << GetName() << "\n";
+ s << "Triple: ";
+ m_arch.DumpTriple(s);
+ s << "\n";
+
+ s << "Arguments:\n";
+ m_arguments.Dump(s);
+
+ s << "Environment:\n";
+ m_environment.Dump(s, "env");
+}
+
+void ProcessInfo::SetExecutableFile(const FileSpec &exe_file,
+ bool add_exe_file_as_first_arg) {
+ if (exe_file) {
+ m_executable = exe_file;
+ if (add_exe_file_as_first_arg) {
+ char filename[PATH_MAX];
+ if (exe_file.GetPath(filename, sizeof(filename)))
+ m_arguments.InsertArgumentAtIndex(0, filename);
}
+ } else {
+ m_executable.Clear();
+ }
+}
+
+const char *ProcessInfo::GetArg0() const {
+ return (m_arg0.empty() ? nullptr : m_arg0.c_str());
+}
+
+void ProcessInfo::SetArg0(const char *arg) {
+ if (arg && arg[0])
+ m_arg0 = arg;
+ else
+ m_arg0.clear();
}
-const char *
-ProcessInfo::GetArg0 () const
-{
- return (m_arg0.empty() ? nullptr : m_arg0.c_str());
-}
-
-void
-ProcessInfo::SetArg0 (const char *arg)
-{
- if (arg && arg[0])
- m_arg0 = arg;
- else
- m_arg0.clear();
-}
-
-void
-ProcessInfo::SetArguments (char const **argv, bool first_arg_is_executable)
-{
- m_arguments.SetArguments (argv);
-
- // Is the first argument the executable?
- if (first_arg_is_executable)
- {
- const char *first_arg = m_arguments.GetArgumentAtIndex (0);
- if (first_arg)
- {
- // Yes the first argument is an executable, set it as the executable
- // in the launch options. Don't resolve the file path as the path
- // could be a remote platform path
- const bool resolve = false;
- m_executable.SetFile(first_arg, resolve);
- }
+void ProcessInfo::SetArguments(char const **argv,
+ bool first_arg_is_executable) {
+ m_arguments.SetArguments(argv);
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable) {
+ const char *first_arg = m_arguments.GetArgumentAtIndex(0);
+ if (first_arg) {
+ // Yes the first argument is an executable, set it as the executable
+ // in the launch options. Don't resolve the file path as the path
+ // could be a remote platform path
+ const bool resolve = false;
+ m_executable.SetFile(first_arg, resolve);
}
+ }
}
-void
-ProcessInfo::SetArguments (const Args& args, bool first_arg_is_executable)
-{
- // Copy all arguments
- m_arguments = args;
-
- // Is the first argument the executable?
- if (first_arg_is_executable)
- {
- const char *first_arg = m_arguments.GetArgumentAtIndex (0);
- if (first_arg)
- {
- // Yes the first argument is an executable, set it as the executable
- // in the launch options. Don't resolve the file path as the path
- // could be a remote platform path
- const bool resolve = false;
- m_executable.SetFile(first_arg, resolve);
- }
+void ProcessInfo::SetArguments(const Args &args, bool first_arg_is_executable) {
+ // Copy all arguments
+ m_arguments = args;
+
+ // Is the first argument the executable?
+ if (first_arg_is_executable) {
+ const char *first_arg = m_arguments.GetArgumentAtIndex(0);
+ if (first_arg) {
+ // Yes the first argument is an executable, set it as the executable
+ // in the launch options. Don't resolve the file path as the path
+ // could be a remote platform path
+ const bool resolve = false;
+ m_executable.SetFile(first_arg, resolve);
}
+ }
}
Modified: lldb/trunk/source/Target/ProcessLaunchInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/ProcessLaunchInfo.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/ProcessLaunchInfo.cpp (original)
+++ lldb/trunk/source/Target/ProcessLaunchInfo.cpp Tue Sep 6 15:57:50 2016
@@ -35,498 +35,415 @@ using namespace lldb_private;
// ProcessLaunchInfo member functions
//----------------------------------------------------------------------------
-ProcessLaunchInfo::ProcessLaunchInfo() :
- ProcessInfo(),
- m_working_dir(),
- m_plugin_name(),
- m_flags(0),
- m_file_actions(),
- m_pty(new lldb_utility::PseudoTerminal),
- m_resume_count(0),
- m_monitor_callback(nullptr),
- m_monitor_callback_baton(nullptr),
- m_monitor_signals(false),
- m_listener_sp(),
- m_hijack_listener_sp()
-{
-}
+ProcessLaunchInfo::ProcessLaunchInfo()
+ : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(0),
+ m_file_actions(), m_pty(new lldb_utility::PseudoTerminal),
+ m_resume_count(0), m_monitor_callback(nullptr),
+ m_monitor_callback_baton(nullptr), m_monitor_signals(false),
+ m_listener_sp(), m_hijack_listener_sp() {}
ProcessLaunchInfo::ProcessLaunchInfo(const FileSpec &stdin_file_spec,
const FileSpec &stdout_file_spec,
const FileSpec &stderr_file_spec,
const FileSpec &working_directory,
- uint32_t launch_flags) :
- ProcessInfo(),
- m_working_dir(),
- m_plugin_name(),
- m_flags(launch_flags),
- m_file_actions(),
- m_pty(new lldb_utility::PseudoTerminal),
- m_resume_count(0),
- m_monitor_callback(nullptr),
- m_monitor_callback_baton(nullptr),
- m_monitor_signals(false),
- m_listener_sp (),
- m_hijack_listener_sp()
-{
- if (stdin_file_spec)
- {
- FileAction file_action;
- const bool read = true;
- const bool write = false;
- if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
- AppendFileAction (file_action);
- }
- if (stdout_file_spec)
- {
- FileAction file_action;
- const bool read = false;
- const bool write = true;
- if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
- AppendFileAction (file_action);
- }
- if (stderr_file_spec)
- {
- FileAction file_action;
- const bool read = false;
- const bool write = true;
- if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
- AppendFileAction (file_action);
- }
- if (working_directory)
- SetWorkingDirectory(working_directory);
-}
-
-bool
-ProcessLaunchInfo::AppendCloseFileAction (int fd)
-{
+ uint32_t launch_flags)
+ : ProcessInfo(), m_working_dir(), m_plugin_name(), m_flags(launch_flags),
+ m_file_actions(), m_pty(new lldb_utility::PseudoTerminal),
+ m_resume_count(0), m_monitor_callback(nullptr),
+ m_monitor_callback_baton(nullptr), m_monitor_signals(false),
+ m_listener_sp(), m_hijack_listener_sp() {
+ if (stdin_file_spec) {
FileAction file_action;
- if (file_action.Close (fd))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
-}
-
-bool
-ProcessLaunchInfo::AppendDuplicateFileAction (int fd, int dup_fd)
-{
+ const bool read = true;
+ const bool write = false;
+ if (file_action.Open(STDIN_FILENO, stdin_file_spec, read, write))
+ AppendFileAction(file_action);
+ }
+ if (stdout_file_spec) {
FileAction file_action;
- if (file_action.Duplicate (fd, dup_fd))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDOUT_FILENO, stdout_file_spec, read, write))
+ AppendFileAction(file_action);
+ }
+ if (stderr_file_spec) {
+ FileAction file_action;
+ const bool read = false;
+ const bool write = true;
+ if (file_action.Open(STDERR_FILENO, stderr_file_spec, read, write))
+ AppendFileAction(file_action);
+ }
+ if (working_directory)
+ SetWorkingDirectory(working_directory);
}
-bool
-ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
- bool read, bool write)
-{
- FileAction file_action;
- if (file_action.Open(fd, file_spec, read, write))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
+bool ProcessLaunchInfo::AppendCloseFileAction(int fd) {
+ FileAction file_action;
+ if (file_action.Close(fd)) {
+ AppendFileAction(file_action);
+ return true;
+ }
+ return false;
}
-bool
-ProcessLaunchInfo::AppendSuppressFileAction (int fd, bool read, bool write)
-{
- FileAction file_action;
- if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read, write))
- {
- AppendFileAction (file_action);
- return true;
- }
- return false;
+bool ProcessLaunchInfo::AppendDuplicateFileAction(int fd, int dup_fd) {
+ FileAction file_action;
+ if (file_action.Duplicate(fd, dup_fd)) {
+ AppendFileAction(file_action);
+ return true;
+ }
+ return false;
}
-const FileAction *
-ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const
-{
- if (idx < m_file_actions.size())
- return &m_file_actions[idx];
- return nullptr;
-}
-
-const FileAction *
-ProcessLaunchInfo::GetFileActionForFD(int fd) const
-{
- for (size_t idx=0, count=m_file_actions.size(); idx < count; ++idx)
- {
- if (m_file_actions[idx].GetFD () == fd)
- return &m_file_actions[idx];
- }
- return nullptr;
+bool ProcessLaunchInfo::AppendOpenFileAction(int fd, const FileSpec &file_spec,
+ bool read, bool write) {
+ FileAction file_action;
+ if (file_action.Open(fd, file_spec, read, write)) {
+ AppendFileAction(file_action);
+ return true;
+ }
+ return false;
}
-const FileSpec &
-ProcessLaunchInfo::GetWorkingDirectory() const
-{
- return m_working_dir;
+bool ProcessLaunchInfo::AppendSuppressFileAction(int fd, bool read,
+ bool write) {
+ FileAction file_action;
+ if (file_action.Open(fd, FileSpec{FileSystem::DEV_NULL, false}, read,
+ write)) {
+ AppendFileAction(file_action);
+ return true;
+ }
+ return false;
}
-void
-ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir)
-{
- m_working_dir = working_dir;
+const FileAction *ProcessLaunchInfo::GetFileActionAtIndex(size_t idx) const {
+ if (idx < m_file_actions.size())
+ return &m_file_actions[idx];
+ return nullptr;
}
-const char *
-ProcessLaunchInfo::GetProcessPluginName () const
-{
- return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str());
+const FileAction *ProcessLaunchInfo::GetFileActionForFD(int fd) const {
+ for (size_t idx = 0, count = m_file_actions.size(); idx < count; ++idx) {
+ if (m_file_actions[idx].GetFD() == fd)
+ return &m_file_actions[idx];
+ }
+ return nullptr;
}
-void
-ProcessLaunchInfo::SetProcessPluginName (const char *plugin)
-{
- if (plugin && plugin[0])
- m_plugin_name.assign (plugin);
- else
- m_plugin_name.clear();
+const FileSpec &ProcessLaunchInfo::GetWorkingDirectory() const {
+ return m_working_dir;
}
-const FileSpec &
-ProcessLaunchInfo::GetShell () const
-{
- return m_shell;
+void ProcessLaunchInfo::SetWorkingDirectory(const FileSpec &working_dir) {
+ m_working_dir = working_dir;
}
-void
-ProcessLaunchInfo::SetShell (const FileSpec &shell)
-{
- m_shell = shell;
- if (m_shell)
- {
- m_shell.ResolveExecutableLocation();
- m_flags.Set (lldb::eLaunchFlagLaunchInShell);
- }
- else
- m_flags.Clear (lldb::eLaunchFlagLaunchInShell);
+const char *ProcessLaunchInfo::GetProcessPluginName() const {
+ return (m_plugin_name.empty() ? nullptr : m_plugin_name.c_str());
}
-void
-ProcessLaunchInfo::SetLaunchInSeparateProcessGroup (bool separate)
-{
- if (separate)
- m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
- else
- m_flags.Clear (lldb::eLaunchFlagLaunchInSeparateProcessGroup);
-}
-
-void
-ProcessLaunchInfo::SetShellExpandArguments (bool expand)
-{
- if (expand)
- m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
- else
- m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
-}
-
-void
-ProcessLaunchInfo::Clear ()
-{
- ProcessInfo::Clear();
- m_working_dir.Clear();
+void ProcessLaunchInfo::SetProcessPluginName(const char *plugin) {
+ if (plugin && plugin[0])
+ m_plugin_name.assign(plugin);
+ else
m_plugin_name.clear();
- m_shell.Clear();
- m_flags.Clear();
- m_file_actions.clear();
- m_resume_count = 0;
- m_listener_sp.reset();
- m_hijack_listener_sp.reset();
-}
-
-void
-ProcessLaunchInfo::SetMonitorProcessCallback(const Host::MonitorChildProcessCallback &callback, bool monitor_signals)
-{
- m_monitor_callback = callback;
- m_monitor_signals = monitor_signals;
-}
-
-bool
-ProcessLaunchInfo::MonitorProcess () const
-{
- if (m_monitor_callback && ProcessIDIsValid())
- {
- Host::StartMonitoringChildProcess (m_monitor_callback,
- GetProcessID(),
- m_monitor_signals);
- return true;
- }
- return false;
}
-void
-ProcessLaunchInfo::SetDetachOnError (bool enable)
-{
- if (enable)
- m_flags.Set(lldb::eLaunchFlagDetachOnError);
- else
- m_flags.Clear(lldb::eLaunchFlagDetachOnError);
-}
-
-void
-ProcessLaunchInfo::FinalizeFileActions (Target *target, bool default_to_use_pty)
-{
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-
- // If nothing for stdin or stdout or stderr was specified, then check the process for any default
- // settings that were set with "settings set"
- if (GetFileActionForFD(STDIN_FILENO) == nullptr ||
- GetFileActionForFD(STDOUT_FILENO) == nullptr ||
- GetFileActionForFD(STDERR_FILENO) == nullptr)
- {
+const FileSpec &ProcessLaunchInfo::GetShell() const { return m_shell; }
+
+void ProcessLaunchInfo::SetShell(const FileSpec &shell) {
+ m_shell = shell;
+ if (m_shell) {
+ m_shell.ResolveExecutableLocation();
+ m_flags.Set(lldb::eLaunchFlagLaunchInShell);
+ } else
+ m_flags.Clear(lldb::eLaunchFlagLaunchInShell);
+}
+
+void ProcessLaunchInfo::SetLaunchInSeparateProcessGroup(bool separate) {
+ if (separate)
+ m_flags.Set(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+ else
+ m_flags.Clear(lldb::eLaunchFlagLaunchInSeparateProcessGroup);
+}
+
+void ProcessLaunchInfo::SetShellExpandArguments(bool expand) {
+ if (expand)
+ m_flags.Set(lldb::eLaunchFlagShellExpandArguments);
+ else
+ m_flags.Clear(lldb::eLaunchFlagShellExpandArguments);
+}
+
+void ProcessLaunchInfo::Clear() {
+ ProcessInfo::Clear();
+ m_working_dir.Clear();
+ m_plugin_name.clear();
+ m_shell.Clear();
+ m_flags.Clear();
+ m_file_actions.clear();
+ m_resume_count = 0;
+ m_listener_sp.reset();
+ m_hijack_listener_sp.reset();
+}
+
+void ProcessLaunchInfo::SetMonitorProcessCallback(
+ const Host::MonitorChildProcessCallback &callback, bool monitor_signals) {
+ m_monitor_callback = callback;
+ m_monitor_signals = monitor_signals;
+}
+
+bool ProcessLaunchInfo::MonitorProcess() const {
+ if (m_monitor_callback && ProcessIDIsValid()) {
+ Host::StartMonitoringChildProcess(m_monitor_callback, GetProcessID(),
+ m_monitor_signals);
+ return true;
+ }
+ return false;
+}
+
+void ProcessLaunchInfo::SetDetachOnError(bool enable) {
+ if (enable)
+ m_flags.Set(lldb::eLaunchFlagDetachOnError);
+ else
+ m_flags.Clear(lldb::eLaunchFlagDetachOnError);
+}
+
+void ProcessLaunchInfo::FinalizeFileActions(Target *target,
+ bool default_to_use_pty) {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ // If nothing for stdin or stdout or stderr was specified, then check the
+ // process for any default
+ // settings that were set with "settings set"
+ if (GetFileActionForFD(STDIN_FILENO) == nullptr ||
+ GetFileActionForFD(STDOUT_FILENO) == nullptr ||
+ GetFileActionForFD(STDERR_FILENO) == nullptr) {
+ if (log)
+ log->Printf("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr "
+ "was not set, evaluating default handling",
+ __FUNCTION__);
+
+ if (m_flags.Test(eLaunchFlagLaunchInTTY)) {
+ // Do nothing, if we are launching in a remote terminal
+ // no file actions should be done at all.
+ return;
+ }
+
+ if (m_flags.Test(eLaunchFlagDisableSTDIO)) {
+ if (log)
+ log->Printf("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding "
+ "suppression action for stdin, stdout and stderr",
+ __FUNCTION__);
+ AppendSuppressFileAction(STDIN_FILENO, true, false);
+ AppendSuppressFileAction(STDOUT_FILENO, false, true);
+ AppendSuppressFileAction(STDERR_FILENO, false, true);
+ } else {
+ // Check for any values that might have gotten set with any of:
+ // (lldb) settings set target.input-path
+ // (lldb) settings set target.output-path
+ // (lldb) settings set target.error-path
+ FileSpec in_file_spec;
+ FileSpec out_file_spec;
+ FileSpec err_file_spec;
+ if (target) {
+ // Only override with the target settings if we don't already have
+ // an action for in, out or error
+ if (GetFileActionForFD(STDIN_FILENO) == nullptr)
+ in_file_spec = target->GetStandardInputPath();
+ if (GetFileActionForFD(STDOUT_FILENO) == nullptr)
+ out_file_spec = target->GetStandardOutputPath();
+ if (GetFileActionForFD(STDERR_FILENO) == nullptr)
+ err_file_spec = target->GetStandardErrorPath();
+ }
+
+ if (log)
+ log->Printf("ProcessLaunchInfo::%s target stdin='%s', target "
+ "stdout='%s', stderr='%s'",
+ __FUNCTION__,
+ in_file_spec ? in_file_spec.GetCString() : "<null>",
+ out_file_spec ? out_file_spec.GetCString() : "<null>",
+ err_file_spec ? err_file_spec.GetCString() : "<null>");
+
+ if (in_file_spec) {
+ AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false);
if (log)
- log->Printf ("ProcessLaunchInfo::%s at least one of stdin/stdout/stderr was not set, evaluating default handling",
- __FUNCTION__);
+ log->Printf(
+ "ProcessLaunchInfo::%s appended stdin open file action for %s",
+ __FUNCTION__, in_file_spec.GetCString());
+ }
- if (m_flags.Test(eLaunchFlagLaunchInTTY))
- {
- // Do nothing, if we are launching in a remote terminal
- // no file actions should be done at all.
- return;
- }
+ if (out_file_spec) {
+ AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true);
+ if (log)
+ log->Printf(
+ "ProcessLaunchInfo::%s appended stdout open file action for %s",
+ __FUNCTION__, out_file_spec.GetCString());
+ }
- if (m_flags.Test(eLaunchFlagDisableSTDIO))
- {
- if (log)
- log->Printf ("ProcessLaunchInfo::%s eLaunchFlagDisableSTDIO set, adding suppression action for stdin, stdout and stderr",
- __FUNCTION__);
- AppendSuppressFileAction (STDIN_FILENO , true, false);
- AppendSuppressFileAction (STDOUT_FILENO, false, true);
- AppendSuppressFileAction (STDERR_FILENO, false, true);
- }
- else
- {
- // Check for any values that might have gotten set with any of:
- // (lldb) settings set target.input-path
- // (lldb) settings set target.output-path
- // (lldb) settings set target.error-path
- FileSpec in_file_spec;
- FileSpec out_file_spec;
- FileSpec err_file_spec;
- if (target)
- {
- // Only override with the target settings if we don't already have
- // an action for in, out or error
- if (GetFileActionForFD(STDIN_FILENO) == nullptr)
- in_file_spec = target->GetStandardInputPath();
- if (GetFileActionForFD(STDOUT_FILENO) == nullptr)
- out_file_spec = target->GetStandardOutputPath();
- if (GetFileActionForFD(STDERR_FILENO) == nullptr)
- err_file_spec = target->GetStandardErrorPath();
- }
-
- if (log)
- log->Printf ("ProcessLaunchInfo::%s target stdin='%s', target stdout='%s', stderr='%s'",
- __FUNCTION__,
- in_file_spec ? in_file_spec.GetCString() : "<null>",
- out_file_spec ? out_file_spec.GetCString() : "<null>",
- err_file_spec ? err_file_spec.GetCString() : "<null>");
-
- if (in_file_spec)
- {
- AppendOpenFileAction(STDIN_FILENO, in_file_spec, true, false);
- if (log)
- log->Printf ("ProcessLaunchInfo::%s appended stdin open file action for %s",
- __FUNCTION__, in_file_spec.GetCString());
- }
-
- if (out_file_spec)
- {
- AppendOpenFileAction(STDOUT_FILENO, out_file_spec, false, true);
- if (log)
- log->Printf ("ProcessLaunchInfo::%s appended stdout open file action for %s",
- __FUNCTION__, out_file_spec.GetCString());
- }
-
- if (err_file_spec)
- {
- AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true);
- if (log)
- log->Printf ("ProcessLaunchInfo::%s appended stderr open file action for %s",
- __FUNCTION__, err_file_spec.GetCString());
- }
-
- if (default_to_use_pty && (!in_file_spec || !out_file_spec || !err_file_spec))
- {
- if (log)
- log->Printf ("ProcessLaunchInfo::%s default_to_use_pty is set, and at least one stdin/stderr/stdout is unset, so generating a pty to use for it",
- __FUNCTION__);
+ if (err_file_spec) {
+ AppendOpenFileAction(STDERR_FILENO, err_file_spec, false, true);
+ if (log)
+ log->Printf(
+ "ProcessLaunchInfo::%s appended stderr open file action for %s",
+ __FUNCTION__, err_file_spec.GetCString());
+ }
+
+ if (default_to_use_pty &&
+ (!in_file_spec || !out_file_spec || !err_file_spec)) {
+ if (log)
+ log->Printf("ProcessLaunchInfo::%s default_to_use_pty is set, and at "
+ "least one stdin/stderr/stdout is unset, so generating a "
+ "pty to use for it",
+ __FUNCTION__);
- int open_flags = O_RDWR | O_NOCTTY;
+ int open_flags = O_RDWR | O_NOCTTY;
#if !defined(_MSC_VER)
- // We really shouldn't be specifying platform specific flags
- // that are intended for a system call in generic code. But
- // this will have to do for now.
- open_flags |= O_CLOEXEC;
+ // We really shouldn't be specifying platform specific flags
+ // that are intended for a system call in generic code. But
+ // this will have to do for now.
+ open_flags |= O_CLOEXEC;
#endif
- if (m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0))
- {
- const FileSpec slave_file_spec{m_pty->GetSlaveName(nullptr, 0), false};
-
- // Only use the slave tty if we don't have anything specified for
- // input and don't have an action for stdin
- if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == nullptr)
- {
- AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
- }
-
- // Only use the slave tty if we don't have anything specified for
- // output and don't have an action for stdout
- if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == nullptr)
- {
- AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
- }
-
- // Only use the slave tty if we don't have anything specified for
- // error and don't have an action for stderr
- if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == nullptr)
- {
- AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
- }
- }
- }
+ if (m_pty->OpenFirstAvailableMaster(open_flags, nullptr, 0)) {
+ const FileSpec slave_file_spec{m_pty->GetSlaveName(nullptr, 0),
+ false};
+
+ // Only use the slave tty if we don't have anything specified for
+ // input and don't have an action for stdin
+ if (!in_file_spec && GetFileActionForFD(STDIN_FILENO) == nullptr) {
+ AppendOpenFileAction(STDIN_FILENO, slave_file_spec, true, false);
+ }
+
+ // Only use the slave tty if we don't have anything specified for
+ // output and don't have an action for stdout
+ if (!out_file_spec && GetFileActionForFD(STDOUT_FILENO) == nullptr) {
+ AppendOpenFileAction(STDOUT_FILENO, slave_file_spec, false, true);
+ }
+
+ // Only use the slave tty if we don't have anything specified for
+ // error and don't have an action for stderr
+ if (!err_file_spec && GetFileActionForFD(STDERR_FILENO) == nullptr) {
+ AppendOpenFileAction(STDERR_FILENO, slave_file_spec, false, true);
+ }
}
+ }
}
+ }
}
-bool
-ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell (Error &error,
- bool localhost,
- bool will_debug,
- bool first_arg_is_full_shell_command,
- int32_t num_resumes)
-{
- error.Clear();
-
- if (GetFlags().Test (eLaunchFlagLaunchInShell))
- {
- if (m_shell)
- {
- std::string shell_executable = m_shell.GetPath();
-
- const char **argv = GetArguments().GetConstArgumentVector ();
- if (argv == nullptr || argv[0] == nullptr)
- return false;
- Args shell_arguments;
- std::string safe_arg;
- shell_arguments.AppendArgument (shell_executable.c_str());
- const llvm::Triple &triple = GetArchitecture().GetTriple();
- if (triple.getOS() == llvm::Triple::Win32 && !triple.isWindowsCygwinEnvironment())
- shell_arguments.AppendArgument("/C");
- else
- shell_arguments.AppendArgument("-c");
-
- StreamString shell_command;
- if (will_debug)
- {
- // Add a modified PATH environment variable in case argv[0]
- // is a relative path.
- const char *argv0 = argv[0];
- FileSpec arg_spec(argv0, false);
- if (arg_spec.IsRelative())
- {
- // We have a relative path to our executable which may not work if
- // we just try to run "a.out" (without it being converted to "./a.out")
- FileSpec working_dir = GetWorkingDirectory();
- // Be sure to put quotes around PATH's value in case any paths have spaces...
- std::string new_path("PATH=\"");
- const size_t empty_path_len = new_path.size();
-
- if (working_dir)
- {
- new_path += working_dir.GetPath();
- }
- else
- {
- char current_working_dir[PATH_MAX];
- const char *cwd = getcwd(current_working_dir, sizeof(current_working_dir));
- if (cwd && cwd[0])
- new_path += cwd;
- }
- std::string curr_path;
- if (HostInfo::GetEnvironmentVar("PATH", curr_path))
- {
- if (new_path.size() > empty_path_len)
- new_path += ':';
- new_path += curr_path;
- }
- new_path += "\" ";
- shell_command.PutCString(new_path.c_str());
- }
-
- if (triple.getOS() != llvm::Triple::Win32 || triple.isWindowsCygwinEnvironment())
- shell_command.PutCString("exec");
-
- // Only Apple supports /usr/bin/arch being able to specify the architecture
- if (GetArchitecture().IsValid() && // Valid architecture
- GetArchitecture().GetTriple().getVendor() == llvm::Triple::Apple && // Apple only
- GetArchitecture().GetCore() != ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
- {
- shell_command.Printf(" /usr/bin/arch -arch %s", GetArchitecture().GetArchitectureName());
- // Set the resume count to 2:
- // 1 - stop in shell
- // 2 - stop in /usr/bin/arch
- // 3 - then we will stop in our program
- SetResumeCount(num_resumes + 1);
- }
- else
- {
- // Set the resume count to 1:
- // 1 - stop in shell
- // 2 - then we will stop in our program
- SetResumeCount(num_resumes);
- }
- }
-
- if (first_arg_is_full_shell_command)
- {
- // There should only be one argument that is the shell command itself to be used as is
- if (argv[0] && !argv[1])
- shell_command.Printf("%s", argv[0]);
- else
- return false;
- }
- else
- {
- for (size_t i=0; argv[i] != nullptr; ++i)
- {
- const char *arg = Args::GetShellSafeArgument (m_shell,
- argv[i],
- safe_arg);
- shell_command.Printf(" %s", arg);
- }
- }
- shell_arguments.AppendArgument (shell_command.GetString().c_str());
- m_executable = m_shell;
- m_arguments = shell_arguments;
- return true;
+bool ProcessLaunchInfo::ConvertArgumentsForLaunchingInShell(
+ Error &error, bool localhost, bool will_debug,
+ bool first_arg_is_full_shell_command, int32_t num_resumes) {
+ error.Clear();
+
+ if (GetFlags().Test(eLaunchFlagLaunchInShell)) {
+ if (m_shell) {
+ std::string shell_executable = m_shell.GetPath();
+
+ const char **argv = GetArguments().GetConstArgumentVector();
+ if (argv == nullptr || argv[0] == nullptr)
+ return false;
+ Args shell_arguments;
+ std::string safe_arg;
+ shell_arguments.AppendArgument(shell_executable.c_str());
+ const llvm::Triple &triple = GetArchitecture().GetTriple();
+ if (triple.getOS() == llvm::Triple::Win32 &&
+ !triple.isWindowsCygwinEnvironment())
+ shell_arguments.AppendArgument("/C");
+ else
+ shell_arguments.AppendArgument("-c");
+
+ StreamString shell_command;
+ if (will_debug) {
+ // Add a modified PATH environment variable in case argv[0]
+ // is a relative path.
+ const char *argv0 = argv[0];
+ FileSpec arg_spec(argv0, false);
+ if (arg_spec.IsRelative()) {
+ // We have a relative path to our executable which may not work if
+ // we just try to run "a.out" (without it being converted to
+ // "./a.out")
+ FileSpec working_dir = GetWorkingDirectory();
+ // Be sure to put quotes around PATH's value in case any paths have
+ // spaces...
+ std::string new_path("PATH=\"");
+ const size_t empty_path_len = new_path.size();
+
+ if (working_dir) {
+ new_path += working_dir.GetPath();
+ } else {
+ char current_working_dir[PATH_MAX];
+ const char *cwd =
+ getcwd(current_working_dir, sizeof(current_working_dir));
+ if (cwd && cwd[0])
+ new_path += cwd;
+ }
+ std::string curr_path;
+ if (HostInfo::GetEnvironmentVar("PATH", curr_path)) {
+ if (new_path.size() > empty_path_len)
+ new_path += ':';
+ new_path += curr_path;
+ }
+ new_path += "\" ";
+ shell_command.PutCString(new_path.c_str());
}
- else
+
+ if (triple.getOS() != llvm::Triple::Win32 ||
+ triple.isWindowsCygwinEnvironment())
+ shell_command.PutCString("exec");
+
+ // Only Apple supports /usr/bin/arch being able to specify the
+ // architecture
+ if (GetArchitecture().IsValid() && // Valid architecture
+ GetArchitecture().GetTriple().getVendor() ==
+ llvm::Triple::Apple && // Apple only
+ GetArchitecture().GetCore() !=
+ ArchSpec::eCore_x86_64_x86_64h) // Don't do this for x86_64h
{
- error.SetErrorString ("invalid shell path");
+ shell_command.Printf(" /usr/bin/arch -arch %s",
+ GetArchitecture().GetArchitectureName());
+ // Set the resume count to 2:
+ // 1 - stop in shell
+ // 2 - stop in /usr/bin/arch
+ // 3 - then we will stop in our program
+ SetResumeCount(num_resumes + 1);
+ } else {
+ // Set the resume count to 1:
+ // 1 - stop in shell
+ // 2 - then we will stop in our program
+ SetResumeCount(num_resumes);
}
- }
- else
- {
- error.SetErrorString ("not launching in shell");
- }
- return false;
-}
+ }
-ListenerSP
-ProcessLaunchInfo::GetListenerForProcess (Debugger &debugger)
-{
- if (m_listener_sp)
- return m_listener_sp;
- else
- return debugger.GetListener();
+ if (first_arg_is_full_shell_command) {
+ // There should only be one argument that is the shell command itself to
+ // be used as is
+ if (argv[0] && !argv[1])
+ shell_command.Printf("%s", argv[0]);
+ else
+ return false;
+ } else {
+ for (size_t i = 0; argv[i] != nullptr; ++i) {
+ const char *arg =
+ Args::GetShellSafeArgument(m_shell, argv[i], safe_arg);
+ shell_command.Printf(" %s", arg);
+ }
+ }
+ shell_arguments.AppendArgument(shell_command.GetString().c_str());
+ m_executable = m_shell;
+ m_arguments = shell_arguments;
+ return true;
+ } else {
+ error.SetErrorString("invalid shell path");
+ }
+ } else {
+ error.SetErrorString("not launching in shell");
+ }
+ return false;
+}
+
+ListenerSP ProcessLaunchInfo::GetListenerForProcess(Debugger &debugger) {
+ if (m_listener_sp)
+ return m_listener_sp;
+ else
+ return debugger.GetListener();
}
Modified: lldb/trunk/source/Target/Queue.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/Queue.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/Queue.cpp (original)
+++ lldb/trunk/source/Target/Queue.cpp Tue Sep 6 15:57:50 2016
@@ -11,127 +11,84 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/Target/Process.h"
#include "lldb/Target/Queue.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/QueueList.h"
-#include "lldb/Target/Thread.h"
#include "lldb/Target/SystemRuntime.h"
+#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
-Queue::Queue (ProcessSP process_sp, lldb::queue_id_t queue_id, const char *queue_name) :
- m_process_wp (),
- m_queue_id (queue_id),
- m_queue_name (),
- m_running_work_items_count(0),
- m_pending_work_items_count(0),
- m_pending_items(),
- m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS),
- m_kind (eQueueKindUnknown)
-{
- if (queue_name)
- m_queue_name = queue_name;
+Queue::Queue(ProcessSP process_sp, lldb::queue_id_t queue_id,
+ const char *queue_name)
+ : m_process_wp(), m_queue_id(queue_id), m_queue_name(),
+ m_running_work_items_count(0), m_pending_work_items_count(0),
+ m_pending_items(), m_dispatch_queue_t_addr(LLDB_INVALID_ADDRESS),
+ m_kind(eQueueKindUnknown) {
+ if (queue_name)
+ m_queue_name = queue_name;
- m_process_wp = process_sp;
+ m_process_wp = process_sp;
}
Queue::~Queue() = default;
-queue_id_t
-Queue::GetID ()
-{
- return m_queue_id;
-}
+queue_id_t Queue::GetID() { return m_queue_id; }
-const char *
-Queue::GetName ()
-{
- return (m_queue_name.empty() ? nullptr : m_queue_name.c_str());
+const char *Queue::GetName() {
+ return (m_queue_name.empty() ? nullptr : m_queue_name.c_str());
}
-uint32_t
-Queue::GetIndexID ()
-{
- return m_queue_id;
-}
+uint32_t Queue::GetIndexID() { return m_queue_id; }
-std::vector<lldb::ThreadSP>
-Queue::GetThreads ()
-{
- std::vector<ThreadSP> result;
- ProcessSP process_sp = m_process_wp.lock();
- if (process_sp)
- {
- for (ThreadSP thread_sp : process_sp->Threads())
- {
- if (thread_sp->GetQueueID() == m_queue_id)
- {
- result.push_back (thread_sp);
- }
- }
+std::vector<lldb::ThreadSP> Queue::GetThreads() {
+ std::vector<ThreadSP> result;
+ ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp) {
+ for (ThreadSP thread_sp : process_sp->Threads()) {
+ if (thread_sp->GetQueueID() == m_queue_id) {
+ result.push_back(thread_sp);
+ }
}
- return result;
+ }
+ return result;
}
-void
-Queue::SetNumRunningWorkItems (uint32_t count)
-{
- m_running_work_items_count = count;
+void Queue::SetNumRunningWorkItems(uint32_t count) {
+ m_running_work_items_count = count;
}
-uint32_t
-Queue::GetNumRunningWorkItems () const
-{
- return m_running_work_items_count;
+uint32_t Queue::GetNumRunningWorkItems() const {
+ return m_running_work_items_count;
}
-void
-Queue::SetNumPendingWorkItems (uint32_t count)
-{
- m_pending_work_items_count = count;
+void Queue::SetNumPendingWorkItems(uint32_t count) {
+ m_pending_work_items_count = count;
}
-uint32_t
-Queue::GetNumPendingWorkItems () const
-{
- return m_pending_work_items_count;
+uint32_t Queue::GetNumPendingWorkItems() const {
+ return m_pending_work_items_count;
}
-void
-Queue::SetLibdispatchQueueAddress (addr_t dispatch_queue_t_addr)
-{
- m_dispatch_queue_t_addr = dispatch_queue_t_addr;
+void Queue::SetLibdispatchQueueAddress(addr_t dispatch_queue_t_addr) {
+ m_dispatch_queue_t_addr = dispatch_queue_t_addr;
}
-addr_t
-Queue::GetLibdispatchQueueAddress () const
-{
- return m_dispatch_queue_t_addr;
+addr_t Queue::GetLibdispatchQueueAddress() const {
+ return m_dispatch_queue_t_addr;
}
-const std::vector<lldb::QueueItemSP> &
-Queue::GetPendingItems ()
-{
- if (m_pending_items.empty())
- {
- ProcessSP process_sp = m_process_wp.lock();
- if (process_sp && process_sp->GetSystemRuntime())
- {
- process_sp->GetSystemRuntime()->PopulatePendingItemsForQueue (this);
- }
+const std::vector<lldb::QueueItemSP> &Queue::GetPendingItems() {
+ if (m_pending_items.empty()) {
+ ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp && process_sp->GetSystemRuntime()) {
+ process_sp->GetSystemRuntime()->PopulatePendingItemsForQueue(this);
}
- return m_pending_items;
+ }
+ return m_pending_items;
}
-lldb::QueueKind
-Queue::GetKind ()
-{
- return m_kind;
-}
+lldb::QueueKind Queue::GetKind() { return m_kind; }
-void
-Queue::SetKind (lldb::QueueKind kind)
-{
- m_kind = kind;
-}
+void Queue::SetKind(lldb::QueueKind kind) { m_kind = kind; }
Modified: lldb/trunk/source/Target/QueueItem.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/QueueItem.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/QueueItem.cpp (original)
+++ lldb/trunk/source/Target/QueueItem.cpp Tue Sep 6 15:57:50 2016
@@ -15,142 +15,93 @@
using namespace lldb;
using namespace lldb_private;
-QueueItem::QueueItem (QueueSP queue_sp, ProcessSP process_sp, lldb::addr_t item_ref, lldb_private::Address address) :
- m_queue_wp (),
- m_process_wp (),
- m_item_ref (item_ref),
- m_address (address),
- m_have_fetched_entire_item (false),
- m_kind (eQueueItemKindUnknown),
- m_item_that_enqueued_this_ref (LLDB_INVALID_ADDRESS),
- m_enqueueing_thread_id (LLDB_INVALID_THREAD_ID),
- m_enqueueing_queue_id (LLDB_INVALID_QUEUE_ID),
- m_target_queue_id (LLDB_INVALID_QUEUE_ID),
- m_stop_id (0),
- m_backtrace(),
- m_thread_label(),
- m_queue_label(),
- m_target_queue_label()
-{
- m_queue_wp = queue_sp;
- m_process_wp = process_sp;
-}
-
-QueueItem::~QueueItem ()
-{
-}
-
-QueueItemKind
-QueueItem::GetKind()
-{
- FetchEntireItem ();
- return m_kind;
-}
-
-void
-QueueItem::SetKind (QueueItemKind item_kind)
-{
- m_kind = item_kind;
-}
-
-Address &
-QueueItem::GetAddress ()
-{
- return m_address;
-}
-
-void
-QueueItem::SetAddress (Address addr)
-{
- m_address = addr;
-}
-
-ThreadSP
-QueueItem::GetExtendedBacktraceThread (ConstString type)
-{
- FetchEntireItem ();
- ThreadSP return_thread;
- QueueSP queue_sp = m_queue_wp.lock();
- if (queue_sp)
- {
- ProcessSP process_sp = queue_sp->GetProcess();
- if (process_sp && process_sp->GetSystemRuntime())
- {
- return_thread = process_sp->GetSystemRuntime()->GetExtendedBacktraceForQueueItem (this->shared_from_this(), type);
- }
+QueueItem::QueueItem(QueueSP queue_sp, ProcessSP process_sp,
+ lldb::addr_t item_ref, lldb_private::Address address)
+ : m_queue_wp(), m_process_wp(), m_item_ref(item_ref), m_address(address),
+ m_have_fetched_entire_item(false), m_kind(eQueueItemKindUnknown),
+ m_item_that_enqueued_this_ref(LLDB_INVALID_ADDRESS),
+ m_enqueueing_thread_id(LLDB_INVALID_THREAD_ID),
+ m_enqueueing_queue_id(LLDB_INVALID_QUEUE_ID),
+ m_target_queue_id(LLDB_INVALID_QUEUE_ID), m_stop_id(0), m_backtrace(),
+ m_thread_label(), m_queue_label(), m_target_queue_label() {
+ m_queue_wp = queue_sp;
+ m_process_wp = process_sp;
+}
+
+QueueItem::~QueueItem() {}
+
+QueueItemKind QueueItem::GetKind() {
+ FetchEntireItem();
+ return m_kind;
+}
+
+void QueueItem::SetKind(QueueItemKind item_kind) { m_kind = item_kind; }
+
+Address &QueueItem::GetAddress() { return m_address; }
+
+void QueueItem::SetAddress(Address addr) { m_address = addr; }
+
+ThreadSP QueueItem::GetExtendedBacktraceThread(ConstString type) {
+ FetchEntireItem();
+ ThreadSP return_thread;
+ QueueSP queue_sp = m_queue_wp.lock();
+ if (queue_sp) {
+ ProcessSP process_sp = queue_sp->GetProcess();
+ if (process_sp && process_sp->GetSystemRuntime()) {
+ return_thread =
+ process_sp->GetSystemRuntime()->GetExtendedBacktraceForQueueItem(
+ this->shared_from_this(), type);
}
- return return_thread;
+ }
+ return return_thread;
}
-lldb::addr_t
-QueueItem::GetItemThatEnqueuedThis ()
-{
- FetchEntireItem ();
- return m_item_that_enqueued_this_ref;
-}
-
-lldb::tid_t
-QueueItem::GetEnqueueingThreadID ()
-{
- FetchEntireItem ();
- return m_enqueueing_thread_id;
-}
-
-lldb::queue_id_t
-QueueItem::GetEnqueueingQueueID ()
-{
- FetchEntireItem ();
- return m_enqueueing_queue_id;
-}
-
-uint32_t
-QueueItem::GetStopID ()
-{
- FetchEntireItem ();
- return m_stop_id;
-}
-
-std::vector<lldb::addr_t> &
-QueueItem::GetEnqueueingBacktrace ()
-{
- FetchEntireItem ();
- return m_backtrace;
-}
-
-std::string
-QueueItem::GetThreadLabel ()
-{
- FetchEntireItem ();
- return m_thread_label;
-}
-
-std::string
-QueueItem::GetQueueLabel ()
-{
- FetchEntireItem ();
- return m_queue_label;
-}
-
-
-ProcessSP
-QueueItem::GetProcessSP()
-{
- return m_process_wp.lock ();
-}
-
-void
-QueueItem::FetchEntireItem()
-{
- if (m_have_fetched_entire_item == true)
- return;
- ProcessSP process_sp = m_process_wp.lock();
- if (process_sp)
- {
- SystemRuntime *runtime = process_sp->GetSystemRuntime();
- if (runtime)
- {
- runtime->CompleteQueueItem (this, m_item_ref);
- m_have_fetched_entire_item = true;
- }
+lldb::addr_t QueueItem::GetItemThatEnqueuedThis() {
+ FetchEntireItem();
+ return m_item_that_enqueued_this_ref;
+}
+
+lldb::tid_t QueueItem::GetEnqueueingThreadID() {
+ FetchEntireItem();
+ return m_enqueueing_thread_id;
+}
+
+lldb::queue_id_t QueueItem::GetEnqueueingQueueID() {
+ FetchEntireItem();
+ return m_enqueueing_queue_id;
+}
+
+uint32_t QueueItem::GetStopID() {
+ FetchEntireItem();
+ return m_stop_id;
+}
+
+std::vector<lldb::addr_t> &QueueItem::GetEnqueueingBacktrace() {
+ FetchEntireItem();
+ return m_backtrace;
+}
+
+std::string QueueItem::GetThreadLabel() {
+ FetchEntireItem();
+ return m_thread_label;
+}
+
+std::string QueueItem::GetQueueLabel() {
+ FetchEntireItem();
+ return m_queue_label;
+}
+
+ProcessSP QueueItem::GetProcessSP() { return m_process_wp.lock(); }
+
+void QueueItem::FetchEntireItem() {
+ if (m_have_fetched_entire_item == true)
+ return;
+ ProcessSP process_sp = m_process_wp.lock();
+ if (process_sp) {
+ SystemRuntime *runtime = process_sp->GetSystemRuntime();
+ if (runtime) {
+ runtime->CompleteQueueItem(this, m_item_ref);
+ m_have_fetched_entire_item = true;
}
+ }
}
Modified: lldb/trunk/source/Target/QueueList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/QueueList.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/QueueList.cpp (original)
+++ lldb/trunk/source/Target/QueueList.cpp Tue Sep 6 15:57:50 2016
@@ -7,92 +7,64 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/Target/Process.h"
#include "lldb/Target/Queue.h"
+#include "lldb/Target/Process.h"
#include "lldb/Target/QueueList.h"
using namespace lldb;
using namespace lldb_private;
-QueueList::QueueList(Process *process) : m_process(process), m_stop_id(0), m_queues(), m_mutex()
-{
-}
+QueueList::QueueList(Process *process)
+ : m_process(process), m_stop_id(0), m_queues(), m_mutex() {}
-QueueList::~QueueList ()
-{
- Clear();
-}
+QueueList::~QueueList() { Clear(); }
-uint32_t
-QueueList::GetSize ()
-{
- std::lock_guard<std::mutex> guard(m_mutex);
- return m_queues.size();
+uint32_t QueueList::GetSize() {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ return m_queues.size();
}
-lldb::QueueSP
-QueueList::GetQueueAtIndex (uint32_t idx)
-{
- std::lock_guard<std::mutex> guard(m_mutex);
- if (idx < m_queues.size())
- {
- return m_queues[idx];
- }
- else
- {
- return QueueSP();
- }
+lldb::QueueSP QueueList::GetQueueAtIndex(uint32_t idx) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ if (idx < m_queues.size()) {
+ return m_queues[idx];
+ } else {
+ return QueueSP();
+ }
}
-void
-QueueList::Clear ()
-{
- std::lock_guard<std::mutex> guard(m_mutex);
- m_queues.clear();
+void QueueList::Clear() {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ m_queues.clear();
}
-void
-QueueList::AddQueue (QueueSP queue_sp)
-{
- std::lock_guard<std::mutex> guard(m_mutex);
- if (queue_sp.get ())
- {
- m_queues.push_back (queue_sp);
- }
+void QueueList::AddQueue(QueueSP queue_sp) {
+ std::lock_guard<std::mutex> guard(m_mutex);
+ if (queue_sp.get()) {
+ m_queues.push_back(queue_sp);
+ }
}
-lldb::QueueSP
-QueueList::FindQueueByID (lldb::queue_id_t qid)
-{
- QueueSP ret;
- for (QueueSP queue_sp : Queues())
- {
- if (queue_sp->GetID() == qid)
- {
- ret = queue_sp;
- break;
- }
+lldb::QueueSP QueueList::FindQueueByID(lldb::queue_id_t qid) {
+ QueueSP ret;
+ for (QueueSP queue_sp : Queues()) {
+ if (queue_sp->GetID() == qid) {
+ ret = queue_sp;
+ break;
}
- return ret;
+ }
+ return ret;
}
-lldb::QueueSP
-QueueList::FindQueueByIndexID (uint32_t index_id)
-{
- QueueSP ret;
- for (QueueSP queue_sp : Queues())
- {
- if (queue_sp->GetIndexID() == index_id)
- {
- ret = queue_sp;
- break;
- }
+lldb::QueueSP QueueList::FindQueueByIndexID(uint32_t index_id) {
+ QueueSP ret;
+ for (QueueSP queue_sp : Queues()) {
+ if (queue_sp->GetIndexID() == index_id) {
+ ret = queue_sp;
+ break;
}
- return ret;
+ }
+ return ret;
}
-std::mutex &
-QueueList::GetMutex()
-{
- return m_mutex;
-}
+std::mutex &QueueList::GetMutex() { return m_mutex; }
Modified: lldb/trunk/source/Target/RegisterContext.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/RegisterContext.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/RegisterContext.cpp (original)
+++ lldb/trunk/source/Target/RegisterContext.cpp Tue Sep 6 15:57:50 2016
@@ -13,543 +13,455 @@
// Project includes
#include "lldb/Target/RegisterContext.h"
#include "lldb/Core/DataExtractor.h"
+#include "lldb/Core/Module.h"
#include "lldb/Core/RegisterValue.h"
#include "lldb/Core/Scalar.h"
+#include "lldb/Core/Value.h"
+#include "lldb/Expression/DWARFExpression.h"
#include "lldb/Host/Endian.h"
#include "lldb/Target/ExecutionContext.h"
-#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Process.h"
-#include "lldb/Target/Thread.h"
+#include "lldb/Target/StackFrame.h"
#include "lldb/Target/Target.h"
-#include "lldb/Core/Module.h"
-#include "lldb/Expression/DWARFExpression.h"
-#include "lldb/Core/Value.h"
+#include "lldb/Target/Thread.h"
using namespace lldb;
using namespace lldb_private;
-RegisterContext::RegisterContext (Thread &thread, uint32_t concrete_frame_idx) :
- m_thread (thread),
- m_concrete_frame_idx (concrete_frame_idx),
- m_stop_id (thread.GetProcess()->GetStopID())
-{
-}
+RegisterContext::RegisterContext(Thread &thread, uint32_t concrete_frame_idx)
+ : m_thread(thread), m_concrete_frame_idx(concrete_frame_idx),
+ m_stop_id(thread.GetProcess()->GetStopID()) {}
RegisterContext::~RegisterContext() = default;
-void
-RegisterContext::InvalidateIfNeeded (bool force)
-{
- ProcessSP process_sp (m_thread.GetProcess());
- bool invalidate = force;
- uint32_t process_stop_id = UINT32_MAX;
+void RegisterContext::InvalidateIfNeeded(bool force) {
+ ProcessSP process_sp(m_thread.GetProcess());
+ bool invalidate = force;
+ uint32_t process_stop_id = UINT32_MAX;
+
+ if (process_sp)
+ process_stop_id = process_sp->GetStopID();
+ else
+ invalidate = true;
+
+ if (!invalidate)
+ invalidate = process_stop_id != GetStopID();
+
+ if (invalidate) {
+ InvalidateAllRegisters();
+ SetStopID(process_stop_id);
+ }
+}
+
+const RegisterInfo *RegisterContext::GetRegisterInfoByName(const char *reg_name,
+ uint32_t start_idx) {
+ if (reg_name && reg_name[0]) {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = start_idx; reg < num_registers; ++reg) {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
- if (process_sp)
- process_stop_id = process_sp->GetStopID();
- else
- invalidate = true;
-
- if (!invalidate)
- invalidate = process_stop_id != GetStopID();
-
- if (invalidate)
- {
- InvalidateAllRegisters ();
- SetStopID (process_stop_id);
+ if ((reg_info->name != nullptr &&
+ ::strcasecmp(reg_info->name, reg_name) == 0) ||
+ (reg_info->alt_name != nullptr &&
+ ::strcasecmp(reg_info->alt_name, reg_name) == 0)) {
+ return reg_info;
+ }
}
+ }
+ return nullptr;
}
-const RegisterInfo *
-RegisterContext::GetRegisterInfoByName (const char *reg_name, uint32_t start_idx)
-{
- if (reg_name && reg_name[0])
- {
- const uint32_t num_registers = GetRegisterCount();
- for (uint32_t reg = start_idx; reg < num_registers; ++reg)
- {
- const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
-
- if ((reg_info->name != nullptr && ::strcasecmp (reg_info->name, reg_name) == 0) ||
- (reg_info->alt_name != nullptr && ::strcasecmp (reg_info->alt_name, reg_name) == 0))
- {
- return reg_info;
- }
- }
- }
+uint32_t
+RegisterContext::UpdateDynamicRegisterSize(const lldb_private::ArchSpec &arch,
+ RegisterInfo *reg_info) {
+ ExecutionContext exe_ctx(CalculateThread());
+
+ // In MIPS, the floating point registers size is depends on FR bit of SR
+ // register.
+ // if SR.FR == 1 then all floating point registers are 64 bits.
+ // else they are all 32 bits.
+
+ int expr_result;
+ uint32_t addr_size = arch.GetAddressByteSize();
+ const uint8_t *dwarf_opcode_ptr = reg_info->dynamic_size_dwarf_expr_bytes;
+ const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len;
+
+ DataExtractor dwarf_data(dwarf_opcode_ptr, dwarf_opcode_len,
+ arch.GetByteOrder(), addr_size);
+ ModuleSP opcode_ctx;
+ DWARFExpression dwarf_expr(opcode_ctx, dwarf_data, nullptr, 0,
+ dwarf_opcode_len);
+ Value result;
+ Error error;
+ const lldb::offset_t offset = 0;
+ if (dwarf_expr.Evaluate(&exe_ctx, nullptr, nullptr, this, opcode_ctx,
+ dwarf_data, nullptr, offset, dwarf_opcode_len,
+ eRegisterKindDWARF, nullptr, nullptr, result,
+ &error)) {
+ expr_result = result.GetScalar().SInt(-1);
+ switch (expr_result) {
+ case 0:
+ return 4;
+ case 1:
+ return 8;
+ default:
+ return reg_info->byte_size;
+ }
+ } else {
+ printf("Error executing DwarfExpression::Evaluate %s\n", error.AsCString());
+ return reg_info->byte_size;
+ }
+}
+
+const RegisterInfo *RegisterContext::GetRegisterInfo(lldb::RegisterKind kind,
+ uint32_t num) {
+ const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
+ if (reg_num == LLDB_INVALID_REGNUM)
return nullptr;
+ return GetRegisterInfoAtIndex(reg_num);
}
-uint32_t
-RegisterContext::UpdateDynamicRegisterSize (const lldb_private::ArchSpec &arch,
- RegisterInfo* reg_info)
-{
- ExecutionContext exe_ctx (CalculateThread());
-
- // In MIPS, the floating point registers size is depends on FR bit of SR register.
- // if SR.FR == 1 then all floating point registers are 64 bits.
- // else they are all 32 bits.
-
- int expr_result;
- uint32_t addr_size = arch.GetAddressByteSize ();
- const uint8_t* dwarf_opcode_ptr = reg_info->dynamic_size_dwarf_expr_bytes;
- const size_t dwarf_opcode_len = reg_info->dynamic_size_dwarf_len;
-
- DataExtractor dwarf_data (dwarf_opcode_ptr, dwarf_opcode_len,
- arch.GetByteOrder (), addr_size);
- ModuleSP opcode_ctx;
- DWARFExpression dwarf_expr (opcode_ctx, dwarf_data, nullptr, 0, dwarf_opcode_len);
- Value result;
- Error error;
- const lldb::offset_t offset = 0;
- if (dwarf_expr.Evaluate (&exe_ctx, nullptr, nullptr, this, opcode_ctx, dwarf_data, nullptr,
- offset, dwarf_opcode_len, eRegisterKindDWARF, nullptr, nullptr, result, &error))
- {
- expr_result = result.GetScalar ().SInt (-1);
- switch (expr_result)
- {
- case 0: return 4;
- case 1: return 8;
- default: return reg_info->byte_size;
- }
- }
- else
- {
- printf ("Error executing DwarfExpression::Evaluate %s\n", error.AsCString());
- return reg_info->byte_size;
- }
+const char *RegisterContext::GetRegisterName(uint32_t reg) {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (reg_info)
+ return reg_info->name;
+ return nullptr;
}
-const RegisterInfo *
-RegisterContext::GetRegisterInfo (lldb::RegisterKind kind, uint32_t num)
-{
- const uint32_t reg_num = ConvertRegisterKindToRegisterNumber(kind, num);
- if (reg_num == LLDB_INVALID_REGNUM)
- return nullptr;
- return GetRegisterInfoAtIndex (reg_num);
-}
+uint64_t RegisterContext::GetPC(uint64_t fail_value) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+ uint64_t pc = ReadRegisterAsUnsigned(reg, fail_value);
-const char *
-RegisterContext::GetRegisterName (uint32_t reg)
-{
- const RegisterInfo * reg_info = GetRegisterInfoAtIndex(reg);
- if (reg_info)
- return reg_info->name;
- return nullptr;
+ if (pc != fail_value) {
+ TargetSP target_sp = m_thread.CalculateTarget();
+ if (target_sp) {
+ Target *target = target_sp.get();
+ if (target)
+ pc = target->GetOpcodeLoadAddress(pc, eAddressClassCode);
+ }
+ }
+
+ return pc;
+}
+
+bool RegisterContext::SetPC(uint64_t pc) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_PC);
+ bool success = WriteRegisterFromUnsigned(reg, pc);
+ if (success) {
+ StackFrameSP frame_sp(
+ m_thread.GetFrameWithConcreteFrameIndex(m_concrete_frame_idx));
+ if (frame_sp)
+ frame_sp->ChangePC(pc);
+ else
+ m_thread.ClearStackFrames();
+ }
+ return success;
}
-uint64_t
-RegisterContext::GetPC(uint64_t fail_value)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
- uint64_t pc = ReadRegisterAsUnsigned (reg, fail_value);
-
- if (pc != fail_value)
- {
- TargetSP target_sp = m_thread.CalculateTarget();
- if (target_sp)
- {
- Target *target = target_sp.get();
- if (target)
- pc = target->GetOpcodeLoadAddress (pc, eAddressClassCode);
- }
- }
+bool RegisterContext::SetPC(Address addr) {
+ TargetSP target_sp = m_thread.CalculateTarget();
+ Target *target = target_sp.get();
- return pc;
-}
+ lldb::addr_t callAddr = addr.GetCallableLoadAddress(target);
+ if (callAddr == LLDB_INVALID_ADDRESS)
+ return false;
-bool
-RegisterContext::SetPC(uint64_t pc)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC);
- bool success = WriteRegisterFromUnsigned (reg, pc);
- if (success)
- {
- StackFrameSP frame_sp(m_thread.GetFrameWithConcreteFrameIndex (m_concrete_frame_idx));
- if (frame_sp)
- frame_sp->ChangePC(pc);
- else
- m_thread.ClearStackFrames ();
- }
- return success;
+ return SetPC(callAddr);
}
-bool
-RegisterContext::SetPC(Address addr)
-{
- TargetSP target_sp = m_thread.CalculateTarget();
- Target *target = target_sp.get();
-
- lldb::addr_t callAddr = addr.GetCallableLoadAddress (target);
- if (callAddr == LLDB_INVALID_ADDRESS)
- return false;
-
- return SetPC (callAddr);
+uint64_t RegisterContext::GetSP(uint64_t fail_value) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_SP);
+ return ReadRegisterAsUnsigned(reg, fail_value);
}
-uint64_t
-RegisterContext::GetSP(uint64_t fail_value)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
- return ReadRegisterAsUnsigned (reg, fail_value);
+bool RegisterContext::SetSP(uint64_t sp) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_SP);
+ return WriteRegisterFromUnsigned(reg, sp);
}
-bool
-RegisterContext::SetSP(uint64_t sp)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_SP);
- return WriteRegisterFromUnsigned (reg, sp);
+uint64_t RegisterContext::GetFP(uint64_t fail_value) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_FP);
+ return ReadRegisterAsUnsigned(reg, fail_value);
}
-uint64_t
-RegisterContext::GetFP(uint64_t fail_value)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
- return ReadRegisterAsUnsigned (reg, fail_value);
+bool RegisterContext::SetFP(uint64_t fp) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_FP);
+ return WriteRegisterFromUnsigned(reg, fp);
}
-bool
-RegisterContext::SetFP(uint64_t fp)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FP);
- return WriteRegisterFromUnsigned (reg, fp);
+uint64_t RegisterContext::GetReturnAddress(uint64_t fail_value) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_RA);
+ return ReadRegisterAsUnsigned(reg, fail_value);
}
-uint64_t
-RegisterContext::GetReturnAddress (uint64_t fail_value)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_RA);
- return ReadRegisterAsUnsigned (reg, fail_value);
+uint64_t RegisterContext::GetFlags(uint64_t fail_value) {
+ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric,
+ LLDB_REGNUM_GENERIC_FLAGS);
+ return ReadRegisterAsUnsigned(reg, fail_value);
}
-uint64_t
-RegisterContext::GetFlags (uint64_t fail_value)
-{
- uint32_t reg = ConvertRegisterKindToRegisterNumber (eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS);
- return ReadRegisterAsUnsigned (reg, fail_value);
+uint64_t RegisterContext::ReadRegisterAsUnsigned(uint32_t reg,
+ uint64_t fail_value) {
+ if (reg != LLDB_INVALID_REGNUM)
+ return ReadRegisterAsUnsigned(GetRegisterInfoAtIndex(reg), fail_value);
+ return fail_value;
}
-uint64_t
-RegisterContext::ReadRegisterAsUnsigned (uint32_t reg, uint64_t fail_value)
-{
- if (reg != LLDB_INVALID_REGNUM)
- return ReadRegisterAsUnsigned (GetRegisterInfoAtIndex (reg), fail_value);
- return fail_value;
+uint64_t RegisterContext::ReadRegisterAsUnsigned(const RegisterInfo *reg_info,
+ uint64_t fail_value) {
+ if (reg_info) {
+ RegisterValue value;
+ if (ReadRegister(reg_info, value))
+ return value.GetAsUInt64();
+ }
+ return fail_value;
}
-uint64_t
-RegisterContext::ReadRegisterAsUnsigned (const RegisterInfo *reg_info, uint64_t fail_value)
-{
- if (reg_info)
- {
- RegisterValue value;
- if (ReadRegister (reg_info, value))
- return value.GetAsUInt64();
- }
- return fail_value;
+bool RegisterContext::WriteRegisterFromUnsigned(uint32_t reg, uint64_t uval) {
+ if (reg == LLDB_INVALID_REGNUM)
+ return false;
+ return WriteRegisterFromUnsigned(GetRegisterInfoAtIndex(reg), uval);
}
-bool
-RegisterContext::WriteRegisterFromUnsigned (uint32_t reg, uint64_t uval)
-{
- if (reg == LLDB_INVALID_REGNUM)
- return false;
- return WriteRegisterFromUnsigned (GetRegisterInfoAtIndex (reg), uval);
-}
-
-bool
-RegisterContext::WriteRegisterFromUnsigned (const RegisterInfo *reg_info, uint64_t uval)
-{
- if (reg_info)
- {
- RegisterValue value;
- if (value.SetUInt(uval, reg_info->byte_size))
- return WriteRegister (reg_info, value);
- }
+bool RegisterContext::WriteRegisterFromUnsigned(const RegisterInfo *reg_info,
+ uint64_t uval) {
+ if (reg_info) {
+ RegisterValue value;
+ if (value.SetUInt(uval, reg_info->byte_size))
+ return WriteRegister(reg_info, value);
+ }
+ return false;
+}
+
+bool RegisterContext::CopyFromRegisterContext(lldb::RegisterContextSP context) {
+ uint32_t num_register_sets = context->GetRegisterSetCount();
+ // We don't know that two threads have the same register context, so require
+ // the threads to be the same.
+ if (context->GetThreadID() != GetThreadID())
return false;
-}
-bool
-RegisterContext::CopyFromRegisterContext (lldb::RegisterContextSP context)
-{
- uint32_t num_register_sets = context->GetRegisterSetCount();
- // We don't know that two threads have the same register context, so require the threads to be the same.
- if (context->GetThreadID() != GetThreadID())
- return false;
-
- if (num_register_sets != GetRegisterSetCount())
- return false;
-
- RegisterContextSP frame_zero_context = m_thread.GetRegisterContext();
-
- for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx)
- {
- const RegisterSet * const reg_set = GetRegisterSet(set_idx);
-
- const uint32_t num_registers = reg_set->num_registers;
- for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx)
- {
- const uint32_t reg = reg_set->registers[reg_idx];
- const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
- if (!reg_info || reg_info->value_regs)
- continue;
- RegisterValue reg_value;
-
- // If we can reconstruct the register from the frame we are copying from, then do so, otherwise
- // use the value from frame 0.
- if (context->ReadRegister(reg_info, reg_value))
- {
- WriteRegister(reg_info, reg_value);
- }
- else if (frame_zero_context->ReadRegister(reg_info, reg_value))
- {
- WriteRegister(reg_info, reg_value);
- }
- }
+ if (num_register_sets != GetRegisterSetCount())
+ return false;
+
+ RegisterContextSP frame_zero_context = m_thread.GetRegisterContext();
+
+ for (uint32_t set_idx = 0; set_idx < num_register_sets; ++set_idx) {
+ const RegisterSet *const reg_set = GetRegisterSet(set_idx);
+
+ const uint32_t num_registers = reg_set->num_registers;
+ for (uint32_t reg_idx = 0; reg_idx < num_registers; ++reg_idx) {
+ const uint32_t reg = reg_set->registers[reg_idx];
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+ if (!reg_info || reg_info->value_regs)
+ continue;
+ RegisterValue reg_value;
+
+ // If we can reconstruct the register from the frame we are copying from,
+ // then do so, otherwise
+ // use the value from frame 0.
+ if (context->ReadRegister(reg_info, reg_value)) {
+ WriteRegister(reg_info, reg_value);
+ } else if (frame_zero_context->ReadRegister(reg_info, reg_value)) {
+ WriteRegister(reg_info, reg_value);
+ }
}
- return true;
+ }
+ return true;
}
-lldb::tid_t
-RegisterContext::GetThreadID() const
-{
- return m_thread.GetID();
-}
+lldb::tid_t RegisterContext::GetThreadID() const { return m_thread.GetID(); }
-uint32_t
-RegisterContext::NumSupportedHardwareBreakpoints ()
-{
- return 0;
-}
+uint32_t RegisterContext::NumSupportedHardwareBreakpoints() { return 0; }
-uint32_t
-RegisterContext::SetHardwareBreakpoint (lldb::addr_t addr, size_t size)
-{
- return LLDB_INVALID_INDEX32;
+uint32_t RegisterContext::SetHardwareBreakpoint(lldb::addr_t addr,
+ size_t size) {
+ return LLDB_INVALID_INDEX32;
}
-bool
-RegisterContext::ClearHardwareBreakpoint (uint32_t hw_idx)
-{
- return false;
-}
+bool RegisterContext::ClearHardwareBreakpoint(uint32_t hw_idx) { return false; }
-uint32_t
-RegisterContext::NumSupportedHardwareWatchpoints ()
-{
- return 0;
-}
+uint32_t RegisterContext::NumSupportedHardwareWatchpoints() { return 0; }
-uint32_t
-RegisterContext::SetHardwareWatchpoint (lldb::addr_t addr, size_t size, bool read, bool write)
-{
- return LLDB_INVALID_INDEX32;
+uint32_t RegisterContext::SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
+ bool read, bool write) {
+ return LLDB_INVALID_INDEX32;
}
-bool
-RegisterContext::ClearHardwareWatchpoint (uint32_t hw_index)
-{
- return false;
+bool RegisterContext::ClearHardwareWatchpoint(uint32_t hw_index) {
+ return false;
}
-bool
-RegisterContext::HardwareSingleStep (bool enable)
-{
- return false;
-}
+bool RegisterContext::HardwareSingleStep(bool enable) { return false; }
-Error
-RegisterContext::ReadRegisterValueFromMemory (const RegisterInfo *reg_info,
- lldb::addr_t src_addr,
- uint32_t src_len,
- RegisterValue ®_value)
-{
- Error error;
- if (reg_info == nullptr)
- {
- error.SetErrorString ("invalid register info argument.");
- return error;
- }
+Error RegisterContext::ReadRegisterValueFromMemory(const RegisterInfo *reg_info,
+ lldb::addr_t src_addr,
+ uint32_t src_len,
+ RegisterValue ®_value) {
+ Error error;
+ if (reg_info == nullptr) {
+ error.SetErrorString("invalid register info argument.");
+ return error;
+ }
- // Moving from addr into a register
- //
- // Case 1: src_len == dst_len
- //
- // |AABBCCDD| Address contents
- // |AABBCCDD| Register contents
- //
- // Case 2: src_len > dst_len
- //
- // Error! (The register should always be big enough to hold the data)
- //
- // Case 3: src_len < dst_len
- //
- // |AABB| Address contents
- // |AABB0000| Register contents [on little-endian hardware]
- // |0000AABB| Register contents [on big-endian hardware]
- if (src_len > RegisterValue::kMaxRegisterByteSize)
- {
- error.SetErrorString ("register too small to receive memory data");
- return error;
- }
-
- const uint32_t dst_len = reg_info->byte_size;
-
- if (src_len > dst_len)
- {
- error.SetErrorStringWithFormat("%u bytes is too big to store in register %s (%u bytes)", src_len, reg_info->name, dst_len);
- return error;
- }
-
- ProcessSP process_sp (m_thread.GetProcess());
- if (process_sp)
- {
- uint8_t src[RegisterValue::kMaxRegisterByteSize];
-
- // Read the memory
- const uint32_t bytes_read = process_sp->ReadMemory (src_addr, src, src_len, error);
-
- // Make sure the memory read succeeded...
- if (bytes_read != src_len)
- {
- if (error.Success())
- {
- // This might happen if we read _some_ bytes but not all
- error.SetErrorStringWithFormat("read %u of %u bytes", bytes_read, src_len);
- }
- return error;
- }
-
- // We now have a memory buffer that contains the part or all of the register
- // value. Set the register value using this memory data.
- // TODO: we might need to add a parameter to this function in case the byte
- // order of the memory data doesn't match the process. For now we are assuming
- // they are the same.
- reg_value.SetFromMemoryData (reg_info,
- src,
- src_len,
- process_sp->GetByteOrder(),
- error);
- }
- else
- error.SetErrorString("invalid process");
+ // Moving from addr into a register
+ //
+ // Case 1: src_len == dst_len
+ //
+ // |AABBCCDD| Address contents
+ // |AABBCCDD| Register contents
+ //
+ // Case 2: src_len > dst_len
+ //
+ // Error! (The register should always be big enough to hold the data)
+ //
+ // Case 3: src_len < dst_len
+ //
+ // |AABB| Address contents
+ // |AABB0000| Register contents [on little-endian hardware]
+ // |0000AABB| Register contents [on big-endian hardware]
+ if (src_len > RegisterValue::kMaxRegisterByteSize) {
+ error.SetErrorString("register too small to receive memory data");
+ return error;
+ }
+
+ const uint32_t dst_len = reg_info->byte_size;
+ if (src_len > dst_len) {
+ error.SetErrorStringWithFormat(
+ "%u bytes is too big to store in register %s (%u bytes)", src_len,
+ reg_info->name, dst_len);
return error;
-}
+ }
-Error
-RegisterContext::WriteRegisterValueToMemory (const RegisterInfo *reg_info,
- lldb::addr_t dst_addr,
- uint32_t dst_len,
- const RegisterValue ®_value)
-{
- uint8_t dst[RegisterValue::kMaxRegisterByteSize];
-
- Error error;
-
- ProcessSP process_sp (m_thread.GetProcess());
- if (process_sp)
- {
-
- // TODO: we might need to add a parameter to this function in case the byte
- // order of the memory data doesn't match the process. For now we are assuming
- // they are the same.
-
- const uint32_t bytes_copied = reg_value.GetAsMemoryData (reg_info,
- dst,
- dst_len,
- process_sp->GetByteOrder(),
- error);
-
- if (error.Success())
- {
- if (bytes_copied == 0)
- {
- error.SetErrorString("byte copy failed.");
- }
- else
- {
- const uint32_t bytes_written = process_sp->WriteMemory (dst_addr, dst, bytes_copied, error);
- if (bytes_written != bytes_copied)
- {
- if (error.Success())
- {
- // This might happen if we read _some_ bytes but not all
- error.SetErrorStringWithFormat("only wrote %u of %u bytes", bytes_written, bytes_copied);
- }
- }
- }
+ ProcessSP process_sp(m_thread.GetProcess());
+ if (process_sp) {
+ uint8_t src[RegisterValue::kMaxRegisterByteSize];
+
+ // Read the memory
+ const uint32_t bytes_read =
+ process_sp->ReadMemory(src_addr, src, src_len, error);
+
+ // Make sure the memory read succeeded...
+ if (bytes_read != src_len) {
+ if (error.Success()) {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("read %u of %u bytes", bytes_read,
+ src_len);
+ }
+ return error;
+ }
+
+ // We now have a memory buffer that contains the part or all of the register
+ // value. Set the register value using this memory data.
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are
+ // assuming
+ // they are the same.
+ reg_value.SetFromMemoryData(reg_info, src, src_len,
+ process_sp->GetByteOrder(), error);
+ } else
+ error.SetErrorString("invalid process");
+
+ return error;
+}
+
+Error RegisterContext::WriteRegisterValueToMemory(
+ const RegisterInfo *reg_info, lldb::addr_t dst_addr, uint32_t dst_len,
+ const RegisterValue ®_value) {
+ uint8_t dst[RegisterValue::kMaxRegisterByteSize];
+
+ Error error;
+
+ ProcessSP process_sp(m_thread.GetProcess());
+ if (process_sp) {
+
+ // TODO: we might need to add a parameter to this function in case the byte
+ // order of the memory data doesn't match the process. For now we are
+ // assuming
+ // they are the same.
+
+ const uint32_t bytes_copied = reg_value.GetAsMemoryData(
+ reg_info, dst, dst_len, process_sp->GetByteOrder(), error);
+
+ if (error.Success()) {
+ if (bytes_copied == 0) {
+ error.SetErrorString("byte copy failed.");
+ } else {
+ const uint32_t bytes_written =
+ process_sp->WriteMemory(dst_addr, dst, bytes_copied, error);
+ if (bytes_written != bytes_copied) {
+ if (error.Success()) {
+ // This might happen if we read _some_ bytes but not all
+ error.SetErrorStringWithFormat("only wrote %u of %u bytes",
+ bytes_written, bytes_copied);
+ }
}
+ }
}
- else
- error.SetErrorString("invalid process");
+ } else
+ error.SetErrorString("invalid process");
- return error;
+ return error;
}
-bool
-RegisterContext::ReadAllRegisterValues (lldb_private::RegisterCheckpoint ®_checkpoint)
-{
- return ReadAllRegisterValues(reg_checkpoint.GetData());
+bool RegisterContext::ReadAllRegisterValues(
+ lldb_private::RegisterCheckpoint ®_checkpoint) {
+ return ReadAllRegisterValues(reg_checkpoint.GetData());
}
-bool
-RegisterContext::WriteAllRegisterValues (const lldb_private::RegisterCheckpoint ®_checkpoint)
-{
- return WriteAllRegisterValues(reg_checkpoint.GetData());
+bool RegisterContext::WriteAllRegisterValues(
+ const lldb_private::RegisterCheckpoint ®_checkpoint) {
+ return WriteAllRegisterValues(reg_checkpoint.GetData());
}
-TargetSP
-RegisterContext::CalculateTarget ()
-{
- return m_thread.CalculateTarget();
+TargetSP RegisterContext::CalculateTarget() {
+ return m_thread.CalculateTarget();
}
-ProcessSP
-RegisterContext::CalculateProcess ()
-{
- return m_thread.CalculateProcess ();
+ProcessSP RegisterContext::CalculateProcess() {
+ return m_thread.CalculateProcess();
}
-ThreadSP
-RegisterContext::CalculateThread ()
-{
- return m_thread.shared_from_this();
+ThreadSP RegisterContext::CalculateThread() {
+ return m_thread.shared_from_this();
}
-StackFrameSP
-RegisterContext::CalculateStackFrame ()
-{
- // Register contexts might belong to many frames if we have inlined
- // functions inside a frame since all inlined functions share the
- // same registers, so we can't definitively say which frame we come from...
- return StackFrameSP();
+StackFrameSP RegisterContext::CalculateStackFrame() {
+ // Register contexts might belong to many frames if we have inlined
+ // functions inside a frame since all inlined functions share the
+ // same registers, so we can't definitively say which frame we come from...
+ return StackFrameSP();
}
-void
-RegisterContext::CalculateExecutionContext (ExecutionContext &exe_ctx)
-{
- m_thread.CalculateExecutionContext (exe_ctx);
+void RegisterContext::CalculateExecutionContext(ExecutionContext &exe_ctx) {
+ m_thread.CalculateExecutionContext(exe_ctx);
}
-bool
-RegisterContext::ConvertBetweenRegisterKinds (lldb::RegisterKind source_rk, uint32_t source_regnum, lldb::RegisterKind target_rk, uint32_t& target_regnum)
-{
- const uint32_t num_registers = GetRegisterCount();
- for (uint32_t reg = 0; reg < num_registers; ++reg)
- {
- const RegisterInfo * reg_info = GetRegisterInfoAtIndex (reg);
-
- if (reg_info->kinds[source_rk] == source_regnum)
- {
- target_regnum = reg_info->kinds[target_rk];
- return (target_regnum != LLDB_INVALID_REGNUM);
- }
+bool RegisterContext::ConvertBetweenRegisterKinds(lldb::RegisterKind source_rk,
+ uint32_t source_regnum,
+ lldb::RegisterKind target_rk,
+ uint32_t &target_regnum) {
+ const uint32_t num_registers = GetRegisterCount();
+ for (uint32_t reg = 0; reg < num_registers; ++reg) {
+ const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg);
+
+ if (reg_info->kinds[source_rk] == source_regnum) {
+ target_regnum = reg_info->kinds[target_rk];
+ return (target_regnum != LLDB_INVALID_REGNUM);
}
- return false;
+ }
+ return false;
}
-//bool
-//RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
+// bool
+// RegisterContext::ReadRegisterValue (uint32_t reg, Scalar &value)
//{
// DataExtractor data;
// if (!ReadRegisterBytes (reg, data))
@@ -594,7 +506,8 @@ RegisterContext::ConvertBetweenRegisterK
// case 1:
// {
// int8_t v;
-// if (data.ExtractBytes (0, sizeof (int8_t), endian::InlHostByteOrder(), &v) != sizeof (int8_t))
+// if (data.ExtractBytes (0, sizeof (int8_t),
+// endian::InlHostByteOrder(), &v) != sizeof (int8_t))
// return false;
// value = v;
// return true;
@@ -602,7 +515,8 @@ RegisterContext::ConvertBetweenRegisterK
// case 2:
// {
// int16_t v;
-// if (data.ExtractBytes (0, sizeof (int16_t), endian::InlHostByteOrder(), &v) != sizeof (int16_t))
+// if (data.ExtractBytes (0, sizeof (int16_t),
+// endian::InlHostByteOrder(), &v) != sizeof (int16_t))
// return false;
// value = v;
// return true;
@@ -610,7 +524,8 @@ RegisterContext::ConvertBetweenRegisterK
// case 4:
// {
// int32_t v;
-// if (data.ExtractBytes (0, sizeof (int32_t), endian::InlHostByteOrder(), &v) != sizeof (int32_t))
+// if (data.ExtractBytes (0, sizeof (int32_t),
+// endian::InlHostByteOrder(), &v) != sizeof (int32_t))
// return false;
// value = v;
// return true;
@@ -618,7 +533,8 @@ RegisterContext::ConvertBetweenRegisterK
// case 8:
// {
// int64_t v;
-// if (data.ExtractBytes (0, sizeof (int64_t), endian::InlHostByteOrder(), &v) != sizeof (int64_t))
+// if (data.ExtractBytes (0, sizeof (int64_t),
+// endian::InlHostByteOrder(), &v) != sizeof (int64_t))
// return false;
// value = v;
// return true;
@@ -631,7 +547,8 @@ RegisterContext::ConvertBetweenRegisterK
// case sizeof (float):
// {
// float v;
-// if (data.ExtractBytes (0, sizeof (float), endian::InlHostByteOrder(), &v) != sizeof (float))
+// if (data.ExtractBytes (0, sizeof (float),
+// endian::InlHostByteOrder(), &v) != sizeof (float))
// return false;
// value = v;
// return true;
@@ -639,7 +556,8 @@ RegisterContext::ConvertBetweenRegisterK
// case sizeof (double):
// {
// double v;
-// if (data.ExtractBytes (0, sizeof (double), endian::InlHostByteOrder(), &v) != sizeof (double))
+// if (data.ExtractBytes (0, sizeof (double),
+// endian::InlHostByteOrder(), &v) != sizeof (double))
// return false;
// value = v;
// return true;
@@ -647,7 +565,8 @@ RegisterContext::ConvertBetweenRegisterK
// case sizeof (long double):
// {
// double v;
-// if (data.ExtractBytes (0, sizeof (long double), endian::InlHostByteOrder(), &v) != sizeof (long double))
+// if (data.ExtractBytes (0, sizeof (long double),
+// endian::InlHostByteOrder(), &v) != sizeof (long double))
// return false;
// value = v;
// return true;
@@ -658,8 +577,8 @@ RegisterContext::ConvertBetweenRegisterK
// return false;
//}
//
-//bool
-//RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
+// bool
+// RegisterContext::WriteRegisterValue (uint32_t reg, const Scalar &value)
//{
// DataExtractor data;
// if (!value.IsValid())
Modified: lldb/trunk/source/Target/SectionLoadHistory.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/SectionLoadHistory.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/SectionLoadHistory.cpp (original)
+++ lldb/trunk/source/Target/SectionLoadHistory.cpp Tue Sep 6 15:57:50 2016
@@ -19,161 +19,154 @@
using namespace lldb;
using namespace lldb_private;
-
-bool
-SectionLoadHistory::IsEmpty() const
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- return m_stop_id_to_section_load_list.empty();
-}
-
-void
-SectionLoadHistory::Clear ()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- m_stop_id_to_section_load_list.clear();
-}
-
-uint32_t
-SectionLoadHistory::GetLastStopID() const
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (m_stop_id_to_section_load_list.empty())
- return 0;
- else
- return m_stop_id_to_section_load_list.rbegin()->first;
+bool SectionLoadHistory::IsEmpty() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return m_stop_id_to_section_load_list.empty();
+}
+
+void SectionLoadHistory::Clear() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_stop_id_to_section_load_list.clear();
+}
+
+uint32_t SectionLoadHistory::GetLastStopID() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_stop_id_to_section_load_list.empty())
+ return 0;
+ else
+ return m_stop_id_to_section_load_list.rbegin()->first;
}
SectionLoadList *
-SectionLoadHistory::GetSectionLoadListForStopID (uint32_t stop_id, bool read_only)
-{
- if (!m_stop_id_to_section_load_list.empty())
- {
- if (read_only)
- {
- // The section load list is for reading data only so we don't need to create
- // a new SectionLoadList for the current stop ID, just return the section
- // load list for the stop ID that is equal to or less than the current stop ID
- if (stop_id == eStopIDNow)
- {
- // If we are asking for the latest and greatest value, it is always
- // at the end of our list because that will be the highest stop ID.
- StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin();
- return rpos->second.get();
- }
- else
- {
- StopIDToSectionLoadList::iterator pos = m_stop_id_to_section_load_list.lower_bound(stop_id);
- if (pos != m_stop_id_to_section_load_list.end() && pos->first == stop_id)
- return pos->second.get();
- else if (pos != m_stop_id_to_section_load_list.begin())
- {
- --pos;
- return pos->second.get();
- }
- }
- }
- else
- {
- // You can only use "eStopIDNow" when reading from the section load history
- assert(stop_id != eStopIDNow);
-
- // We are updating the section load list (not read only), so if the stop ID
- // passed in isn't the same as the last stop ID in our collection, then create
- // a new node using the current stop ID
- StopIDToSectionLoadList::iterator pos = m_stop_id_to_section_load_list.lower_bound(stop_id);
- if (pos != m_stop_id_to_section_load_list.end() && pos->first == stop_id)
- {
- // We already have an entry for this value
- return pos->second.get();
- }
-
- // We must make a new section load list that is based on the last valid
- // section load list, so here we copy the last section load list and add
- // a new node for the current stop ID.
- StopIDToSectionLoadList::reverse_iterator rpos = m_stop_id_to_section_load_list.rbegin();
- SectionLoadListSP section_load_list_sp(new SectionLoadList(*rpos->second.get()));
- m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
- return section_load_list_sp.get();
+SectionLoadHistory::GetSectionLoadListForStopID(uint32_t stop_id,
+ bool read_only) {
+ if (!m_stop_id_to_section_load_list.empty()) {
+ if (read_only) {
+ // The section load list is for reading data only so we don't need to
+ // create
+ // a new SectionLoadList for the current stop ID, just return the section
+ // load list for the stop ID that is equal to or less than the current
+ // stop ID
+ if (stop_id == eStopIDNow) {
+ // If we are asking for the latest and greatest value, it is always
+ // at the end of our list because that will be the highest stop ID.
+ StopIDToSectionLoadList::reverse_iterator rpos =
+ m_stop_id_to_section_load_list.rbegin();
+ return rpos->second.get();
+ } else {
+ StopIDToSectionLoadList::iterator pos =
+ m_stop_id_to_section_load_list.lower_bound(stop_id);
+ if (pos != m_stop_id_to_section_load_list.end() &&
+ pos->first == stop_id)
+ return pos->second.get();
+ else if (pos != m_stop_id_to_section_load_list.begin()) {
+ --pos;
+ return pos->second.get();
}
+ }
+ } else {
+ // You can only use "eStopIDNow" when reading from the section load
+ // history
+ assert(stop_id != eStopIDNow);
+
+ // We are updating the section load list (not read only), so if the stop
+ // ID
+ // passed in isn't the same as the last stop ID in our collection, then
+ // create
+ // a new node using the current stop ID
+ StopIDToSectionLoadList::iterator pos =
+ m_stop_id_to_section_load_list.lower_bound(stop_id);
+ if (pos != m_stop_id_to_section_load_list.end() &&
+ pos->first == stop_id) {
+ // We already have an entry for this value
+ return pos->second.get();
+ }
+
+ // We must make a new section load list that is based on the last valid
+ // section load list, so here we copy the last section load list and add
+ // a new node for the current stop ID.
+ StopIDToSectionLoadList::reverse_iterator rpos =
+ m_stop_id_to_section_load_list.rbegin();
+ SectionLoadListSP section_load_list_sp(
+ new SectionLoadList(*rpos->second.get()));
+ m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
+ return section_load_list_sp.get();
}
- SectionLoadListSP section_load_list_sp(new SectionLoadList());
- if (stop_id == eStopIDNow)
- stop_id = 0;
- m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
- return section_load_list_sp.get();
+ }
+ SectionLoadListSP section_load_list_sp(new SectionLoadList());
+ if (stop_id == eStopIDNow)
+ stop_id = 0;
+ m_stop_id_to_section_load_list[stop_id] = section_load_list_sp;
+ return section_load_list_sp.get();
}
-SectionLoadList &
-SectionLoadHistory::GetCurrentSectionLoadList ()
-{
- const bool read_only = true;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- SectionLoadList *section_load_list = GetSectionLoadListForStopID (eStopIDNow, read_only);
- assert(section_load_list != NULL);
- return *section_load_list;
+SectionLoadList &SectionLoadHistory::GetCurrentSectionLoadList() {
+ const bool read_only = true;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ SectionLoadList *section_load_list =
+ GetSectionLoadListForStopID(eStopIDNow, read_only);
+ assert(section_load_list != NULL);
+ return *section_load_list;
}
addr_t
-SectionLoadHistory::GetSectionLoadAddress (uint32_t stop_id, const lldb::SectionSP §ion_sp)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- const bool read_only = true;
- SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only);
- return section_load_list->GetSectionLoadAddress(section_sp);
-}
-
-bool
-SectionLoadHistory::ResolveLoadAddress (uint32_t stop_id, addr_t load_addr, Address &so_addr)
-{
- // First find the top level section that this load address exists in
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- const bool read_only = true;
- SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only);
- return section_load_list->ResolveLoadAddress (load_addr, so_addr);
-}
-
-bool
-SectionLoadHistory::SetSectionLoadAddress (uint32_t stop_id,
- const lldb::SectionSP §ion_sp,
- addr_t load_addr,
- bool warn_multiple)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- const bool read_only = false;
- SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only);
- return section_load_list->SetSectionLoadAddress(section_sp, load_addr, warn_multiple);
+SectionLoadHistory::GetSectionLoadAddress(uint32_t stop_id,
+ const lldb::SectionSP §ion_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const bool read_only = true;
+ SectionLoadList *section_load_list =
+ GetSectionLoadListForStopID(stop_id, read_only);
+ return section_load_list->GetSectionLoadAddress(section_sp);
+}
+
+bool SectionLoadHistory::ResolveLoadAddress(uint32_t stop_id, addr_t load_addr,
+ Address &so_addr) {
+ // First find the top level section that this load address exists in
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const bool read_only = true;
+ SectionLoadList *section_load_list =
+ GetSectionLoadListForStopID(stop_id, read_only);
+ return section_load_list->ResolveLoadAddress(load_addr, so_addr);
+}
+
+bool SectionLoadHistory::SetSectionLoadAddress(
+ uint32_t stop_id, const lldb::SectionSP §ion_sp, addr_t load_addr,
+ bool warn_multiple) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const bool read_only = false;
+ SectionLoadList *section_load_list =
+ GetSectionLoadListForStopID(stop_id, read_only);
+ return section_load_list->SetSectionLoadAddress(section_sp, load_addr,
+ warn_multiple);
}
size_t
-SectionLoadHistory::SetSectionUnloaded (uint32_t stop_id, const lldb::SectionSP §ion_sp)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- const bool read_only = false;
- SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only);
- return section_load_list->SetSectionUnloaded (section_sp);
-}
-
-bool
-SectionLoadHistory::SetSectionUnloaded (uint32_t stop_id, const lldb::SectionSP §ion_sp, addr_t load_addr)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- const bool read_only = false;
- SectionLoadList *section_load_list = GetSectionLoadListForStopID (stop_id, read_only);
- return section_load_list->SetSectionUnloaded (section_sp, load_addr);
-}
-
-void
-SectionLoadHistory::Dump (Stream &s, Target *target)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- StopIDToSectionLoadList::iterator pos, end = m_stop_id_to_section_load_list.end();
- for (pos = m_stop_id_to_section_load_list.begin(); pos != end; ++pos)
- {
- s.Printf("StopID = %u:\n", pos->first);
- pos->second->Dump(s, target);
- s.EOL();
- }
+SectionLoadHistory::SetSectionUnloaded(uint32_t stop_id,
+ const lldb::SectionSP §ion_sp) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const bool read_only = false;
+ SectionLoadList *section_load_list =
+ GetSectionLoadListForStopID(stop_id, read_only);
+ return section_load_list->SetSectionUnloaded(section_sp);
+}
+
+bool SectionLoadHistory::SetSectionUnloaded(uint32_t stop_id,
+ const lldb::SectionSP §ion_sp,
+ addr_t load_addr) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const bool read_only = false;
+ SectionLoadList *section_load_list =
+ GetSectionLoadListForStopID(stop_id, read_only);
+ return section_load_list->SetSectionUnloaded(section_sp, load_addr);
+}
+
+void SectionLoadHistory::Dump(Stream &s, Target *target) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ StopIDToSectionLoadList::iterator pos,
+ end = m_stop_id_to_section_load_list.end();
+ for (pos = m_stop_id_to_section_load_list.begin(); pos != end; ++pos) {
+ s.Printf("StopID = %u:\n", pos->first);
+ pos->second->Dump(s, target);
+ s.EOL();
+ }
}
-
-
Modified: lldb/trunk/source/Target/SectionLoadList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/SectionLoadList.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/SectionLoadList.cpp (original)
+++ lldb/trunk/source/Target/SectionLoadList.cpp Tue Sep 6 15:57:50 2016
@@ -24,275 +24,244 @@
using namespace lldb;
using namespace lldb_private;
-SectionLoadList::SectionLoadList(const SectionLoadList &rhs) : m_addr_to_sect(), m_sect_to_addr(), m_mutex()
-{
- std::lock_guard<std::recursive_mutex> guard(rhs.m_mutex);
- m_addr_to_sect = rhs.m_addr_to_sect;
- m_sect_to_addr = rhs.m_sect_to_addr;
+SectionLoadList::SectionLoadList(const SectionLoadList &rhs)
+ : m_addr_to_sect(), m_sect_to_addr(), m_mutex() {
+ std::lock_guard<std::recursive_mutex> guard(rhs.m_mutex);
+ m_addr_to_sect = rhs.m_addr_to_sect;
+ m_sect_to_addr = rhs.m_sect_to_addr;
}
-void
-SectionLoadList::operator=(const SectionLoadList &rhs)
-{
- std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
- std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
- m_addr_to_sect = rhs.m_addr_to_sect;
- m_sect_to_addr = rhs.m_sect_to_addr;
+void SectionLoadList::operator=(const SectionLoadList &rhs) {
+ std::lock_guard<std::recursive_mutex> lhs_guard(m_mutex);
+ std::lock_guard<std::recursive_mutex> rhs_guard(rhs.m_mutex);
+ m_addr_to_sect = rhs.m_addr_to_sect;
+ m_sect_to_addr = rhs.m_sect_to_addr;
}
-bool
-SectionLoadList::IsEmpty() const
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- return m_addr_to_sect.empty();
+bool SectionLoadList::IsEmpty() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return m_addr_to_sect.empty();
}
-void
-SectionLoadList::Clear ()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- m_addr_to_sect.clear();
- m_sect_to_addr.clear();
+void SectionLoadList::Clear() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_addr_to_sect.clear();
+ m_sect_to_addr.clear();
}
addr_t
-SectionLoadList::GetSectionLoadAddress (const lldb::SectionSP §ion) const
-{
- // TODO: add support for the same section having multiple load addresses
- addr_t section_load_addr = LLDB_INVALID_ADDRESS;
- if (section)
- {
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- sect_to_addr_collection::const_iterator pos = m_sect_to_addr.find (section.get());
-
- if (pos != m_sect_to_addr.end())
- section_load_addr = pos->second;
- }
- return section_load_addr;
-}
-
-bool
-SectionLoadList::SetSectionLoadAddress (const lldb::SectionSP §ion, addr_t load_addr, bool warn_multiple)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
-
- ModuleSP module_sp (section->GetModule());
-
- if (module_sp)
- {
- if (log)
- {
- const FileSpec &module_file_spec (module_sp->GetFileSpec());
- log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ") module = %p",
- __FUNCTION__, static_cast<void*>(section.get()),
- module_file_spec.GetPath().c_str(),
- section->GetName().AsCString(), load_addr,
- static_cast<void*>(module_sp.get()));
- }
-
- if (section->GetByteSize() == 0)
- return false; // No change
-
- // Fill in the section -> load_addr map
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section.get());
- if (sta_pos != m_sect_to_addr.end())
- {
- if (load_addr == sta_pos->second)
- return false; // No change...
- else
- sta_pos->second = load_addr;
- }
- else
- m_sect_to_addr[section.get()] = load_addr;
-
- // Fill in the load_addr -> section map
- addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
- if (ats_pos != m_addr_to_sect.end())
- {
- // Some sections are ok to overlap, and for others we should warn. When
- // we have multiple load addresses that correspond to a section, we will
- // always attribute the section to the be last section that claims it
- // exists at that address. Sometimes it is ok for more that one section
- // to be loaded at a specific load address, and other times it isn't.
- // The "warn_multiple" parameter tells us if we should warn in this case
- // or not. The DynamicLoader plug-in subclasses should know which
- // sections should warn and which shouldn't (darwin shared cache modules
- // all shared the same "__LINKEDIT" sections, so the dynamic loader can
- // pass false for "warn_multiple").
- if (warn_multiple && section != ats_pos->second)
- {
- ModuleSP module_sp (section->GetModule());
- if (module_sp)
- {
- ModuleSP curr_module_sp (ats_pos->second->GetModule());
- if (curr_module_sp)
- {
- module_sp->ReportWarning ("address 0x%16.16" PRIx64 " maps to more than one section: %s.%s and %s.%s",
- load_addr,
- module_sp->GetFileSpec().GetFilename().GetCString(),
- section->GetName().GetCString(),
- curr_module_sp->GetFileSpec().GetFilename().GetCString(),
- ats_pos->second->GetName().GetCString());
- }
- }
- }
- ats_pos->second = section;
- }
- else
- m_addr_to_sect[load_addr] = section;
- return true; // Changed
+SectionLoadList::GetSectionLoadAddress(const lldb::SectionSP §ion) const {
+ // TODO: add support for the same section having multiple load addresses
+ addr_t section_load_addr = LLDB_INVALID_ADDRESS;
+ if (section) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ sect_to_addr_collection::const_iterator pos =
+ m_sect_to_addr.find(section.get());
+ if (pos != m_sect_to_addr.end())
+ section_load_addr = pos->second;
+ }
+ return section_load_addr;
+}
+
+bool SectionLoadList::SetSectionLoadAddress(const lldb::SectionSP §ion,
+ addr_t load_addr,
+ bool warn_multiple) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
+ LIBLLDB_LOG_VERBOSE));
+
+ ModuleSP module_sp(section->GetModule());
+
+ if (module_sp) {
+ if (log) {
+ const FileSpec &module_file_spec(module_sp->GetFileSpec());
+ log->Printf("SectionLoadList::%s (section = %p (%s.%s), load_addr = "
+ "0x%16.16" PRIx64 ") module = %p",
+ __FUNCTION__, static_cast<void *>(section.get()),
+ module_file_spec.GetPath().c_str(),
+ section->GetName().AsCString(), load_addr,
+ static_cast<void *>(module_sp.get()));
}
- else
- {
- if (log)
- {
- log->Printf ("SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64 ") error: module has been deleted",
- __FUNCTION__, static_cast<void*>(section.get()),
- section->GetName().AsCString(),
- load_addr);
- }
- }
- return false;
-}
-
-size_t
-SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp)
-{
- size_t unload_count = 0;
-
- if (section_sp)
- {
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
-
- if (log)
- {
- ModuleSP module_sp = section_sp->GetModule();
- std::string module_name("<Unknown>");
- if (module_sp)
- {
- const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
- module_name = module_file_spec.GetPath();
- }
- log->Printf ("SectionLoadList::%s (section = %p (%s.%s))",
- __FUNCTION__, static_cast<void*>(section_sp.get()),
- module_name.c_str(),
- section_sp->GetName().AsCString());
- }
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (section->GetByteSize() == 0)
+ return false; // No change
- sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get());
- if (sta_pos != m_sect_to_addr.end())
- {
- ++unload_count;
- addr_t load_addr = sta_pos->second;
- m_sect_to_addr.erase (sta_pos);
-
- addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
- if (ats_pos != m_addr_to_sect.end())
- m_addr_to_sect.erase (ats_pos);
- }
- }
- return unload_count;
-}
-
-bool
-SectionLoadList::SetSectionUnloaded (const lldb::SectionSP §ion_sp, addr_t load_addr)
-{
- Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_DYNAMIC_LOADER | LIBLLDB_LOG_VERBOSE));
-
- if (log)
- {
- ModuleSP module_sp = section_sp->GetModule();
- std::string module_name("<Unknown>");
- if (module_sp)
- {
- const FileSpec &module_file_spec (section_sp->GetModule()->GetFileSpec());
- module_name = module_file_spec.GetPath();
- }
- log->Printf ("SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64 ")",
- __FUNCTION__, static_cast<void*>(section_sp.get()),
- module_name.c_str(),
- section_sp->GetName().AsCString(), load_addr);
- }
- bool erased = false;
+ // Fill in the section -> load_addr map
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- sect_to_addr_collection::iterator sta_pos = m_sect_to_addr.find(section_sp.get());
- if (sta_pos != m_sect_to_addr.end())
- {
- erased = true;
- m_sect_to_addr.erase (sta_pos);
- }
+ sect_to_addr_collection::iterator sta_pos =
+ m_sect_to_addr.find(section.get());
+ if (sta_pos != m_sect_to_addr.end()) {
+ if (load_addr == sta_pos->second)
+ return false; // No change...
+ else
+ sta_pos->second = load_addr;
+ } else
+ m_sect_to_addr[section.get()] = load_addr;
+ // Fill in the load_addr -> section map
addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
- if (ats_pos != m_addr_to_sect.end())
- {
- erased = true;
- m_addr_to_sect.erase (ats_pos);
+ if (ats_pos != m_addr_to_sect.end()) {
+ // Some sections are ok to overlap, and for others we should warn. When
+ // we have multiple load addresses that correspond to a section, we will
+ // always attribute the section to the be last section that claims it
+ // exists at that address. Sometimes it is ok for more that one section
+ // to be loaded at a specific load address, and other times it isn't.
+ // The "warn_multiple" parameter tells us if we should warn in this case
+ // or not. The DynamicLoader plug-in subclasses should know which
+ // sections should warn and which shouldn't (darwin shared cache modules
+ // all shared the same "__LINKEDIT" sections, so the dynamic loader can
+ // pass false for "warn_multiple").
+ if (warn_multiple && section != ats_pos->second) {
+ ModuleSP module_sp(section->GetModule());
+ if (module_sp) {
+ ModuleSP curr_module_sp(ats_pos->second->GetModule());
+ if (curr_module_sp) {
+ module_sp->ReportWarning(
+ "address 0x%16.16" PRIx64
+ " maps to more than one section: %s.%s and %s.%s",
+ load_addr, module_sp->GetFileSpec().GetFilename().GetCString(),
+ section->GetName().GetCString(),
+ curr_module_sp->GetFileSpec().GetFilename().GetCString(),
+ ats_pos->second->GetName().GetCString());
+ }
+ }
+ }
+ ats_pos->second = section;
+ } else
+ m_addr_to_sect[load_addr] = section;
+ return true; // Changed
+
+ } else {
+ if (log) {
+ log->Printf(
+ "SectionLoadList::%s (section = %p (%s), load_addr = 0x%16.16" PRIx64
+ ") error: module has been deleted",
+ __FUNCTION__, static_cast<void *>(section.get()),
+ section->GetName().AsCString(), load_addr);
+ }
+ }
+ return false;
+}
+
+size_t SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp) {
+ size_t unload_count = 0;
+
+ if (section_sp) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
+ LIBLLDB_LOG_VERBOSE));
+
+ if (log) {
+ ModuleSP module_sp = section_sp->GetModule();
+ std::string module_name("<Unknown>");
+ if (module_sp) {
+ const FileSpec &module_file_spec(
+ section_sp->GetModule()->GetFileSpec());
+ module_name = module_file_spec.GetPath();
+ }
+ log->Printf("SectionLoadList::%s (section = %p (%s.%s))", __FUNCTION__,
+ static_cast<void *>(section_sp.get()), module_name.c_str(),
+ section_sp->GetName().AsCString());
}
- return erased;
-}
-
-
-bool
-SectionLoadList::ResolveLoadAddress (addr_t load_addr, Address &so_addr) const
-{
- // First find the top level section that this load address exists in
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (!m_addr_to_sect.empty())
- {
- addr_to_sect_collection::const_iterator pos = m_addr_to_sect.lower_bound (load_addr);
- if (pos != m_addr_to_sect.end())
- {
- if (load_addr != pos->first && pos != m_addr_to_sect.begin())
- --pos;
- const addr_t pos_load_addr = pos->first;
- if (load_addr >= pos_load_addr)
- {
- addr_t offset = load_addr - pos_load_addr;
- if (offset < pos->second->GetByteSize())
- {
- // We have found the top level section, now we need to find the
- // deepest child section.
- return pos->second->ResolveContainedAddress (offset, so_addr);
- }
- }
- }
- else
- {
- // There are no entries that have an address that is >= load_addr,
- // so we need to check the last entry on our collection.
- addr_to_sect_collection::const_reverse_iterator rpos = m_addr_to_sect.rbegin();
- if (load_addr >= rpos->first)
- {
- addr_t offset = load_addr - rpos->first;
- if (offset < rpos->second->GetByteSize())
- {
- // We have found the top level section, now we need to find the
- // deepest child section.
- return rpos->second->ResolveContainedAddress (offset, so_addr);
- }
- }
- }
- }
- so_addr.Clear();
- return false;
-}
-void
-SectionLoadList::Dump (Stream &s, Target *target)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- addr_to_sect_collection::const_iterator pos, end;
- for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end; ++pos)
- {
- s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ",
- pos->first, static_cast<void*>(pos->second.get()));
- pos->second->Dump (&s, target, 0);
- }
+ sect_to_addr_collection::iterator sta_pos =
+ m_sect_to_addr.find(section_sp.get());
+ if (sta_pos != m_sect_to_addr.end()) {
+ ++unload_count;
+ addr_t load_addr = sta_pos->second;
+ m_sect_to_addr.erase(sta_pos);
+
+ addr_to_sect_collection::iterator ats_pos =
+ m_addr_to_sect.find(load_addr);
+ if (ats_pos != m_addr_to_sect.end())
+ m_addr_to_sect.erase(ats_pos);
+ }
+ }
+ return unload_count;
+}
+
+bool SectionLoadList::SetSectionUnloaded(const lldb::SectionSP §ion_sp,
+ addr_t load_addr) {
+ Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_DYNAMIC_LOADER |
+ LIBLLDB_LOG_VERBOSE));
+
+ if (log) {
+ ModuleSP module_sp = section_sp->GetModule();
+ std::string module_name("<Unknown>");
+ if (module_sp) {
+ const FileSpec &module_file_spec(section_sp->GetModule()->GetFileSpec());
+ module_name = module_file_spec.GetPath();
+ }
+ log->Printf(
+ "SectionLoadList::%s (section = %p (%s.%s), load_addr = 0x%16.16" PRIx64
+ ")",
+ __FUNCTION__, static_cast<void *>(section_sp.get()),
+ module_name.c_str(), section_sp->GetName().AsCString(), load_addr);
+ }
+ bool erased = false;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ sect_to_addr_collection::iterator sta_pos =
+ m_sect_to_addr.find(section_sp.get());
+ if (sta_pos != m_sect_to_addr.end()) {
+ erased = true;
+ m_sect_to_addr.erase(sta_pos);
+ }
+
+ addr_to_sect_collection::iterator ats_pos = m_addr_to_sect.find(load_addr);
+ if (ats_pos != m_addr_to_sect.end()) {
+ erased = true;
+ m_addr_to_sect.erase(ats_pos);
+ }
+
+ return erased;
+}
+
+bool SectionLoadList::ResolveLoadAddress(addr_t load_addr,
+ Address &so_addr) const {
+ // First find the top level section that this load address exists in
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (!m_addr_to_sect.empty()) {
+ addr_to_sect_collection::const_iterator pos =
+ m_addr_to_sect.lower_bound(load_addr);
+ if (pos != m_addr_to_sect.end()) {
+ if (load_addr != pos->first && pos != m_addr_to_sect.begin())
+ --pos;
+ const addr_t pos_load_addr = pos->first;
+ if (load_addr >= pos_load_addr) {
+ addr_t offset = load_addr - pos_load_addr;
+ if (offset < pos->second->GetByteSize()) {
+ // We have found the top level section, now we need to find the
+ // deepest child section.
+ return pos->second->ResolveContainedAddress(offset, so_addr);
+ }
+ }
+ } else {
+ // There are no entries that have an address that is >= load_addr,
+ // so we need to check the last entry on our collection.
+ addr_to_sect_collection::const_reverse_iterator rpos =
+ m_addr_to_sect.rbegin();
+ if (load_addr >= rpos->first) {
+ addr_t offset = load_addr - rpos->first;
+ if (offset < rpos->second->GetByteSize()) {
+ // We have found the top level section, now we need to find the
+ // deepest child section.
+ return rpos->second->ResolveContainedAddress(offset, so_addr);
+ }
+ }
+ }
+ }
+ so_addr.Clear();
+ return false;
+}
+
+void SectionLoadList::Dump(Stream &s, Target *target) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ addr_to_sect_collection::const_iterator pos, end;
+ for (pos = m_addr_to_sect.begin(), end = m_addr_to_sect.end(); pos != end;
+ ++pos) {
+ s.Printf("addr = 0x%16.16" PRIx64 ", section = %p: ", pos->first,
+ static_cast<void *>(pos->second.get()));
+ pos->second->Dump(&s, target, 0);
+ }
}
-
-
Modified: lldb/trunk/source/Target/StackFrame.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrame.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrame.cpp (original)
+++ lldb/trunk/source/Target/StackFrame.cpp Tue Sep 6 15:57:50 2016
@@ -18,9 +18,9 @@
#include "lldb/Core/Mangled.h"
#include "lldb/Core/Module.h"
#include "lldb/Core/Value.h"
-#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Core/ValueObjectMemory.h"
+#include "lldb/Core/ValueObjectVariable.h"
#include "lldb/Symbol/CompileUnit.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
@@ -40,289 +40,221 @@ using namespace lldb_private;
// The first bits in the flags are reserved for the SymbolContext::Scope bits
// so we know if we have tried to look up information in our internal symbol
// context (m_sc) already.
-#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1))
-#define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1)
-#define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1)
-#define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1)
-#define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1)
-
-StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index, addr_t cfa,
- bool cfa_is_valid, addr_t pc, uint32_t stop_id, bool stop_id_is_valid, bool is_history_frame,
+#define RESOLVED_FRAME_CODE_ADDR (uint32_t(eSymbolContextEverything + 1))
+#define RESOLVED_FRAME_ID_SYMBOL_SCOPE (RESOLVED_FRAME_CODE_ADDR << 1)
+#define GOT_FRAME_BASE (RESOLVED_FRAME_ID_SYMBOL_SCOPE << 1)
+#define RESOLVED_VARIABLES (GOT_FRAME_BASE << 1)
+#define RESOLVED_GLOBAL_VARIABLES (RESOLVED_VARIABLES << 1)
+
+StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
+ user_id_t unwind_frame_index, addr_t cfa,
+ bool cfa_is_valid, addr_t pc, uint32_t stop_id,
+ bool stop_id_is_valid, bool is_history_frame,
const SymbolContext *sc_ptr)
- : m_thread_wp(thread_sp),
- m_frame_index(frame_idx),
+ : m_thread_wp(thread_sp), m_frame_index(frame_idx),
+ m_concrete_frame_index(unwind_frame_index), m_reg_context_sp(),
+ m_id(pc, cfa, nullptr), m_frame_code_addr(pc), m_sc(), m_flags(),
+ m_frame_base(), m_frame_base_error(), m_cfa_is_valid(cfa_is_valid),
+ m_stop_id(stop_id), m_stop_id_is_valid(stop_id_is_valid),
+ m_is_history_frame(is_history_frame), m_variable_list_sp(),
+ m_variable_list_value_objects(), m_disassembly(), m_mutex() {
+ // If we don't have a CFA value, use the frame index for our StackID so that
+ // recursive
+ // functions properly aren't confused with one another on a history stack.
+ if (m_is_history_frame && !m_cfa_is_valid) {
+ m_id.SetCFA(m_frame_index);
+ }
+
+ if (sc_ptr != nullptr) {
+ m_sc = *sc_ptr;
+ m_flags.Set(m_sc.GetResolvedMask());
+ }
+}
+
+StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
+ user_id_t unwind_frame_index,
+ const RegisterContextSP ®_context_sp, addr_t cfa,
+ addr_t pc, const SymbolContext *sc_ptr)
+ : m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index),
- m_reg_context_sp(),
- m_id(pc, cfa, nullptr),
- m_frame_code_addr(pc),
- m_sc(),
- m_flags(),
- m_frame_base(),
- m_frame_base_error(),
- m_cfa_is_valid(cfa_is_valid),
- m_stop_id(stop_id),
- m_stop_id_is_valid(stop_id_is_valid),
- m_is_history_frame(is_history_frame),
- m_variable_list_sp(),
- m_variable_list_value_objects(),
- m_disassembly(),
- m_mutex()
-{
- // If we don't have a CFA value, use the frame index for our StackID so that recursive
- // functions properly aren't confused with one another on a history stack.
- if (m_is_history_frame && !m_cfa_is_valid)
- {
- m_id.SetCFA(m_frame_index);
- }
-
- if (sc_ptr != nullptr)
- {
- m_sc = *sc_ptr;
- m_flags.Set(m_sc.GetResolvedMask());
- }
-}
-
-StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index,
- const RegisterContextSP ®_context_sp, addr_t cfa, addr_t pc, const SymbolContext *sc_ptr)
- : m_thread_wp(thread_sp),
- m_frame_index(frame_idx),
- m_concrete_frame_index(unwind_frame_index),
- m_reg_context_sp(reg_context_sp),
- m_id(pc, cfa, nullptr),
- m_frame_code_addr(pc),
- m_sc(),
- m_flags(),
- m_frame_base(),
- m_frame_base_error(),
- m_cfa_is_valid(true),
- m_stop_id(0),
- m_stop_id_is_valid(false),
- m_is_history_frame(false),
- m_variable_list_sp(),
- m_variable_list_value_objects(),
- m_disassembly(),
- m_mutex()
-{
- if (sc_ptr != nullptr)
- {
- m_sc = *sc_ptr;
- m_flags.Set(m_sc.GetResolvedMask());
- }
-
- if (reg_context_sp && !m_sc.target_sp)
- {
- m_sc.target_sp = reg_context_sp->CalculateTarget();
- if (m_sc.target_sp)
- m_flags.Set(eSymbolContextTarget);
- }
-}
-
-StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx, user_id_t unwind_frame_index,
- const RegisterContextSP ®_context_sp, addr_t cfa, const Address &pc_addr,
- const SymbolContext *sc_ptr)
- : m_thread_wp(thread_sp),
- m_frame_index(frame_idx),
+ m_reg_context_sp(reg_context_sp), m_id(pc, cfa, nullptr),
+ m_frame_code_addr(pc), m_sc(), m_flags(), m_frame_base(),
+ m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0),
+ m_stop_id_is_valid(false), m_is_history_frame(false),
+ m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(),
+ m_mutex() {
+ if (sc_ptr != nullptr) {
+ m_sc = *sc_ptr;
+ m_flags.Set(m_sc.GetResolvedMask());
+ }
+
+ if (reg_context_sp && !m_sc.target_sp) {
+ m_sc.target_sp = reg_context_sp->CalculateTarget();
+ if (m_sc.target_sp)
+ m_flags.Set(eSymbolContextTarget);
+ }
+}
+
+StackFrame::StackFrame(const ThreadSP &thread_sp, user_id_t frame_idx,
+ user_id_t unwind_frame_index,
+ const RegisterContextSP ®_context_sp, addr_t cfa,
+ const Address &pc_addr, const SymbolContext *sc_ptr)
+ : m_thread_wp(thread_sp), m_frame_index(frame_idx),
m_concrete_frame_index(unwind_frame_index),
m_reg_context_sp(reg_context_sp),
- m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa, nullptr),
- m_frame_code_addr(pc_addr),
- m_sc(),
- m_flags(),
- m_frame_base(),
- m_frame_base_error(),
- m_cfa_is_valid(true),
- m_stop_id(0),
- m_stop_id_is_valid(false),
- m_is_history_frame(false),
- m_variable_list_sp(),
- m_variable_list_value_objects(),
- m_disassembly(),
- m_mutex()
-{
- if (sc_ptr != nullptr)
- {
- m_sc = *sc_ptr;
- m_flags.Set(m_sc.GetResolvedMask());
- }
-
- if (!m_sc.target_sp && reg_context_sp)
- {
- m_sc.target_sp = reg_context_sp->CalculateTarget();
- if (m_sc.target_sp)
- m_flags.Set(eSymbolContextTarget);
- }
-
- ModuleSP pc_module_sp(pc_addr.GetModule());
- if (!m_sc.module_sp || m_sc.module_sp != pc_module_sp)
- {
- if (pc_module_sp)
- {
- m_sc.module_sp = pc_module_sp;
- m_flags.Set(eSymbolContextModule);
- }
- else
- {
- m_sc.module_sp.reset();
- }
+ m_id(pc_addr.GetLoadAddress(thread_sp->CalculateTarget().get()), cfa,
+ nullptr),
+ m_frame_code_addr(pc_addr), m_sc(), m_flags(), m_frame_base(),
+ m_frame_base_error(), m_cfa_is_valid(true), m_stop_id(0),
+ m_stop_id_is_valid(false), m_is_history_frame(false),
+ m_variable_list_sp(), m_variable_list_value_objects(), m_disassembly(),
+ m_mutex() {
+ if (sc_ptr != nullptr) {
+ m_sc = *sc_ptr;
+ m_flags.Set(m_sc.GetResolvedMask());
+ }
+
+ if (!m_sc.target_sp && reg_context_sp) {
+ m_sc.target_sp = reg_context_sp->CalculateTarget();
+ if (m_sc.target_sp)
+ m_flags.Set(eSymbolContextTarget);
+ }
+
+ ModuleSP pc_module_sp(pc_addr.GetModule());
+ if (!m_sc.module_sp || m_sc.module_sp != pc_module_sp) {
+ if (pc_module_sp) {
+ m_sc.module_sp = pc_module_sp;
+ m_flags.Set(eSymbolContextModule);
+ } else {
+ m_sc.module_sp.reset();
}
+ }
}
StackFrame::~StackFrame() = default;
-StackID&
-StackFrame::GetStackID()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- // Make sure we have resolved the StackID object's symbol context scope if
- // we already haven't looked it up.
-
- if (m_flags.IsClear (RESOLVED_FRAME_ID_SYMBOL_SCOPE))
- {
- if (m_id.GetSymbolContextScope ())
- {
- // We already have a symbol context scope, we just don't have our
- // flag bit set.
- m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE);
- }
- else
- {
- // Calculate the frame block and use this for the stack ID symbol
- // context scope if we have one.
- SymbolContextScope *scope = GetFrameBlock ();
- if (scope == nullptr)
- {
- // We don't have a block, so use the symbol
- if (m_flags.IsClear (eSymbolContextSymbol))
- GetSymbolContext (eSymbolContextSymbol);
-
- // It is ok if m_sc.symbol is nullptr here
- scope = m_sc.symbol;
- }
- // Set the symbol context scope (the accessor will set the
- // RESOLVED_FRAME_ID_SYMBOL_SCOPE bit in m_flags).
- SetSymbolContextScope (scope);
- }
- }
- return m_id;
-}
+StackID &StackFrame::GetStackID() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ // Make sure we have resolved the StackID object's symbol context scope if
+ // we already haven't looked it up.
+
+ if (m_flags.IsClear(RESOLVED_FRAME_ID_SYMBOL_SCOPE)) {
+ if (m_id.GetSymbolContextScope()) {
+ // We already have a symbol context scope, we just don't have our
+ // flag bit set.
+ m_flags.Set(RESOLVED_FRAME_ID_SYMBOL_SCOPE);
+ } else {
+ // Calculate the frame block and use this for the stack ID symbol
+ // context scope if we have one.
+ SymbolContextScope *scope = GetFrameBlock();
+ if (scope == nullptr) {
+ // We don't have a block, so use the symbol
+ if (m_flags.IsClear(eSymbolContextSymbol))
+ GetSymbolContext(eSymbolContextSymbol);
+
+ // It is ok if m_sc.symbol is nullptr here
+ scope = m_sc.symbol;
+ }
+ // Set the symbol context scope (the accessor will set the
+ // RESOLVED_FRAME_ID_SYMBOL_SCOPE bit in m_flags).
+ SetSymbolContextScope(scope);
+ }
+ }
+ return m_id;
+}
+
+uint32_t StackFrame::GetFrameIndex() const {
+ ThreadSP thread_sp = GetThread();
+ if (thread_sp)
+ return thread_sp->GetStackFrameList()->GetVisibleStackFrameIndex(
+ m_frame_index);
+ else
+ return m_frame_index;
+}
+
+void StackFrame::SetSymbolContextScope(SymbolContextScope *symbol_scope) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_flags.Set(RESOLVED_FRAME_ID_SYMBOL_SCOPE);
+ m_id.SetSymbolContextScope(symbol_scope);
+}
+
+const Address &StackFrame::GetFrameCodeAddress() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) &&
+ !m_frame_code_addr.IsSectionOffset()) {
+ m_flags.Set(RESOLVED_FRAME_CODE_ADDR);
-uint32_t
-StackFrame::GetFrameIndex () const
-{
- ThreadSP thread_sp = GetThread();
- if (thread_sp)
- return thread_sp->GetStackFrameList()->GetVisibleStackFrameIndex(m_frame_index);
- else
- return m_frame_index;
-}
-
-void
-StackFrame::SetSymbolContextScope (SymbolContextScope *symbol_scope)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- m_flags.Set (RESOLVED_FRAME_ID_SYMBOL_SCOPE);
- m_id.SetSymbolContextScope (symbol_scope);
-}
-
-const Address&
-StackFrame::GetFrameCodeAddress()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR) && !m_frame_code_addr.IsSectionOffset())
- {
- m_flags.Set (RESOLVED_FRAME_CODE_ADDR);
-
- // Resolve the PC into a temporary address because if ResolveLoadAddress
- // fails to resolve the address, it will clear the address object...
- ThreadSP thread_sp (GetThread());
- if (thread_sp)
- {
- TargetSP target_sp (thread_sp->CalculateTarget());
- if (target_sp)
- {
- if (m_frame_code_addr.SetOpcodeLoadAddress (m_frame_code_addr.GetOffset(), target_sp.get(), eAddressClassCode))
- {
- ModuleSP module_sp (m_frame_code_addr.GetModule());
- if (module_sp)
- {
- m_sc.module_sp = module_sp;
- m_flags.Set(eSymbolContextModule);
- }
- }
- }
+ // Resolve the PC into a temporary address because if ResolveLoadAddress
+ // fails to resolve the address, it will clear the address object...
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp) {
+ TargetSP target_sp(thread_sp->CalculateTarget());
+ if (target_sp) {
+ if (m_frame_code_addr.SetOpcodeLoadAddress(
+ m_frame_code_addr.GetOffset(), target_sp.get(),
+ eAddressClassCode)) {
+ ModuleSP module_sp(m_frame_code_addr.GetModule());
+ if (module_sp) {
+ m_sc.module_sp = module_sp;
+ m_flags.Set(eSymbolContextModule);
+ }
}
+ }
}
- return m_frame_code_addr;
+ }
+ return m_frame_code_addr;
}
-bool
-StackFrame::ChangePC (addr_t pc)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- // We can't change the pc value of a history stack frame - it is immutable.
- if (m_is_history_frame)
- return false;
- m_frame_code_addr.SetRawAddress(pc);
- m_sc.Clear(false);
- m_flags.Reset(0);
- ThreadSP thread_sp (GetThread());
- if (thread_sp)
- thread_sp->ClearStackFrames ();
- return true;
+bool StackFrame::ChangePC(addr_t pc) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ // We can't change the pc value of a history stack frame - it is immutable.
+ if (m_is_history_frame)
+ return false;
+ m_frame_code_addr.SetRawAddress(pc);
+ m_sc.Clear(false);
+ m_flags.Reset(0);
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp)
+ thread_sp->ClearStackFrames();
+ return true;
}
-const char *
-StackFrame::Disassemble ()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
+const char *StackFrame::Disassemble() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_disassembly.GetSize() == 0) {
+ ExecutionContext exe_ctx(shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ Disassembler::Disassemble(target->GetDebugger(),
+ target->GetArchitecture(), plugin_name, flavor,
+ exe_ctx, 0, 0, 0, m_disassembly);
+ }
if (m_disassembly.GetSize() == 0)
- {
- ExecutionContext exe_ctx (shared_from_this());
- Target *target = exe_ctx.GetTargetPtr();
- if (target)
- {
- const char *plugin_name = nullptr;
- const char *flavor = nullptr;
- Disassembler::Disassemble (target->GetDebugger(),
- target->GetArchitecture(),
- plugin_name,
- flavor,
- exe_ctx,
- 0,
- 0,
- 0,
- m_disassembly);
- }
- if (m_disassembly.GetSize() == 0)
- return nullptr;
- }
- return m_disassembly.GetData();
-}
-
-Block *
-StackFrame::GetFrameBlock ()
-{
- if (m_sc.block == nullptr && m_flags.IsClear(eSymbolContextBlock))
- GetSymbolContext (eSymbolContextBlock);
-
- if (m_sc.block)
- {
- Block *inline_block = m_sc.block->GetContainingInlinedBlock();
- if (inline_block)
- {
- // Use the block with the inlined function info
- // as the frame block we want this frame to have only the variables
- // for the inlined function and its non-inlined block child blocks.
- return inline_block;
- }
- else
- {
- // This block is not contained within any inlined function blocks
- // with so we want to use the top most function block.
- return &m_sc.function->GetBlock (false);
- }
- }
- return nullptr;
+ return nullptr;
+ }
+ return m_disassembly.GetData();
+}
+
+Block *StackFrame::GetFrameBlock() {
+ if (m_sc.block == nullptr && m_flags.IsClear(eSymbolContextBlock))
+ GetSymbolContext(eSymbolContextBlock);
+
+ if (m_sc.block) {
+ Block *inline_block = m_sc.block->GetContainingInlinedBlock();
+ if (inline_block) {
+ // Use the block with the inlined function info
+ // as the frame block we want this frame to have only the variables
+ // for the inlined function and its non-inlined block child blocks.
+ return inline_block;
+ } else {
+ // This block is not contained within any inlined function blocks
+ // with so we want to use the top most function block.
+ return &m_sc.function->GetBlock(false);
+ }
+ }
+ return nullptr;
}
//----------------------------------------------------------------------
@@ -331,1840 +263,1658 @@ StackFrame::GetFrameBlock ()
// StackFrame object, everyone will have as much information as
// possible and no one will ever have to look things up manually.
//----------------------------------------------------------------------
-const SymbolContext&
-StackFrame::GetSymbolContext (uint32_t resolve_scope)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- // Copy our internal symbol context into "sc".
- if ((m_flags.Get() & resolve_scope) != resolve_scope)
- {
- uint32_t resolved = 0;
-
- // If the target was requested add that:
- if (!m_sc.target_sp)
- {
- m_sc.target_sp = CalculateTarget();
- if (m_sc.target_sp)
- resolved |= eSymbolContextTarget;
- }
-
- // Resolve our PC to section offset if we haven't already done so
- // and if we don't have a module. The resolved address section will
- // contain the module to which it belongs
- if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR))
- GetFrameCodeAddress();
-
- // If this is not frame zero, then we need to subtract 1 from the PC
- // value when doing address lookups since the PC will be on the
- // instruction following the function call instruction...
-
- Address lookup_addr(GetFrameCodeAddress());
- if (m_frame_index > 0 && lookup_addr.IsValid())
- {
- addr_t offset = lookup_addr.GetOffset();
- if (offset > 0)
- {
- lookup_addr.SetOffset(offset - 1);
-
- }
- 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);
- }
- }
- }
- }
+const SymbolContext &StackFrame::GetSymbolContext(uint32_t resolve_scope) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ // Copy our internal symbol context into "sc".
+ if ((m_flags.Get() & resolve_scope) != resolve_scope) {
+ uint32_t resolved = 0;
+
+ // If the target was requested add that:
+ if (!m_sc.target_sp) {
+ m_sc.target_sp = CalculateTarget();
+ if (m_sc.target_sp)
+ resolved |= eSymbolContextTarget;
+ }
+
+ // Resolve our PC to section offset if we haven't already done so
+ // and if we don't have a module. The resolved address section will
+ // contain the module to which it belongs
+ if (!m_sc.module_sp && m_flags.IsClear(RESOLVED_FRAME_CODE_ADDR))
+ GetFrameCodeAddress();
+
+ // If this is not frame zero, then we need to subtract 1 from the PC
+ // value when doing address lookups since the PC will be on the
+ // instruction following the function call instruction...
+
+ Address lookup_addr(GetFrameCodeAddress());
+ if (m_frame_index > 0 && lookup_addr.IsValid()) {
+ addr_t offset = lookup_addr.GetOffset();
+ if (offset > 0) {
+ lookup_addr.SetOffset(offset - 1);
+
+ } else {
+ // lookup_addr is the start of a section. We need
+ // do the math on the actual load address and re-compute
+ // the section. We're working with a 'noreturn' function
+ // at the end of a section.
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp) {
+ TargetSP target_sp(thread_sp->CalculateTarget());
+ if (target_sp) {
+ addr_t addr_minus_one =
+ lookup_addr.GetLoadAddress(target_sp.get()) - 1;
+ lookup_addr.SetLoadAddress(addr_minus_one, target_sp.get());
+ } else {
+ lookup_addr.SetOffset(offset - 1);
+ }
+ }
+ }
+ }
+
+ if (m_sc.module_sp) {
+ // We have something in our stack frame symbol context, lets check
+ // if we haven't already tried to lookup one of those things. If we
+ // haven't then we will do the query.
+
+ uint32_t actual_resolve_scope = 0;
+
+ if (resolve_scope & eSymbolContextCompUnit) {
+ if (m_flags.IsClear(eSymbolContextCompUnit)) {
+ if (m_sc.comp_unit)
+ resolved |= eSymbolContextCompUnit;
+ else
+ actual_resolve_scope |= eSymbolContextCompUnit;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextFunction) {
+ if (m_flags.IsClear(eSymbolContextFunction)) {
+ if (m_sc.function)
+ resolved |= eSymbolContextFunction;
+ else
+ actual_resolve_scope |= eSymbolContextFunction;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextBlock) {
+ if (m_flags.IsClear(eSymbolContextBlock)) {
+ if (m_sc.block)
+ resolved |= eSymbolContextBlock;
+ else
+ actual_resolve_scope |= eSymbolContextBlock;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextSymbol) {
+ if (m_flags.IsClear(eSymbolContextSymbol)) {
+ if (m_sc.symbol)
+ resolved |= eSymbolContextSymbol;
+ else
+ actual_resolve_scope |= eSymbolContextSymbol;
+ }
+ }
+
+ if (resolve_scope & eSymbolContextLineEntry) {
+ if (m_flags.IsClear(eSymbolContextLineEntry)) {
+ if (m_sc.line_entry.IsValid())
+ resolved |= eSymbolContextLineEntry;
+ else
+ actual_resolve_scope |= eSymbolContextLineEntry;
+ }
+ }
+
+ if (actual_resolve_scope) {
+ // We might be resolving less information than what is already
+ // in our current symbol context so resolve into a temporary
+ // symbol context "sc" so we don't clear out data we have
+ // already found in "m_sc"
+ SymbolContext sc;
+ // Set flags that indicate what we have tried to resolve
+ resolved |= m_sc.module_sp->ResolveSymbolContextForAddress(
+ lookup_addr, actual_resolve_scope, sc);
+ // Only replace what we didn't already have as we may have
+ // information for an inlined function scope that won't match
+ // what a standard lookup by address would match
+ if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == nullptr)
+ m_sc.comp_unit = sc.comp_unit;
+ if ((resolved & eSymbolContextFunction) && m_sc.function == nullptr)
+ m_sc.function = sc.function;
+ if ((resolved & eSymbolContextBlock) && m_sc.block == nullptr)
+ m_sc.block = sc.block;
+ if ((resolved & eSymbolContextSymbol) && m_sc.symbol == nullptr)
+ m_sc.symbol = sc.symbol;
+ if ((resolved & eSymbolContextLineEntry) &&
+ !m_sc.line_entry.IsValid()) {
+ m_sc.line_entry = sc.line_entry;
+ m_sc.line_entry.ApplyFileMappings(m_sc.target_sp);
+ }
+ }
+ } else {
+ // If we don't have a module, then we can't have the compile unit,
+ // function, block, line entry or symbol, so we can safely call
+ // ResolveSymbolContextForAddress with our symbol context member m_sc.
+ if (m_sc.target_sp) {
+ resolved |= m_sc.target_sp->GetImages().ResolveSymbolContextForAddress(
+ lookup_addr, resolve_scope, m_sc);
+ }
+ }
+
+ // Update our internal flags so we remember what we have tried to locate so
+ // we don't have to keep trying when more calls to this function are made.
+ // We might have dug up more information that was requested (for example
+ // if we were asked to only get the block, we will have gotten the
+ // compile unit, and function) so set any additional bits that we resolved
+ m_flags.Set(resolve_scope | resolved);
+ }
+
+ // Return the symbol context with everything that was possible to resolve
+ // resolved.
+ return m_sc;
+}
+
+VariableList *StackFrame::GetVariableList(bool get_file_globals) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_flags.IsClear(RESOLVED_VARIABLES)) {
+ m_flags.Set(RESOLVED_VARIABLES);
- if (m_sc.module_sp)
- {
- // We have something in our stack frame symbol context, lets check
- // if we haven't already tried to lookup one of those things. If we
- // haven't then we will do the query.
-
- uint32_t actual_resolve_scope = 0;
-
- if (resolve_scope & eSymbolContextCompUnit)
- {
- if (m_flags.IsClear (eSymbolContextCompUnit))
- {
- if (m_sc.comp_unit)
- resolved |= eSymbolContextCompUnit;
- else
- actual_resolve_scope |= eSymbolContextCompUnit;
- }
- }
+ Block *frame_block = GetFrameBlock();
- if (resolve_scope & eSymbolContextFunction)
- {
- if (m_flags.IsClear (eSymbolContextFunction))
- {
- if (m_sc.function)
- resolved |= eSymbolContextFunction;
- else
- actual_resolve_scope |= eSymbolContextFunction;
- }
- }
+ if (frame_block) {
+ const bool get_child_variables = true;
+ const bool can_create = true;
+ const bool stop_if_child_block_is_inlined_function = true;
+ m_variable_list_sp.reset(new VariableList());
+ frame_block->AppendBlockVariables(can_create, get_child_variables,
+ stop_if_child_block_is_inlined_function,
+ [this](Variable *v) { return true; },
+ m_variable_list_sp.get());
+ }
+ }
+
+ if (m_flags.IsClear(RESOLVED_GLOBAL_VARIABLES) && get_file_globals) {
+ m_flags.Set(RESOLVED_GLOBAL_VARIABLES);
+
+ if (m_flags.IsClear(eSymbolContextCompUnit))
+ GetSymbolContext(eSymbolContextCompUnit);
+
+ if (m_sc.comp_unit) {
+ VariableListSP global_variable_list_sp(
+ m_sc.comp_unit->GetVariableList(true));
+ if (m_variable_list_sp)
+ m_variable_list_sp->AddVariables(global_variable_list_sp.get());
+ else
+ m_variable_list_sp = global_variable_list_sp;
+ }
+ }
- if (resolve_scope & eSymbolContextBlock)
- {
- if (m_flags.IsClear (eSymbolContextBlock))
- {
- if (m_sc.block)
- resolved |= eSymbolContextBlock;
- else
- actual_resolve_scope |= eSymbolContextBlock;
- }
- }
+ return m_variable_list_sp.get();
+}
- if (resolve_scope & eSymbolContextSymbol)
- {
- if (m_flags.IsClear (eSymbolContextSymbol))
- {
- if (m_sc.symbol)
- resolved |= eSymbolContextSymbol;
- else
- actual_resolve_scope |= eSymbolContextSymbol;
- }
- }
+VariableListSP
+StackFrame::GetInScopeVariableList(bool get_file_globals,
+ bool must_have_valid_location) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ // We can't fetch variable information for a history stack frame.
+ if (m_is_history_frame)
+ return VariableListSP();
+
+ VariableListSP var_list_sp(new VariableList);
+ GetSymbolContext(eSymbolContextCompUnit | eSymbolContextBlock);
+
+ if (m_sc.block) {
+ const bool can_create = true;
+ const bool get_parent_variables = true;
+ const bool stop_if_block_is_inlined_function = true;
+ m_sc.block->AppendVariables(
+ can_create, get_parent_variables, stop_if_block_is_inlined_function,
+ [this, must_have_valid_location](Variable *v) {
+ return v->IsInScope(this) && (!must_have_valid_location ||
+ v->LocationIsValidForFrame(this));
+ },
+ var_list_sp.get());
+ }
+
+ if (m_sc.comp_unit && get_file_globals) {
+ VariableListSP global_variable_list_sp(
+ m_sc.comp_unit->GetVariableList(true));
+ if (global_variable_list_sp)
+ var_list_sp->AddVariables(global_variable_list_sp.get());
+ }
+
+ return var_list_sp;
+}
+
+ValueObjectSP StackFrame::GetValueForVariableExpressionPath(
+ const char *var_expr_cstr, DynamicValueType use_dynamic, uint32_t options,
+ VariableSP &var_sp, Error &error) {
+ // We can't fetch variable information for a history stack frame.
+ if (m_is_history_frame)
+ return ValueObjectSP();
- if (resolve_scope & eSymbolContextLineEntry)
- {
- if (m_flags.IsClear (eSymbolContextLineEntry))
- {
- if (m_sc.line_entry.IsValid())
- resolved |= eSymbolContextLineEntry;
- else
- actual_resolve_scope |= eSymbolContextLineEntry;
- }
- }
-
- if (actual_resolve_scope)
- {
- // We might be resolving less information than what is already
- // in our current symbol context so resolve into a temporary
- // symbol context "sc" so we don't clear out data we have
- // already found in "m_sc"
- SymbolContext sc;
- // Set flags that indicate what we have tried to resolve
- resolved |= m_sc.module_sp->ResolveSymbolContextForAddress (lookup_addr, actual_resolve_scope, sc);
- // Only replace what we didn't already have as we may have
- // information for an inlined function scope that won't match
- // what a standard lookup by address would match
- if ((resolved & eSymbolContextCompUnit) && m_sc.comp_unit == nullptr)
- m_sc.comp_unit = sc.comp_unit;
- if ((resolved & eSymbolContextFunction) && m_sc.function == nullptr)
- m_sc.function = sc.function;
- if ((resolved & eSymbolContextBlock) && m_sc.block == nullptr)
- m_sc.block = sc.block;
- if ((resolved & eSymbolContextSymbol) && m_sc.symbol == nullptr)
- m_sc.symbol = sc.symbol;
- if ((resolved & eSymbolContextLineEntry) && !m_sc.line_entry.IsValid())
- {
- m_sc.line_entry = sc.line_entry;
- m_sc.line_entry.ApplyFileMappings(m_sc.target_sp);
+ if (var_expr_cstr && var_expr_cstr[0]) {
+ const bool check_ptr_vs_member =
+ (options & eExpressionPathOptionCheckPtrVsMember) != 0;
+ const bool no_fragile_ivar =
+ (options & eExpressionPathOptionsNoFragileObjcIvar) != 0;
+ const bool no_synth_child =
+ (options & eExpressionPathOptionsNoSyntheticChildren) != 0;
+ // const bool no_synth_array = (options &
+ // eExpressionPathOptionsNoSyntheticArrayRange) != 0;
+ error.Clear();
+ bool deref = false;
+ bool address_of = false;
+ ValueObjectSP valobj_sp;
+ const bool get_file_globals = true;
+ // When looking up a variable for an expression, we need only consider the
+ // variables that are in scope.
+ VariableListSP var_list_sp(GetInScopeVariableList(get_file_globals));
+ VariableList *variable_list = var_list_sp.get();
+
+ if (variable_list) {
+ // If first character is a '*', then show pointer contents
+ const char *var_expr = var_expr_cstr;
+ if (var_expr[0] == '*') {
+ deref = true;
+ var_expr++; // Skip the '*'
+ } else if (var_expr[0] == '&') {
+ address_of = true;
+ var_expr++; // Skip the '&'
+ }
+
+ std::string var_path(var_expr);
+ size_t separator_idx = var_path.find_first_of(".-[=+~|&^%#@!/?,<>{}");
+ StreamString var_expr_path_strm;
+
+ ConstString name_const_string;
+ if (separator_idx == std::string::npos)
+ name_const_string.SetCString(var_path.c_str());
+ else
+ name_const_string.SetCStringWithLength(var_path.c_str(), separator_idx);
+
+ var_sp = variable_list->FindVariable(name_const_string, false);
+
+ bool synthetically_added_instance_object = false;
+
+ if (var_sp) {
+ var_path.erase(0, name_const_string.GetLength());
+ }
+
+ if (!var_sp && (options & eExpressionPathOptionsAllowDirectIVarAccess)) {
+ // Check for direct ivars access which helps us with implicit
+ // access to ivars with the "this->" or "self->"
+ GetSymbolContext(eSymbolContextFunction | eSymbolContextBlock);
+ lldb::LanguageType method_language = eLanguageTypeUnknown;
+ bool is_instance_method = false;
+ ConstString method_object_name;
+ if (m_sc.GetFunctionMethodInfo(method_language, is_instance_method,
+ method_object_name)) {
+ if (is_instance_method && method_object_name) {
+ var_sp = variable_list->FindVariable(method_object_name);
+ if (var_sp) {
+ separator_idx = 0;
+ var_path.insert(0, "->");
+ synthetically_added_instance_object = true;
+ }
+ }
+ }
+ }
+
+ if (!var_sp && (options & eExpressionPathOptionsInspectAnonymousUnions)) {
+ // Check if any anonymous unions are there which contain a variable with
+ // the name we need
+ for (size_t i = 0; i < variable_list->GetSize(); i++) {
+ if (VariableSP variable_sp = variable_list->GetVariableAtIndex(i)) {
+ if (variable_sp->GetName().IsEmpty()) {
+ if (Type *var_type = variable_sp->GetType()) {
+ if (var_type->GetForwardCompilerType().IsAnonymousType()) {
+ valobj_sp =
+ GetValueObjectForFrameVariable(variable_sp, use_dynamic);
+ if (!valobj_sp)
+ return valobj_sp;
+ valobj_sp = valobj_sp->GetChildMemberWithName(
+ name_const_string, true);
+ if (valobj_sp)
+ break;
}
+ }
}
+ }
}
- else
- {
- // If we don't have a module, then we can't have the compile unit,
- // function, block, line entry or symbol, so we can safely call
- // ResolveSymbolContextForAddress with our symbol context member m_sc.
- if (m_sc.target_sp)
- {
- resolved |= m_sc.target_sp->GetImages().ResolveSymbolContextForAddress (lookup_addr, resolve_scope, m_sc);
- }
- }
-
- // Update our internal flags so we remember what we have tried to locate so
- // we don't have to keep trying when more calls to this function are made.
- // We might have dug up more information that was requested (for example
- // if we were asked to only get the block, we will have gotten the
- // compile unit, and function) so set any additional bits that we resolved
- m_flags.Set (resolve_scope | resolved);
- }
-
- // Return the symbol context with everything that was possible to resolve
- // resolved.
- return m_sc;
-}
-
-VariableList *
-StackFrame::GetVariableList (bool get_file_globals)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (m_flags.IsClear(RESOLVED_VARIABLES))
- {
- m_flags.Set(RESOLVED_VARIABLES);
-
- Block *frame_block = GetFrameBlock();
-
- if (frame_block)
- {
- const bool get_child_variables = true;
- const bool can_create = true;
- const bool stop_if_child_block_is_inlined_function = true;
- m_variable_list_sp.reset(new VariableList());
- frame_block->AppendBlockVariables(can_create,
- get_child_variables,
- stop_if_child_block_is_inlined_function,
- [this](Variable* v) { return true; },
- m_variable_list_sp.get());
- }
- }
-
- if (m_flags.IsClear(RESOLVED_GLOBAL_VARIABLES) &&
- get_file_globals)
- {
- m_flags.Set(RESOLVED_GLOBAL_VARIABLES);
-
- if (m_flags.IsClear (eSymbolContextCompUnit))
- GetSymbolContext (eSymbolContextCompUnit);
-
- if (m_sc.comp_unit)
- {
- VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true));
- if (m_variable_list_sp)
- m_variable_list_sp->AddVariables (global_variable_list_sp.get());
- else
- m_variable_list_sp = global_variable_list_sp;
- }
- }
-
- return m_variable_list_sp.get();
-}
-
-VariableListSP
-StackFrame::GetInScopeVariableList (bool get_file_globals, bool must_have_valid_location)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- // We can't fetch variable information for a history stack frame.
- if (m_is_history_frame)
- return VariableListSP();
-
- VariableListSP var_list_sp(new VariableList);
- GetSymbolContext (eSymbolContextCompUnit | eSymbolContextBlock);
-
- if (m_sc.block)
- {
- const bool can_create = true;
- const bool get_parent_variables = true;
- const bool stop_if_block_is_inlined_function = true;
- m_sc.block->AppendVariables (can_create,
- get_parent_variables,
- stop_if_block_is_inlined_function,
- [this, must_have_valid_location](Variable* v)
- {
- return v->IsInScope(this) && (!must_have_valid_location || v->LocationIsValidForFrame(this));
- },
- var_list_sp.get());
- }
-
- if (m_sc.comp_unit && get_file_globals)
- {
- VariableListSP global_variable_list_sp (m_sc.comp_unit->GetVariableList(true));
- if (global_variable_list_sp)
- var_list_sp->AddVariables (global_variable_list_sp.get());
- }
-
- return var_list_sp;
-}
+ }
-ValueObjectSP
-StackFrame::GetValueForVariableExpressionPath (const char *var_expr_cstr,
- DynamicValueType use_dynamic,
- uint32_t options,
- VariableSP &var_sp,
- Error &error)
-{
- // We can't fetch variable information for a history stack frame.
- if (m_is_history_frame)
- return ValueObjectSP();
-
- if (var_expr_cstr && var_expr_cstr[0])
- {
- const bool check_ptr_vs_member = (options & eExpressionPathOptionCheckPtrVsMember) != 0;
- const bool no_fragile_ivar = (options & eExpressionPathOptionsNoFragileObjcIvar) != 0;
- const bool no_synth_child = (options & eExpressionPathOptionsNoSyntheticChildren) != 0;
- //const bool no_synth_array = (options & eExpressionPathOptionsNoSyntheticArrayRange) != 0;
- error.Clear();
- bool deref = false;
- bool address_of = false;
- ValueObjectSP valobj_sp;
- const bool get_file_globals = true;
- // When looking up a variable for an expression, we need only consider the
- // variables that are in scope.
- VariableListSP var_list_sp (GetInScopeVariableList (get_file_globals));
- VariableList *variable_list = var_list_sp.get();
-
- if (variable_list)
- {
- // If first character is a '*', then show pointer contents
- const char *var_expr = var_expr_cstr;
- if (var_expr[0] == '*')
- {
- deref = true;
- var_expr++; // Skip the '*'
- }
- else if (var_expr[0] == '&')
- {
- address_of = true;
- var_expr++; // Skip the '&'
+ if (var_sp && !valobj_sp) {
+ valobj_sp = GetValueObjectForFrameVariable(var_sp, use_dynamic);
+ if (!valobj_sp)
+ return valobj_sp;
+ }
+ if (valobj_sp) {
+ // We are dumping at least one child
+ while (separator_idx != std::string::npos) {
+ // Calculate the next separator index ahead of time
+ ValueObjectSP child_valobj_sp;
+ const char separator_type = var_path[0];
+ switch (separator_type) {
+ case '-':
+ if (var_path.size() >= 2 && var_path[1] != '>')
+ return ValueObjectSP();
+
+ if (no_fragile_ivar) {
+ // Make sure we aren't trying to deref an objective
+ // C ivar if this is not allowed
+ const uint32_t pointer_type_flags =
+ valobj_sp->GetCompilerType().GetTypeInfo(nullptr);
+ if ((pointer_type_flags & eTypeIsObjC) &&
+ (pointer_type_flags & eTypeIsPointer)) {
+ // This was an objective C object pointer and
+ // it was requested we skip any fragile ivars
+ // so return nothing here
+ return ValueObjectSP();
+ }
}
-
- std::string var_path (var_expr);
- size_t separator_idx = var_path.find_first_of(".-[=+~|&^%#@!/?,<>{}");
- StreamString var_expr_path_strm;
-
- ConstString name_const_string;
+ var_path.erase(0, 1); // Remove the '-'
+ LLVM_FALLTHROUGH;
+ case '.': {
+ const bool expr_is_ptr = var_path[0] == '>';
+
+ var_path.erase(0, 1); // Remove the '.' or '>'
+ separator_idx = var_path.find_first_of(".-[");
+ ConstString child_name;
if (separator_idx == std::string::npos)
- name_const_string.SetCString (var_path.c_str());
+ child_name.SetCString(var_path.c_str());
else
- name_const_string.SetCStringWithLength (var_path.c_str(), separator_idx);
+ child_name.SetCStringWithLength(var_path.c_str(), separator_idx);
- var_sp = variable_list->FindVariable(name_const_string, false);
-
- bool synthetically_added_instance_object = false;
-
- if (var_sp)
- {
- var_path.erase (0, name_const_string.GetLength ());
- }
-
- if (!var_sp && (options & eExpressionPathOptionsAllowDirectIVarAccess))
- {
- // Check for direct ivars access which helps us with implicit
- // access to ivars with the "this->" or "self->"
- GetSymbolContext(eSymbolContextFunction|eSymbolContextBlock);
- lldb::LanguageType method_language = eLanguageTypeUnknown;
- bool is_instance_method = false;
- ConstString method_object_name;
- if (m_sc.GetFunctionMethodInfo (method_language, is_instance_method, method_object_name))
- {
- if (is_instance_method && method_object_name)
- {
- var_sp = variable_list->FindVariable(method_object_name);
- if (var_sp)
- {
- separator_idx = 0;
- var_path.insert(0, "->");
- synthetically_added_instance_object = true;
- }
- }
- }
+ if (check_ptr_vs_member) {
+ // We either have a pointer type and need to verify
+ // valobj_sp is a pointer, or we have a member of a
+ // class/union/struct being accessed with the . syntax
+ // and need to verify we don't have a pointer.
+ const bool actual_is_ptr = valobj_sp->IsPointerType();
+
+ if (actual_is_ptr != expr_is_ptr) {
+ // Incorrect use of "." with a pointer, or "->" with
+ // a class/union/struct instance or reference.
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ if (actual_is_ptr)
+ error.SetErrorStringWithFormat(
+ "\"%s\" is a pointer and . was used to attempt to access "
+ "\"%s\". Did you mean \"%s->%s\"?",
+ var_expr_path_strm.GetString().c_str(),
+ child_name.GetCString(),
+ var_expr_path_strm.GetString().c_str(), var_path.c_str());
+ else
+ error.SetErrorStringWithFormat(
+ "\"%s\" is not a pointer and -> was used to attempt to "
+ "access \"%s\". Did you mean \"%s.%s\"?",
+ var_expr_path_strm.GetString().c_str(),
+ child_name.GetCString(),
+ var_expr_path_strm.GetString().c_str(), var_path.c_str());
+ return ValueObjectSP();
+ }
}
-
- if (!var_sp && (options & eExpressionPathOptionsInspectAnonymousUnions))
- {
- // Check if any anonymous unions are there which contain a variable with the name we need
- for (size_t i = 0;
- i < variable_list->GetSize();
- i++)
- {
- if (VariableSP variable_sp = variable_list->GetVariableAtIndex(i))
- {
- if (variable_sp->GetName().IsEmpty())
- {
- if (Type *var_type = variable_sp->GetType())
- {
- if (var_type->GetForwardCompilerType().IsAnonymousType())
- {
- valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic);
- if (!valobj_sp)
- return valobj_sp;
- valobj_sp = valobj_sp->GetChildMemberWithName(name_const_string, true);
- if (valobj_sp)
- break;
- }
- }
- }
- }
+ child_valobj_sp =
+ valobj_sp->GetChildMemberWithName(child_name, true);
+ if (!child_valobj_sp) {
+ if (!no_synth_child) {
+ child_valobj_sp = valobj_sp->GetSyntheticValue();
+ if (child_valobj_sp)
+ child_valobj_sp =
+ child_valobj_sp->GetChildMemberWithName(child_name, true);
+ }
+
+ if (no_synth_child || !child_valobj_sp) {
+ // No child member with name "child_name"
+ if (synthetically_added_instance_object) {
+ // We added a "this->" or "self->" to the beginning of the
+ // expression
+ // and this is the first pointer ivar access, so just return
+ // the normal
+ // error
+ error.SetErrorStringWithFormat(
+ "no variable or instance variable named '%s' found in "
+ "this frame",
+ name_const_string.GetCString());
+ } else {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ if (child_name) {
+ error.SetErrorStringWithFormat(
+ "\"%s\" is not a member of \"(%s) %s\"",
+ child_name.GetCString(),
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ } else {
+ error.SetErrorStringWithFormat(
+ "incomplete expression path after \"%s\" in \"%s\"",
+ var_expr_path_strm.GetString().c_str(), var_expr_cstr);
+ }
}
+ return ValueObjectSP();
+ }
}
+ synthetically_added_instance_object = false;
+ // Remove the child name from the path
+ var_path.erase(0, child_name.GetLength());
+ if (use_dynamic != eNoDynamicValues) {
+ ValueObjectSP dynamic_value_sp(
+ child_valobj_sp->GetDynamicValue(use_dynamic));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
+ }
+ } break;
+
+ case '[':
+ // Array member access, or treating pointer as an array
+ if (var_path.size() > 2) // Need at least two brackets and a number
+ {
+ char *end = nullptr;
+ long child_index = ::strtol(&var_path[1], &end, 0);
+ if (end && *end == ']' &&
+ *(end - 1) != '[') // this code forces an error in the case of
+ // arr[]. as bitfield[] is not a good
+ // syntax we're good to go
+ {
+ if (valobj_sp->GetCompilerType().IsPointerToScalarType() &&
+ deref) {
+ // what we have is *ptr[low]. the most similar C++ syntax is
+ // to deref ptr
+ // and extract bit low out of it. reading array item low
+ // would be done by saying ptr[low], without a deref * sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->Dereference(error));
+ if (error.Fail()) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "could not dereference \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ } else if (valobj_sp->GetCompilerType().IsArrayOfScalarType() &&
+ deref) {
+ // what we have is *arr[low]. the most similar C++ syntax is
+ // to get arr[0]
+ // (an operation that is equivalent to deref-ing arr)
+ // and extract bit low out of it. reading array item low
+ // would be done by saying arr[low], without a deref * sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true));
+ if (error.Fail()) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "could not get item 0 for \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ }
+
+ bool is_incomplete_array = false;
+ if (valobj_sp->IsPointerType()) {
+ bool is_objc_pointer = true;
+
+ if (valobj_sp->GetCompilerType().GetMinimumLanguage() !=
+ eLanguageTypeObjC)
+ is_objc_pointer = false;
+ else if (!valobj_sp->GetCompilerType().IsPointerType())
+ is_objc_pointer = false;
+
+ if (no_synth_child && is_objc_pointer) {
+ error.SetErrorStringWithFormat(
+ "\"(%s) %s\" is an Objective-C pointer, and cannot be "
+ "subscripted",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
- if (var_sp && !valobj_sp)
- {
- valobj_sp = GetValueObjectForFrameVariable (var_sp, use_dynamic);
- if (!valobj_sp)
- return valobj_sp;
- }
- if (valobj_sp)
- {
- // We are dumping at least one child
- while (separator_idx != std::string::npos)
- {
- // Calculate the next separator index ahead of time
- ValueObjectSP child_valobj_sp;
- const char separator_type = var_path[0];
- switch (separator_type)
+ return ValueObjectSP();
+ } else if (is_objc_pointer) {
+ // dereferencing ObjC variables is not valid.. so let's try
+ // and recur to synthetic children
+ ValueObjectSP synthetic = valobj_sp->GetSyntheticValue();
+ if (!synthetic /* no synthetic */
+ || synthetic == valobj_sp) /* synthetic is the same as
+ the original object */
{
- case '-':
- if (var_path.size() >= 2 && var_path[1] != '>')
- return ValueObjectSP();
-
- if (no_fragile_ivar)
- {
- // Make sure we aren't trying to deref an objective
- // C ivar if this is not allowed
- const uint32_t pointer_type_flags = valobj_sp->GetCompilerType().GetTypeInfo(nullptr);
- if ((pointer_type_flags & eTypeIsObjC) &&
- (pointer_type_flags & eTypeIsPointer))
- {
- // This was an objective C object pointer and
- // it was requested we skip any fragile ivars
- // so return nothing here
- return ValueObjectSP();
- }
- }
- var_path.erase (0, 1); // Remove the '-'
- LLVM_FALLTHROUGH;
- case '.':
- {
- const bool expr_is_ptr = var_path[0] == '>';
-
- var_path.erase (0, 1); // Remove the '.' or '>'
- separator_idx = var_path.find_first_of(".-[");
- ConstString child_name;
- if (separator_idx == std::string::npos)
- child_name.SetCString (var_path.c_str());
- else
- child_name.SetCStringWithLength(var_path.c_str(), separator_idx);
-
- if (check_ptr_vs_member)
- {
- // We either have a pointer type and need to verify
- // valobj_sp is a pointer, or we have a member of a
- // class/union/struct being accessed with the . syntax
- // and need to verify we don't have a pointer.
- const bool actual_is_ptr = valobj_sp->IsPointerType ();
-
- if (actual_is_ptr != expr_is_ptr)
- {
- // Incorrect use of "." with a pointer, or "->" with
- // a class/union/struct instance or reference.
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- if (actual_is_ptr)
- error.SetErrorStringWithFormat ("\"%s\" is a pointer and . was used to attempt to access \"%s\". Did you mean \"%s->%s\"?",
- var_expr_path_strm.GetString().c_str(),
- child_name.GetCString(),
- var_expr_path_strm.GetString().c_str(),
- var_path.c_str());
- else
- error.SetErrorStringWithFormat ("\"%s\" is not a pointer and -> was used to attempt to access \"%s\". Did you mean \"%s.%s\"?",
- var_expr_path_strm.GetString().c_str(),
- child_name.GetCString(),
- var_expr_path_strm.GetString().c_str(),
- var_path.c_str());
- return ValueObjectSP();
- }
- }
- child_valobj_sp = valobj_sp->GetChildMemberWithName (child_name, true);
- if (!child_valobj_sp)
- {
- if (!no_synth_child)
- {
- child_valobj_sp = valobj_sp->GetSyntheticValue();
- if (child_valobj_sp)
- child_valobj_sp = child_valobj_sp->GetChildMemberWithName (child_name, true);
- }
-
- if (no_synth_child || !child_valobj_sp)
- {
- // No child member with name "child_name"
- if (synthetically_added_instance_object)
- {
- // We added a "this->" or "self->" to the beginning of the expression
- // and this is the first pointer ivar access, so just return the normal
- // error
- error.SetErrorStringWithFormat("no variable or instance variable named '%s' found in this frame",
- name_const_string.GetCString());
- }
- else
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- if (child_name)
- {
- error.SetErrorStringWithFormat ("\"%s\" is not a member of \"(%s) %s\"",
- child_name.GetCString(),
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- else
- {
- error.SetErrorStringWithFormat ("incomplete expression path after \"%s\" in \"%s\"",
- var_expr_path_strm.GetString().c_str(),
- var_expr_cstr);
- }
- }
- return ValueObjectSP();
- }
- }
- synthetically_added_instance_object = false;
- // Remove the child name from the path
- var_path.erase(0, child_name.GetLength());
- if (use_dynamic != eNoDynamicValues)
- {
- ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
- if (dynamic_value_sp)
- child_valobj_sp = dynamic_value_sp;
- }
- }
- break;
-
- case '[':
- // Array member access, or treating pointer as an array
- if (var_path.size() > 2) // Need at least two brackets and a number
- {
- char *end = nullptr;
- long child_index = ::strtol (&var_path[1], &end, 0);
- if (end && *end == ']'
- && *(end-1) != '[') // this code forces an error in the case of arr[]. as bitfield[] is not a good syntax we're good to go
- {
- if (valobj_sp->GetCompilerType().IsPointerToScalarType() && deref)
- {
- // what we have is *ptr[low]. the most similar C++ syntax is to deref ptr
- // and extract bit low out of it. reading array item low
- // would be done by saying ptr[low], without a deref * sign
- Error error;
- ValueObjectSP temp(valobj_sp->Dereference(error));
- if (error.Fail())
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- return ValueObjectSP();
- }
- valobj_sp = temp;
- deref = false;
- }
- else if (valobj_sp->GetCompilerType().IsArrayOfScalarType() && deref)
- {
- // what we have is *arr[low]. the most similar C++ syntax is to get arr[0]
- // (an operation that is equivalent to deref-ing arr)
- // and extract bit low out of it. reading array item low
- // would be done by saying arr[low], without a deref * sign
- Error error;
- ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true));
- if (error.Fail())
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- return ValueObjectSP();
- }
- valobj_sp = temp;
- deref = false;
- }
-
- bool is_incomplete_array = false;
- if (valobj_sp->IsPointerType ())
- {
- bool is_objc_pointer = true;
-
- if (valobj_sp->GetCompilerType().GetMinimumLanguage() != eLanguageTypeObjC)
- is_objc_pointer = false;
- else if (!valobj_sp->GetCompilerType().IsPointerType())
- is_objc_pointer = false;
-
- if (no_synth_child && is_objc_pointer)
- {
- error.SetErrorStringWithFormat("\"(%s) %s\" is an Objective-C pointer, and cannot be subscripted",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
-
- return ValueObjectSP();
- }
- else if (is_objc_pointer)
- {
- // dereferencing ObjC variables is not valid.. so let's try and recur to synthetic children
- ValueObjectSP synthetic = valobj_sp->GetSyntheticValue();
- if (!synthetic /* no synthetic */
- || synthetic == valobj_sp) /* synthetic is the same as the original object */
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
- child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- else
- {
- child_valobj_sp = synthetic->GetChildAtIndex(child_index, true);
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
- child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }
- }
- else
- {
- child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true);
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("failed to use pointer as array for index %ld for \"(%s) %s\"",
- child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }
- }
- else if (valobj_sp->GetCompilerType().IsArrayType(nullptr, nullptr, &is_incomplete_array))
- {
- // Pass false to dynamic_value here so we can tell the difference between
- // no dynamic value and no member of this type...
- child_valobj_sp = valobj_sp->GetChildAtIndex (child_index, true);
- if (!child_valobj_sp && (is_incomplete_array || !no_synth_child))
- child_valobj_sp = valobj_sp->GetSyntheticArrayMember (child_index, true);
-
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
- child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }
- else if (valobj_sp->GetCompilerType().IsScalarType())
- {
- // this is a bitfield asking to display just one bit
- child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, child_index, true);
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"",
- child_index, child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }
- else
- {
- ValueObjectSP synthetic = valobj_sp->GetSyntheticValue();
- if (no_synth_child /* synthetic is forbidden */ ||
- !synthetic /* no synthetic */
- || synthetic == valobj_sp) /* synthetic is the same as the original object */
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("\"(%s) %s\" is not an array type",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- else if (static_cast<uint32_t>(child_index) >= synthetic->GetNumChildren() /* synthetic does not have that many values */)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
- child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- else
- {
- child_valobj_sp = synthetic->GetChildAtIndex(child_index, true);
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("array index %ld is not valid for \"(%s) %s\"",
- child_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }
- }
-
- if (!child_valobj_sp)
- {
- // Invalid array index...
- return ValueObjectSP();
- }
-
- // Erase the array member specification '[%i]' where
- // %i is the array index
- var_path.erase(0, (end - var_path.c_str()) + 1);
- separator_idx = var_path.find_first_of(".-[");
- if (use_dynamic != eNoDynamicValues)
- {
- ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
- if (dynamic_value_sp)
- child_valobj_sp = dynamic_value_sp;
- }
- // Break out early from the switch since we were
- // able to find the child member
- break;
- }
- else if (end && *end == '-')
- {
- // this is most probably a BitField, let's take a look
- char *real_end = nullptr;
- long final_index = ::strtol (end+1, &real_end, 0);
- bool expand_bitfield = true;
- if (real_end && *real_end == ']')
- {
- // if the format given is [high-low], swap range
- if (child_index > final_index)
- {
- long temp = child_index;
- child_index = final_index;
- final_index = temp;
- }
-
- if (valobj_sp->GetCompilerType().IsPointerToScalarType() && deref)
- {
- // what we have is *ptr[low-high]. the most similar C++ syntax is to deref ptr
- // and extract bits low thru high out of it. reading array items low thru high
- // would be done by saying ptr[low-high], without a deref * sign
- Error error;
- ValueObjectSP temp(valobj_sp->Dereference(error));
- if (error.Fail())
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("could not dereference \"(%s) %s\"",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- return ValueObjectSP();
- }
- valobj_sp = temp;
- deref = false;
- }
- else if (valobj_sp->GetCompilerType().IsArrayOfScalarType() && deref)
- {
- // what we have is *arr[low-high]. the most similar C++ syntax is to get arr[0]
- // (an operation that is equivalent to deref-ing arr)
- // and extract bits low thru high out of it. reading array items low thru high
- // would be done by saying arr[low-high], without a deref * sign
- Error error;
- ValueObjectSP temp(valobj_sp->GetChildAtIndex (0, true));
- if (error.Fail())
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("could not get item 0 for \"(%s) %s\"",
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- return ValueObjectSP();
- }
- valobj_sp = temp;
- deref = false;
- }
- /*else if (valobj_sp->IsArrayType() || valobj_sp->IsPointerType())
- {
- child_valobj_sp = valobj_sp->GetSyntheticArrayRangeChild(child_index, final_index, true);
- expand_bitfield = false;
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("array range %i-%i is not valid for \"(%s) %s\"",
- child_index, final_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }*/
-
- if (expand_bitfield)
- {
- child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(child_index, final_index, true);
- if (!child_valobj_sp)
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("bitfield range %ld-%ld is not valid for \"(%s) %s\"",
- child_index, final_index,
- valobj_sp->GetTypeName().AsCString("<invalid type>"),
- var_expr_path_strm.GetString().c_str());
- }
- }
- }
-
- if (!child_valobj_sp)
- {
- // Invalid bitfield range...
- return ValueObjectSP();
- }
-
- // Erase the bitfield member specification '[%i-%i]' where
- // %i is the index
- var_path.erase(0, (real_end - var_path.c_str()) + 1);
- separator_idx = var_path.find_first_of(".-[");
- if (use_dynamic != eNoDynamicValues)
- {
- ValueObjectSP dynamic_value_sp(child_valobj_sp->GetDynamicValue(use_dynamic));
- if (dynamic_value_sp)
- child_valobj_sp = dynamic_value_sp;
- }
- // Break out early from the switch since we were
- // able to find the child member
- break;
-
- }
- }
- else
- {
- error.SetErrorStringWithFormat("invalid square bracket encountered after \"%s\" in \"%s\"",
- var_expr_path_strm.GetString().c_str(),
- var_path.c_str());
- }
- return ValueObjectSP();
-
- default:
- // Failure...
- {
- valobj_sp->GetExpressionPath (var_expr_path_strm, false);
- error.SetErrorStringWithFormat ("unexpected char '%c' encountered after \"%s\" in \"%s\"",
- separator_type,
- var_expr_path_strm.GetString().c_str(),
- var_path.c_str());
-
- return ValueObjectSP();
- }
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "\"(%s) %s\" is not an array type",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ } else if (
+ static_cast<uint32_t>(child_index) >=
+ synthetic
+ ->GetNumChildren() /* synthetic does not have that many values */) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ } else {
+ child_valobj_sp =
+ synthetic->GetChildAtIndex(child_index, true);
+ if (!child_valobj_sp) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "array index %ld is not valid for \"(%s) %s\"",
+ child_index, valobj_sp->GetTypeName().AsCString(
+ "<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
}
+ } else {
+ child_valobj_sp =
+ valobj_sp->GetSyntheticArrayMember(child_index, true);
+ if (!child_valobj_sp) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "failed to use pointer as array for index %ld for "
+ "\"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ } else if (valobj_sp->GetCompilerType().IsArrayType(
+ nullptr, nullptr, &is_incomplete_array)) {
+ // Pass false to dynamic_value here so we can tell the
+ // difference between
+ // no dynamic value and no member of this type...
+ child_valobj_sp =
+ valobj_sp->GetChildAtIndex(child_index, true);
+ if (!child_valobj_sp &&
+ (is_incomplete_array || !no_synth_child))
+ child_valobj_sp =
+ valobj_sp->GetSyntheticArrayMember(child_index, true);
+
+ if (!child_valobj_sp) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ } else if (valobj_sp->GetCompilerType().IsScalarType()) {
+ // this is a bitfield asking to display just one bit
+ child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(
+ child_index, child_index, true);
+ if (!child_valobj_sp) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "bitfield range %ld-%ld is not valid for \"(%s) %s\"",
+ child_index, child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ } else {
+ ValueObjectSP synthetic = valobj_sp->GetSyntheticValue();
+ if (no_synth_child /* synthetic is forbidden */ ||
+ !synthetic /* no synthetic */
+ ||
+ synthetic == valobj_sp) /* synthetic is the same as the
+ original object */
+ {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "\"(%s) %s\" is not an array type",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ } else if (
+ static_cast<uint32_t>(child_index) >=
+ synthetic
+ ->GetNumChildren() /* synthetic does not have that many values */) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ } else {
+ child_valobj_sp =
+ synthetic->GetChildAtIndex(child_index, true);
+ if (!child_valobj_sp) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "array index %ld is not valid for \"(%s) %s\"",
+ child_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }
+ }
- if (child_valobj_sp)
- valobj_sp = child_valobj_sp;
-
- if (var_path.empty())
- break;
+ if (!child_valobj_sp) {
+ // Invalid array index...
+ return ValueObjectSP();
+ }
+
+ // Erase the array member specification '[%i]' where
+ // %i is the array index
+ var_path.erase(0, (end - var_path.c_str()) + 1);
+ separator_idx = var_path.find_first_of(".-[");
+ if (use_dynamic != eNoDynamicValues) {
+ ValueObjectSP dynamic_value_sp(
+ child_valobj_sp->GetDynamicValue(use_dynamic));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
}
- if (valobj_sp)
- {
- if (deref)
- {
- ValueObjectSP deref_valobj_sp (valobj_sp->Dereference(error));
- valobj_sp = deref_valobj_sp;
+ // Break out early from the switch since we were
+ // able to find the child member
+ break;
+ } else if (end && *end == '-') {
+ // this is most probably a BitField, let's take a look
+ char *real_end = nullptr;
+ long final_index = ::strtol(end + 1, &real_end, 0);
+ bool expand_bitfield = true;
+ if (real_end && *real_end == ']') {
+ // if the format given is [high-low], swap range
+ if (child_index > final_index) {
+ long temp = child_index;
+ child_index = final_index;
+ final_index = temp;
+ }
+
+ if (valobj_sp->GetCompilerType().IsPointerToScalarType() &&
+ deref) {
+ // what we have is *ptr[low-high]. the most similar C++
+ // syntax is to deref ptr
+ // and extract bits low thru high out of it. reading array
+ // items low thru high
+ // would be done by saying ptr[low-high], without a deref *
+ // sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->Dereference(error));
+ if (error.Fail()) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "could not dereference \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
}
- else if (address_of)
- {
- ValueObjectSP address_of_valobj_sp (valobj_sp->AddressOf(error));
- valobj_sp = address_of_valobj_sp;
+ valobj_sp = temp;
+ deref = false;
+ } else if (valobj_sp->GetCompilerType()
+ .IsArrayOfScalarType() &&
+ deref) {
+ // what we have is *arr[low-high]. the most similar C++
+ // syntax is to get arr[0]
+ // (an operation that is equivalent to deref-ing arr)
+ // and extract bits low thru high out of it. reading array
+ // items low thru high
+ // would be done by saying arr[low-high], without a deref *
+ // sign
+ Error error;
+ ValueObjectSP temp(valobj_sp->GetChildAtIndex(0, true));
+ if (error.Fail()) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "could not get item 0 for \"(%s) %s\"",
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
+ return ValueObjectSP();
+ }
+ valobj_sp = temp;
+ deref = false;
+ }
+ /*else if (valobj_sp->IsArrayType() ||
+ valobj_sp->IsPointerType())
+ {
+ child_valobj_sp =
+ valobj_sp->GetSyntheticArrayRangeChild(child_index,
+ final_index, true);
+ expand_bitfield = false;
+ if (!child_valobj_sp)
+ {
+ valobj_sp->GetExpressionPath (var_expr_path_strm,
+ false);
+ error.SetErrorStringWithFormat ("array range %i-%i is
+ not valid for \"(%s) %s\"",
+ child_index,
+ final_index,
+ valobj_sp->GetTypeName().AsCString("<invalid
+ type>"),
+ var_expr_path_strm.GetString().c_str());
+ }
+ }*/
+
+ if (expand_bitfield) {
+ child_valobj_sp = valobj_sp->GetSyntheticBitFieldChild(
+ child_index, final_index, true);
+ if (!child_valobj_sp) {
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "bitfield range %ld-%ld is not valid for \"(%s) %s\"",
+ child_index, final_index,
+ valobj_sp->GetTypeName().AsCString("<invalid type>"),
+ var_expr_path_strm.GetString().c_str());
}
+ }
}
- return valobj_sp;
- }
- else
- {
- error.SetErrorStringWithFormat("no variable named '%s' found in this frame",
- name_const_string.GetCString());
- }
- }
- }
- else
- {
- error.SetErrorStringWithFormat("invalid variable path '%s'", var_expr_cstr);
- }
- return ValueObjectSP();
-}
-bool
-StackFrame::GetFrameBaseValue (Scalar &frame_base, Error *error_ptr)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (!m_cfa_is_valid)
- {
- m_frame_base_error.SetErrorString("No frame base available for this historical stack frame.");
- return false;
- }
-
- if (m_flags.IsClear(GOT_FRAME_BASE))
- {
- if (m_sc.function)
- {
- m_frame_base.Clear();
- m_frame_base_error.Clear();
-
- m_flags.Set(GOT_FRAME_BASE);
- ExecutionContext exe_ctx (shared_from_this());
- Value expr_value;
- addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
- if (m_sc.function->GetFrameBaseExpression().IsLocationList())
- loclist_base_addr = m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress (exe_ctx.GetTargetPtr());
-
- if (m_sc.function->GetFrameBaseExpression().Evaluate(&exe_ctx,
- nullptr,
- nullptr,
- nullptr,
- loclist_base_addr,
- nullptr,
- nullptr,
- expr_value,
- &m_frame_base_error) == false)
- {
- // We should really have an error if evaluate returns, but in case
- // we don't, lets set the error to something at least.
- if (m_frame_base_error.Success())
- m_frame_base_error.SetErrorString("Evaluation of the frame base expression failed.");
+ if (!child_valobj_sp) {
+ // Invalid bitfield range...
+ return ValueObjectSP();
+ }
+
+ // Erase the bitfield member specification '[%i-%i]' where
+ // %i is the index
+ var_path.erase(0, (real_end - var_path.c_str()) + 1);
+ separator_idx = var_path.find_first_of(".-[");
+ if (use_dynamic != eNoDynamicValues) {
+ ValueObjectSP dynamic_value_sp(
+ child_valobj_sp->GetDynamicValue(use_dynamic));
+ if (dynamic_value_sp)
+ child_valobj_sp = dynamic_value_sp;
+ }
+ // Break out early from the switch since we were
+ // able to find the child member
+ break;
+ }
+ } else {
+ error.SetErrorStringWithFormat(
+ "invalid square bracket encountered after \"%s\" in \"%s\"",
+ var_expr_path_strm.GetString().c_str(), var_path.c_str());
}
- else
+ return ValueObjectSP();
+
+ default:
+ // Failure...
{
- m_frame_base = expr_value.ResolveValue(&exe_ctx);
- }
+ valobj_sp->GetExpressionPath(var_expr_path_strm, false);
+ error.SetErrorStringWithFormat(
+ "unexpected char '%c' encountered after \"%s\" in \"%s\"",
+ separator_type, var_expr_path_strm.GetString().c_str(),
+ var_path.c_str());
+
+ return ValueObjectSP();
+ }
+ }
+
+ if (child_valobj_sp)
+ valobj_sp = child_valobj_sp;
+
+ if (var_path.empty())
+ break;
+ }
+ if (valobj_sp) {
+ if (deref) {
+ ValueObjectSP deref_valobj_sp(valobj_sp->Dereference(error));
+ valobj_sp = deref_valobj_sp;
+ } else if (address_of) {
+ ValueObjectSP address_of_valobj_sp(valobj_sp->AddressOf(error));
+ valobj_sp = address_of_valobj_sp;
+ }
}
- else
- {
- m_frame_base_error.SetErrorString ("No function in symbol context.");
- }
- }
-
- if (m_frame_base_error.Success())
- frame_base = m_frame_base;
-
- if (error_ptr)
- *error_ptr = m_frame_base_error;
- return m_frame_base_error.Success();
-}
+ return valobj_sp;
+ } else {
+ error.SetErrorStringWithFormat(
+ "no variable named '%s' found in this frame",
+ name_const_string.GetCString());
+ }
+ }
+ } else {
+ error.SetErrorStringWithFormat("invalid variable path '%s'", var_expr_cstr);
+ }
+ return ValueObjectSP();
+}
+
+bool StackFrame::GetFrameBaseValue(Scalar &frame_base, Error *error_ptr) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (!m_cfa_is_valid) {
+ m_frame_base_error.SetErrorString(
+ "No frame base available for this historical stack frame.");
+ return false;
+ }
-DWARFExpression *
-StackFrame::GetFrameBaseExpression(Error *error_ptr)
-{
- if (!m_sc.function)
- {
- if (error_ptr)
- {
- error_ptr->SetErrorString ("No function in symbol context.");
- }
- return nullptr;
+ if (m_flags.IsClear(GOT_FRAME_BASE)) {
+ if (m_sc.function) {
+ m_frame_base.Clear();
+ m_frame_base_error.Clear();
+
+ m_flags.Set(GOT_FRAME_BASE);
+ ExecutionContext exe_ctx(shared_from_this());
+ Value expr_value;
+ addr_t loclist_base_addr = LLDB_INVALID_ADDRESS;
+ if (m_sc.function->GetFrameBaseExpression().IsLocationList())
+ loclist_base_addr =
+ m_sc.function->GetAddressRange().GetBaseAddress().GetLoadAddress(
+ exe_ctx.GetTargetPtr());
+
+ if (m_sc.function->GetFrameBaseExpression().Evaluate(
+ &exe_ctx, nullptr, nullptr, nullptr, loclist_base_addr, nullptr,
+ nullptr, expr_value, &m_frame_base_error) == false) {
+ // We should really have an error if evaluate returns, but in case
+ // we don't, lets set the error to something at least.
+ if (m_frame_base_error.Success())
+ m_frame_base_error.SetErrorString(
+ "Evaluation of the frame base expression failed.");
+ } else {
+ m_frame_base = expr_value.ResolveValue(&exe_ctx);
+ }
+ } else {
+ m_frame_base_error.SetErrorString("No function in symbol context.");
+ }
+ }
+
+ if (m_frame_base_error.Success())
+ frame_base = m_frame_base;
+
+ if (error_ptr)
+ *error_ptr = m_frame_base_error;
+ return m_frame_base_error.Success();
+}
+
+DWARFExpression *StackFrame::GetFrameBaseExpression(Error *error_ptr) {
+ if (!m_sc.function) {
+ if (error_ptr) {
+ error_ptr->SetErrorString("No function in symbol context.");
}
+ return nullptr;
+ }
- return &m_sc.function->GetFrameBaseExpression();
+ return &m_sc.function->GetFrameBaseExpression();
}
-RegisterContextSP
-StackFrame::GetRegisterContext ()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (!m_reg_context_sp)
- {
- ThreadSP thread_sp (GetThread());
- if (thread_sp)
- m_reg_context_sp = thread_sp->CreateRegisterContextForFrame (this);
- }
- return m_reg_context_sp;
+RegisterContextSP StackFrame::GetRegisterContext() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (!m_reg_context_sp) {
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp)
+ m_reg_context_sp = thread_sp->CreateRegisterContextForFrame(this);
+ }
+ return m_reg_context_sp;
}
-bool
-StackFrame::HasDebugInformation ()
-{
- GetSymbolContext (eSymbolContextLineEntry);
- return m_sc.line_entry.IsValid();
+bool StackFrame::HasDebugInformation() {
+ GetSymbolContext(eSymbolContextLineEntry);
+ return m_sc.line_entry.IsValid();
}
ValueObjectSP
-StackFrame::GetValueObjectForFrameVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- ValueObjectSP valobj_sp;
- if (m_is_history_frame)
- {
- return valobj_sp;
- }
- VariableList *var_list = GetVariableList (true);
- if (var_list)
- {
- // Make sure the variable is a frame variable
- const uint32_t var_idx = var_list->FindIndexForVariable (variable_sp.get());
- const uint32_t num_variables = var_list->GetSize();
- if (var_idx < num_variables)
- {
- valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex (var_idx);
- if (!valobj_sp)
- {
- if (m_variable_list_value_objects.GetSize() < num_variables)
- m_variable_list_value_objects.Resize(num_variables);
- valobj_sp = ValueObjectVariable::Create (this, variable_sp);
- m_variable_list_value_objects.SetValueObjectAtIndex (var_idx, valobj_sp);
- }
- }
- }
- if (use_dynamic != eNoDynamicValues && valobj_sp)
- {
- ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue (use_dynamic);
- if (dynamic_sp)
- return dynamic_sp;
- }
+StackFrame::GetValueObjectForFrameVariable(const VariableSP &variable_sp,
+ DynamicValueType use_dynamic) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ ValueObjectSP valobj_sp;
+ if (m_is_history_frame) {
return valobj_sp;
+ }
+ VariableList *var_list = GetVariableList(true);
+ if (var_list) {
+ // Make sure the variable is a frame variable
+ const uint32_t var_idx = var_list->FindIndexForVariable(variable_sp.get());
+ const uint32_t num_variables = var_list->GetSize();
+ if (var_idx < num_variables) {
+ valobj_sp = m_variable_list_value_objects.GetValueObjectAtIndex(var_idx);
+ if (!valobj_sp) {
+ if (m_variable_list_value_objects.GetSize() < num_variables)
+ m_variable_list_value_objects.Resize(num_variables);
+ valobj_sp = ValueObjectVariable::Create(this, variable_sp);
+ m_variable_list_value_objects.SetValueObjectAtIndex(var_idx, valobj_sp);
+ }
+ }
+ }
+ if (use_dynamic != eNoDynamicValues && valobj_sp) {
+ ValueObjectSP dynamic_sp = valobj_sp->GetDynamicValue(use_dynamic);
+ if (dynamic_sp)
+ return dynamic_sp;
+ }
+ return valobj_sp;
+}
+
+ValueObjectSP StackFrame::TrackGlobalVariable(const VariableSP &variable_sp,
+ DynamicValueType use_dynamic) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_is_history_frame)
+ return ValueObjectSP();
+
+ // Check to make sure we aren't already tracking this variable?
+ ValueObjectSP valobj_sp(
+ GetValueObjectForFrameVariable(variable_sp, use_dynamic));
+ if (!valobj_sp) {
+ // We aren't already tracking this global
+ VariableList *var_list = GetVariableList(true);
+ // If this frame has no variables, create a new list
+ if (var_list == nullptr)
+ m_variable_list_sp.reset(new VariableList());
+
+ // Add the global/static variable to this frame
+ m_variable_list_sp->AddVariable(variable_sp);
+
+ // Now make a value object for it so we can track its changes
+ valobj_sp = GetValueObjectForFrameVariable(variable_sp, use_dynamic);
+ }
+ return valobj_sp;
+}
+
+bool StackFrame::IsInlined() {
+ if (m_sc.block == nullptr)
+ GetSymbolContext(eSymbolContextBlock);
+ if (m_sc.block)
+ return m_sc.block->GetContainingInlinedBlock() != nullptr;
+ return false;
+}
+
+lldb::LanguageType StackFrame::GetLanguage() {
+ CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit;
+ if (cu)
+ return cu->GetLanguage();
+ return lldb::eLanguageTypeUnknown;
+}
+
+lldb::LanguageType StackFrame::GuessLanguage() {
+ LanguageType lang_type = GetLanguage();
+
+ if (lang_type == eLanguageTypeUnknown) {
+ Function *f = GetSymbolContext(eSymbolContextFunction).function;
+ if (f) {
+ lang_type = f->GetMangled().GuessLanguage();
+ }
+ }
+
+ return lang_type;
+}
+
+namespace {
+std::pair<const Instruction::Operand *, int64_t>
+GetBaseExplainingValue(const Instruction::Operand &operand,
+ RegisterContext ®ister_context, lldb::addr_t value) {
+ switch (operand.m_type) {
+ case Instruction::Operand::Type::Dereference:
+ case Instruction::Operand::Type::Immediate:
+ case Instruction::Operand::Type::Invalid:
+ case Instruction::Operand::Type::Product:
+ // These are not currently interesting
+ return std::make_pair(nullptr, 0);
+ case Instruction::Operand::Type::Sum: {
+ const Instruction::Operand *immediate_child = nullptr;
+ const Instruction::Operand *variable_child = nullptr;
+ if (operand.m_children[0].m_type == Instruction::Operand::Type::Immediate) {
+ immediate_child = &operand.m_children[0];
+ variable_child = &operand.m_children[1];
+ } else if (operand.m_children[1].m_type ==
+ Instruction::Operand::Type::Immediate) {
+ immediate_child = &operand.m_children[1];
+ variable_child = &operand.m_children[0];
+ }
+ if (!immediate_child) {
+ return std::make_pair(nullptr, 0);
+ }
+ lldb::addr_t adjusted_value = value;
+ if (immediate_child->m_negative) {
+ adjusted_value += immediate_child->m_immediate;
+ } else {
+ adjusted_value -= immediate_child->m_immediate;
+ }
+ std::pair<const Instruction::Operand *, int64_t> base_and_offset =
+ GetBaseExplainingValue(*variable_child, register_context,
+ adjusted_value);
+ if (!base_and_offset.first) {
+ return std::make_pair(nullptr, 0);
+ }
+ if (immediate_child->m_negative) {
+ base_and_offset.second -= immediate_child->m_immediate;
+ } else {
+ base_and_offset.second += immediate_child->m_immediate;
+ }
+ return base_and_offset;
+ }
+ case Instruction::Operand::Type::Register: {
+ const RegisterInfo *info =
+ register_context.GetRegisterInfoByName(operand.m_register.AsCString());
+ if (!info) {
+ return std::make_pair(nullptr, 0);
+ }
+ RegisterValue reg_value;
+ if (!register_context.ReadRegister(info, reg_value)) {
+ return std::make_pair(nullptr, 0);
+ }
+ if (reg_value.GetAsUInt64() == value) {
+ return std::make_pair(&operand, 0);
+ } else {
+ return std::make_pair(nullptr, 0);
+ }
+ }
+ }
+}
+
+std::pair<const Instruction::Operand *, int64_t>
+GetBaseExplainingDereference(const Instruction::Operand &operand,
+ RegisterContext ®ister_context,
+ lldb::addr_t addr) {
+ if (operand.m_type == Instruction::Operand::Type::Dereference) {
+ return GetBaseExplainingValue(operand.m_children[0], register_context,
+ addr);
+ }
+ return std::make_pair(nullptr, 0);
}
+};
-ValueObjectSP
-StackFrame::TrackGlobalVariable (const VariableSP &variable_sp, DynamicValueType use_dynamic)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (m_is_history_frame)
- return ValueObjectSP();
+lldb::ValueObjectSP StackFrame::GuessValueForAddress(lldb::addr_t addr) {
+ TargetSP target_sp = CalculateTarget();
- // Check to make sure we aren't already tracking this variable?
- ValueObjectSP valobj_sp (GetValueObjectForFrameVariable (variable_sp, use_dynamic));
- if (!valobj_sp)
- {
- // We aren't already tracking this global
- VariableList *var_list = GetVariableList (true);
- // If this frame has no variables, create a new list
- if (var_list == nullptr)
- m_variable_list_sp.reset (new VariableList());
+ const ArchSpec &target_arch = target_sp->GetArchitecture();
- // Add the global/static variable to this frame
- m_variable_list_sp->AddVariable (variable_sp);
+ AddressRange pc_range;
+ pc_range.GetBaseAddress() = GetFrameCodeAddress();
+ pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize());
- // Now make a value object for it so we can track its changes
- valobj_sp = GetValueObjectForFrameVariable (variable_sp, use_dynamic);
- }
- return valobj_sp;
-}
+ ExecutionContext exe_ctx(shared_from_this());
-bool
-StackFrame::IsInlined ()
-{
- if (m_sc.block == nullptr)
- GetSymbolContext (eSymbolContextBlock);
- if (m_sc.block)
- return m_sc.block->GetContainingInlinedBlock() != nullptr;
- return false;
-}
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ const bool prefer_file_cache = false;
-lldb::LanguageType
-StackFrame::GetLanguage ()
-{
- CompileUnit *cu = GetSymbolContext(eSymbolContextCompUnit).comp_unit;
- if (cu)
- return cu->GetLanguage();
- return lldb::eLanguageTypeUnknown;
-}
-
-lldb::LanguageType
-StackFrame::GuessLanguage ()
-{
- LanguageType lang_type = GetLanguage();
-
- if (lang_type == eLanguageTypeUnknown)
- {
- Function *f = GetSymbolContext(eSymbolContextFunction).function;
- if (f)
- {
- lang_type = f->GetMangled().GuessLanguage();
- }
- }
-
- return lang_type;
-}
-
-namespace
-{
- std::pair<const Instruction::Operand *, int64_t>
- GetBaseExplainingValue(const Instruction::Operand &operand,
- RegisterContext ®ister_context,
- lldb::addr_t value)
- {
- switch(operand.m_type)
- {
- case Instruction::Operand::Type::Dereference:
- case Instruction::Operand::Type::Immediate:
- case Instruction::Operand::Type::Invalid:
- case Instruction::Operand::Type::Product:
- // These are not currently interesting
- return std::make_pair(nullptr, 0);
- case Instruction::Operand::Type::Sum:
- {
- const Instruction::Operand *immediate_child = nullptr;
- const Instruction::Operand *variable_child = nullptr;
- if (operand.m_children[0].m_type == Instruction::Operand::Type::Immediate)
- {
- immediate_child = &operand.m_children[0];
- variable_child = &operand.m_children[1];
- }
- else if (operand.m_children[1].m_type == Instruction::Operand::Type::Immediate)
- {
- immediate_child = &operand.m_children[1];
- variable_child = &operand.m_children[0];
- }
- if (!immediate_child)
- {
- return std::make_pair(nullptr, 0);
- }
- lldb::addr_t adjusted_value = value;
- if (immediate_child->m_negative)
- {
- adjusted_value += immediate_child->m_immediate;
- }
- else
- {
- adjusted_value -= immediate_child->m_immediate;
- }
- std::pair<const Instruction::Operand *, int64_t> base_and_offset = GetBaseExplainingValue(*variable_child, register_context, adjusted_value);
- if (!base_and_offset.first)
- {
- return std::make_pair(nullptr, 0);
- }
- if (immediate_child->m_negative)
- {
- base_and_offset.second -= immediate_child->m_immediate;
- }
- else
- {
- base_and_offset.second += immediate_child->m_immediate;
- }
- return base_and_offset;
- }
- case Instruction::Operand::Type::Register:
- {
- const RegisterInfo *info = register_context.GetRegisterInfoByName(operand.m_register.AsCString());
- if (!info)
- {
- return std::make_pair(nullptr, 0);
- }
- RegisterValue reg_value;
- if (!register_context.ReadRegister(info, reg_value))
- {
- return std::make_pair(nullptr, 0);
- }
- if (reg_value.GetAsUInt64() == value)
- {
- return std::make_pair(&operand, 0);
- }
- else
- {
- return std::make_pair(nullptr, 0);
- }
- }
- }
- }
-
- std::pair<const Instruction::Operand *, int64_t>
- GetBaseExplainingDereference(const Instruction::Operand &operand,
- RegisterContext ®ister_context,
- lldb::addr_t addr)
- {
- if (operand.m_type == Instruction::Operand::Type::Dereference)
- {
- return GetBaseExplainingValue(operand.m_children[0],
- register_context,
- addr);
- }
- return std::make_pair(nullptr, 0);
- }
-};
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+ target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache);
-lldb::ValueObjectSP
-StackFrame::GuessValueForAddress(lldb::addr_t addr)
-{
- TargetSP target_sp = CalculateTarget();
-
- const ArchSpec &target_arch = target_sp->GetArchitecture();
-
- AddressRange pc_range;
- pc_range.GetBaseAddress() = GetFrameCodeAddress();
- pc_range.SetByteSize(target_arch.GetMaximumOpcodeByteSize());
-
- ExecutionContext exe_ctx (shared_from_this());
-
- const char *plugin_name = nullptr;
- const char *flavor = nullptr;
- const bool prefer_file_cache = false;
-
- DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch,
- plugin_name,
- flavor,
- exe_ctx,
- pc_range,
- prefer_file_cache);
-
- if (!disassembler_sp->GetInstructionList().GetSize())
- {
- return ValueObjectSP();
- }
-
- InstructionSP instruction_sp = disassembler_sp->GetInstructionList().GetInstructionAtIndex(0);
-
- llvm::SmallVector<Instruction::Operand, 3> operands;
-
- if (!instruction_sp->ParseOperands(operands))
- {
- return ValueObjectSP();
- }
-
- RegisterContextSP register_context_sp = GetRegisterContext();
-
- if (!register_context_sp)
- {
- return ValueObjectSP();
- }
-
- for (const Instruction::Operand &operand : operands)
- {
- std::pair<const Instruction::Operand *, int64_t>
- base_and_offset = GetBaseExplainingDereference(operand, *register_context_sp, addr);
-
- if (!base_and_offset.first)
- {
- continue;
- }
-
- switch (base_and_offset.first->m_type)
- {
- case Instruction::Operand::Type::Immediate:
- {
- lldb_private::Address addr;
- if (target_sp->ResolveLoadAddress(base_and_offset.first->m_immediate + base_and_offset.second, addr))
- {
- TypeSystem *c_type_system = target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
- if (!c_type_system)
- {
- return ValueObjectSP();
- }
- else
- {
- CompilerType void_ptr_type = c_type_system->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar).GetPointerType();
- return ValueObjectMemory::Create(this, "", addr, void_ptr_type);
- }
- }
- else
- {
- return ValueObjectSP();
- }
- break;
- }
- case Instruction::Operand::Type::Register:
- {
- return GuessValueForRegisterAndOffset(base_and_offset.first->m_register, base_and_offset.second);
- }
- default:
- return ValueObjectSP();
- }
-
- }
+ if (!disassembler_sp->GetInstructionList().GetSize()) {
+ return ValueObjectSP();
+ }
+
+ InstructionSP instruction_sp =
+ disassembler_sp->GetInstructionList().GetInstructionAtIndex(0);
+ llvm::SmallVector<Instruction::Operand, 3> operands;
+
+ if (!instruction_sp->ParseOperands(operands)) {
return ValueObjectSP();
-}
+ }
-namespace
-{
- ValueObjectSP
- GetValueForOffset(StackFrame &frame, ValueObjectSP &parent, int64_t offset)
- {
- if (offset < 0 || uint64_t(offset) >= parent->GetByteSize())
- {
- return ValueObjectSP();
- }
-
- if (parent->IsPointerOrReferenceType())
- {
- return parent;
- }
-
- for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci)
- {
- const bool can_create = true;
- ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create);
-
- if (!child_sp)
- {
- return ValueObjectSP();
- }
-
- int64_t child_offset = child_sp->GetByteOffset();
- int64_t child_size = child_sp->GetByteSize();
-
- if (offset >= child_offset &&
- offset < (child_offset + child_size))
- {
- return GetValueForOffset(frame, child_sp, offset - child_offset);
- }
- }
-
- if (offset == 0)
- {
- return parent;
- }
- else
- {
- return ValueObjectSP();
- }
- }
-
- ValueObjectSP
- GetValueForDereferincingOffset(StackFrame &frame, ValueObjectSP &base, int64_t offset)
- {
- // base is a pointer to something
- // offset is the thing to add to the pointer
- // We return the most sensible ValueObject for the result of *(base+offset)
+ RegisterContextSP register_context_sp = GetRegisterContext();
- if (!base->IsPointerOrReferenceType())
- {
- return ValueObjectSP();
- }
-
- Error error;
- ValueObjectSP pointee = base->Dereference(error);
-
- if (offset >= pointee->GetByteSize())
- {
- int64_t index = offset / pointee->GetByteSize();
- offset = offset % pointee->GetByteSize();
- const bool can_create = true;
- pointee = base->GetSyntheticArrayMember(index, can_create);
- }
-
- if (!pointee || error.Fail())
- {
- return ValueObjectSP();
- }
-
- return GetValueForOffset(frame, pointee, offset);
- }
-
- //------------------------------------------------------------------
- /// Attempt to reconstruct the ValueObject for the address contained in a
- /// given register plus an offset.
- ///
- /// @params [in] frame
- /// The current stack frame.
- ///
- /// @params [in] reg
- /// The register.
- ///
- /// @params [in] offset
- /// The offset from the register.
- ///
- /// @param [in] disassembler
- /// A disassembler containing instructions valid up to the current PC.
- ///
- /// @param [in] variables
- /// The variable list from the current frame,
- ///
- /// @param [in] pc
- /// The program counter for the instruction considered the 'user'.
- ///
- /// @return
- /// A string describing the base for the ExpressionPath. This could be a
- /// variable, a register value, an argument, or a function return value.
- /// The ValueObject if found. If valid, it has a valid ExpressionPath.
- //------------------------------------------------------------------
- lldb::ValueObjectSP
- DoGuessValueAt(StackFrame &frame, ConstString reg, int64_t offset, Disassembler &disassembler, VariableList &variables, const Address &pc)
- {
- // Example of operation for Intel:
- //
- // +14: movq -0x8(%rbp), %rdi
- // +18: movq 0x8(%rdi), %rdi
- // +22: addl 0x4(%rdi), %eax
- //
- // f, a pointer to a struct, is known to be at -0x8(%rbp).
- //
- // DoGuessValueAt(frame, rdi, 4, dis, vars, 0x22) finds the instruction at +18 that assigns to rdi, and calls itself recursively for that dereference
- // DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at +14 that assigns to rdi, and calls itself recursively for that derefernece
- // DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the variable list.
- // Returns a ValueObject for f. (That's what was stored at rbp-8 at +14)
- // Returns a ValueObject for *(f+8) or f->b (That's what was stored at rdi+8 at +18)
- // Returns a ValueObject for *(f->b+4) or f->b->a (That's what was stored at rdi+4 at +22)
-
- // First, check the variable list to see if anything is at the specified location.
- for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi)
- {
- VariableSP var_sp = variables.GetVariableAtIndex(vi);
- DWARFExpression &dwarf_expression = var_sp->LocationExpression();
-
- const RegisterInfo *expression_reg;
- int64_t expression_offset;
- ExecutionContext exe_ctx;
-
- if (dwarf_expression.IsDereferenceOfRegister(frame, expression_reg, expression_offset))
- {
- if ((reg == ConstString(expression_reg->name) ||
- reg == ConstString(expression_reg->alt_name)) &&
- expression_offset == offset)
- {
- return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues);
- }
- }
- }
-
- bool is_in_return_register = false;
- ABISP abi_sp = frame.CalculateProcess()->GetABI();
- RegisterInfo return_register_info;
-
- if (abi_sp)
- {
- const char *return_register_name;
- const RegisterInfo *reg_info = nullptr;
- if (abi_sp->GetPointerReturnRegister(return_register_name) &&
- reg == ConstString(return_register_name) &&
- (reg_info = frame.GetRegisterContext()->GetRegisterInfoByName(return_register_name)))
- {
- is_in_return_register = true;
- return_register_info = *reg_info;
- }
- }
-
- const uint32_t current_inst = disassembler.GetInstructionList().GetIndexOfInstructionAtAddress(pc);
- if (current_inst == UINT32_MAX)
- {
- return ValueObjectSP();
- }
-
- ValueObjectSP source_path;
-
- for (uint32_t ii = current_inst - 1; ii != (uint32_t)-1; --ii)
- {
- // This is not an exact algorithm, and it sacrifices accuracy for generality.
- // Recognizing "mov" and "ld" instructions –– and which are their source and
- // destination operands -- is something the disassembler should do for us.
- InstructionSP instruction_sp = disassembler.GetInstructionList().GetInstructionAtIndex(ii);
-
- if (is_in_return_register && instruction_sp->IsCall())
- {
- llvm::SmallVector<Instruction::Operand, 1> operands;
- if (!instruction_sp->ParseOperands(operands) || operands.size() != 1)
- {
- continue;
- }
-
- switch (operands[0].m_type)
- {
- default:
- break;
- case Instruction::Operand::Type::Immediate:
- {
- SymbolContext sc;
- Address load_address;
- if (!frame.CalculateTarget()->ResolveLoadAddress(operands[0].m_immediate, load_address))
- {
- break;
- }
- frame.CalculateTarget()->GetImages().ResolveSymbolContextForAddress(load_address, eSymbolContextFunction, sc);
- if (!sc.function)
- {
- break;
- }
- CompilerType function_type = sc.function->GetCompilerType();
- if (!function_type.IsFunctionType())
- {
- break;
- }
- CompilerType return_type = function_type.GetFunctionReturnType();
- RegisterValue return_value;
- if (!frame.GetRegisterContext()->ReadRegister(&return_register_info, return_value))
- {
- break;
- }
- std::string name_str(sc.function->GetName().AsCString("<unknown function>"));
- name_str.append("()");
- Address return_value_address(return_value.GetAsUInt64());
- ValueObjectSP return_value_sp = ValueObjectMemory::Create(&frame, name_str.c_str(), return_value_address, return_type);
- return GetValueForDereferincingOffset(frame, return_value_sp, offset);
- }
- }
+ if (!register_context_sp) {
+ return ValueObjectSP();
+ }
- continue;
- }
-
- llvm::SmallVector<Instruction::Operand, 2> operands;
- if (!instruction_sp->ParseOperands(operands) || operands.size() != 2)
- {
- continue;
- }
-
- Instruction::Operand *register_operand = nullptr;
- Instruction::Operand *origin_operand = nullptr;
- if (operands[0].m_type == Instruction::Operand::Type::Register &&
- operands[0].m_clobbered == true &&
- operands[0].m_register == reg)
- {
- register_operand = &operands[0];
- origin_operand = &operands[1];
- }
- else if (operands[1].m_type == Instruction::Operand::Type::Register &&
- operands[1].m_clobbered == true &&
- operands[1].m_register == reg)
- {
- register_operand = &operands[1];
- origin_operand = &operands[0];
- }
- else
- {
- continue;
- }
-
- // We have an origin operand. Can we track its value down?
- switch (origin_operand->m_type)
- {
- default:
- break;
- case Instruction::Operand::Type::Register:
- source_path = DoGuessValueAt(frame, origin_operand->m_register, 0, disassembler, variables, instruction_sp->GetAddress());
- break;
- case Instruction::Operand::Type::Dereference:
- {
- const Instruction::Operand &pointer = origin_operand->m_children[0];
- switch (pointer.m_type)
- {
- default:
- break;
- case Instruction::Operand::Type::Register:
- source_path = DoGuessValueAt(frame, pointer.m_register, 0, disassembler, variables, instruction_sp->GetAddress());
- if (source_path)
- {
- Error err;
- source_path = source_path->Dereference(err);
- if (!err.Success())
- {
- source_path.reset();
- }
- }
- break;
- case Instruction::Operand::Type::Sum:
- {
- const Instruction::Operand *origin_register = nullptr;
- const Instruction::Operand *origin_offset = nullptr;
- if (pointer.m_children.size() != 2)
- {
- break;
- }
- if (pointer.m_children[0].m_type == Instruction::Operand::Type::Register &&
- pointer.m_children[1].m_type == Instruction::Operand::Type::Immediate)
- {
- origin_register = &pointer.m_children[0];
- origin_offset = &pointer.m_children[1];
- }
- else if (pointer.m_children[1].m_type == Instruction::Operand::Type::Register &&
- pointer.m_children[0].m_type == Instruction::Operand::Type::Immediate)
- {
- origin_register = &pointer.m_children[1];
- origin_offset = &pointer.m_children[0];
- }
- if (!origin_register)
- {
- break;
- }
- int64_t signed_origin_offset = origin_offset->m_negative ? -((int64_t)origin_offset->m_immediate) : origin_offset->m_immediate;
- source_path = DoGuessValueAt(frame, origin_register->m_register, signed_origin_offset, disassembler, variables, instruction_sp->GetAddress());
- if (!source_path)
- {
- break;
- }
- source_path = GetValueForDereferincingOffset(frame, source_path, offset);
- break;
- }
- }
- }
- }
-
- if (source_path)
- {
- return source_path;
- }
+ for (const Instruction::Operand &operand : operands) {
+ std::pair<const Instruction::Operand *, int64_t> base_and_offset =
+ GetBaseExplainingDereference(operand, *register_context_sp, addr);
+
+ if (!base_and_offset.first) {
+ continue;
+ }
+
+ switch (base_and_offset.first->m_type) {
+ case Instruction::Operand::Type::Immediate: {
+ lldb_private::Address addr;
+ if (target_sp->ResolveLoadAddress(base_and_offset.first->m_immediate +
+ base_and_offset.second,
+ addr)) {
+ TypeSystem *c_type_system =
+ target_sp->GetScratchTypeSystemForLanguage(nullptr, eLanguageTypeC);
+ if (!c_type_system) {
+ return ValueObjectSP();
+ } else {
+ CompilerType void_ptr_type =
+ c_type_system
+ ->GetBasicTypeFromAST(lldb::BasicType::eBasicTypeChar)
+ .GetPointerType();
+ return ValueObjectMemory::Create(this, "", addr, void_ptr_type);
}
-
+ } else {
return ValueObjectSP();
+ }
+ break;
}
+ case Instruction::Operand::Type::Register: {
+ return GuessValueForRegisterAndOffset(base_and_offset.first->m_register,
+ base_and_offset.second);
+ }
+ default:
+ return ValueObjectSP();
+ }
+ }
+
+ return ValueObjectSP();
}
-lldb::ValueObjectSP
-StackFrame::GuessValueForRegisterAndOffset(ConstString reg, int64_t offset)
-{
- TargetSP target_sp = CalculateTarget();
-
- const ArchSpec &target_arch = target_sp->GetArchitecture();
+namespace {
+ValueObjectSP GetValueForOffset(StackFrame &frame, ValueObjectSP &parent,
+ int64_t offset) {
+ if (offset < 0 || uint64_t(offset) >= parent->GetByteSize()) {
+ return ValueObjectSP();
+ }
- Block *frame_block = GetFrameBlock();
-
- if (!frame_block)
- {
- return ValueObjectSP();
- }
+ if (parent->IsPointerOrReferenceType()) {
+ return parent;
+ }
- Function *function = frame_block->CalculateSymbolContextFunction();
- if (!function)
- {
- return ValueObjectSP();
- }
-
- AddressRange pc_range = function->GetAddressRange();
+ for (int ci = 0, ce = parent->GetNumChildren(); ci != ce; ++ci) {
+ const bool can_create = true;
+ ValueObjectSP child_sp = parent->GetChildAtIndex(ci, can_create);
- if (GetFrameCodeAddress().GetFileAddress() < pc_range.GetBaseAddress().GetFileAddress() ||
- GetFrameCodeAddress().GetFileAddress() - pc_range.GetBaseAddress().GetFileAddress() >= pc_range.GetByteSize())
- {
- return ValueObjectSP();
- }
-
- ExecutionContext exe_ctx (shared_from_this());
-
- const char *plugin_name = nullptr;
- const char *flavor = nullptr;
- const bool prefer_file_cache = false;
- DisassemblerSP disassembler_sp = Disassembler::DisassembleRange (target_arch,
- plugin_name,
- flavor,
- exe_ctx,
- pc_range,
- prefer_file_cache);
-
- if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize())
- {
- return ValueObjectSP();
+ if (!child_sp) {
+ return ValueObjectSP();
}
-
- const bool get_file_globals = false;
- VariableList *variables = GetVariableList(get_file_globals);
-
- if (!variables)
- {
- return ValueObjectSP();
+
+ int64_t child_offset = child_sp->GetByteOffset();
+ int64_t child_size = child_sp->GetByteSize();
+
+ if (offset >= child_offset && offset < (child_offset + child_size)) {
+ return GetValueForOffset(frame, child_sp, offset - child_offset);
}
-
- return DoGuessValueAt(*this, reg, offset, *disassembler_sp, *variables, GetFrameCodeAddress());
-}
+ }
-TargetSP
-StackFrame::CalculateTarget ()
-{
- TargetSP target_sp;
- ThreadSP thread_sp(GetThread());
- if (thread_sp)
- {
- ProcessSP process_sp (thread_sp->CalculateProcess());
- if (process_sp)
- target_sp = process_sp->CalculateTarget();
- }
- return target_sp;
+ if (offset == 0) {
+ return parent;
+ } else {
+ return ValueObjectSP();
+ }
}
-ProcessSP
-StackFrame::CalculateProcess ()
-{
- ProcessSP process_sp;
- ThreadSP thread_sp(GetThread());
- if (thread_sp)
- process_sp = thread_sp->CalculateProcess();
- return process_sp;
-}
+ValueObjectSP GetValueForDereferincingOffset(StackFrame &frame,
+ ValueObjectSP &base,
+ int64_t offset) {
+ // base is a pointer to something
+ // offset is the thing to add to the pointer
+ // We return the most sensible ValueObject for the result of *(base+offset)
-ThreadSP
-StackFrame::CalculateThread ()
-{
- return GetThread();
-}
+ if (!base->IsPointerOrReferenceType()) {
+ return ValueObjectSP();
+ }
-StackFrameSP
-StackFrame::CalculateStackFrame ()
-{
- return shared_from_this();
-}
+ Error error;
+ ValueObjectSP pointee = base->Dereference(error);
+
+ if (offset >= pointee->GetByteSize()) {
+ int64_t index = offset / pointee->GetByteSize();
+ offset = offset % pointee->GetByteSize();
+ const bool can_create = true;
+ pointee = base->GetSyntheticArrayMember(index, can_create);
+ }
-void
-StackFrame::CalculateExecutionContext (ExecutionContext &exe_ctx)
-{
- exe_ctx.SetContext (shared_from_this());
+ if (!pointee || error.Fail()) {
+ return ValueObjectSP();
+ }
+
+ return GetValueForOffset(frame, pointee, offset);
}
-void
-StackFrame::DumpUsingSettingsFormat (Stream *strm, const char *frame_marker)
-{
- if (strm == nullptr)
- return;
+//------------------------------------------------------------------
+/// Attempt to reconstruct the ValueObject for the address contained in a
+/// given register plus an offset.
+///
+/// @params [in] frame
+/// The current stack frame.
+///
+/// @params [in] reg
+/// The register.
+///
+/// @params [in] offset
+/// The offset from the register.
+///
+/// @param [in] disassembler
+/// A disassembler containing instructions valid up to the current PC.
+///
+/// @param [in] variables
+/// The variable list from the current frame,
+///
+/// @param [in] pc
+/// The program counter for the instruction considered the 'user'.
+///
+/// @return
+/// A string describing the base for the ExpressionPath. This could be a
+/// variable, a register value, an argument, or a function return value.
+/// The ValueObject if found. If valid, it has a valid ExpressionPath.
+//------------------------------------------------------------------
+lldb::ValueObjectSP DoGuessValueAt(StackFrame &frame, ConstString reg,
+ int64_t offset, Disassembler &disassembler,
+ VariableList &variables, const Address &pc) {
+ // Example of operation for Intel:
+ //
+ // +14: movq -0x8(%rbp), %rdi
+ // +18: movq 0x8(%rdi), %rdi
+ // +22: addl 0x4(%rdi), %eax
+ //
+ // f, a pointer to a struct, is known to be at -0x8(%rbp).
+ //
+ // DoGuessValueAt(frame, rdi, 4, dis, vars, 0x22) finds the instruction at +18
+ // that assigns to rdi, and calls itself recursively for that dereference
+ // DoGuessValueAt(frame, rdi, 8, dis, vars, 0x18) finds the instruction at
+ // +14 that assigns to rdi, and calls itself recursively for that
+ // derefernece
+ // DoGuessValueAt(frame, rbp, -8, dis, vars, 0x14) finds "f" in the
+ // variable list.
+ // Returns a ValueObject for f. (That's what was stored at rbp-8 at +14)
+ // Returns a ValueObject for *(f+8) or f->b (That's what was stored at rdi+8
+ // at +18)
+ // Returns a ValueObject for *(f->b+4) or f->b->a (That's what was stored at
+ // rdi+4 at +22)
+
+ // First, check the variable list to see if anything is at the specified
+ // location.
+ for (size_t vi = 0, ve = variables.GetSize(); vi != ve; ++vi) {
+ VariableSP var_sp = variables.GetVariableAtIndex(vi);
+ DWARFExpression &dwarf_expression = var_sp->LocationExpression();
+
+ const RegisterInfo *expression_reg;
+ int64_t expression_offset;
+ ExecutionContext exe_ctx;
+
+ if (dwarf_expression.IsDereferenceOfRegister(frame, expression_reg,
+ expression_offset)) {
+ if ((reg == ConstString(expression_reg->name) ||
+ reg == ConstString(expression_reg->alt_name)) &&
+ expression_offset == offset) {
+ return frame.GetValueObjectForFrameVariable(var_sp, eNoDynamicValues);
+ }
+ }
+ }
+
+ bool is_in_return_register = false;
+ ABISP abi_sp = frame.CalculateProcess()->GetABI();
+ RegisterInfo return_register_info;
+
+ if (abi_sp) {
+ const char *return_register_name;
+ const RegisterInfo *reg_info = nullptr;
+ if (abi_sp->GetPointerReturnRegister(return_register_name) &&
+ reg == ConstString(return_register_name) &&
+ (reg_info = frame.GetRegisterContext()->GetRegisterInfoByName(
+ return_register_name))) {
+ is_in_return_register = true;
+ return_register_info = *reg_info;
+ }
+ }
+
+ const uint32_t current_inst =
+ disassembler.GetInstructionList().GetIndexOfInstructionAtAddress(pc);
+ if (current_inst == UINT32_MAX) {
+ return ValueObjectSP();
+ }
+
+ ValueObjectSP source_path;
- GetSymbolContext(eSymbolContextEverything);
- ExecutionContext exe_ctx (shared_from_this());
- StreamString s;
-
- if (frame_marker)
- s.PutCString(frame_marker);
+ for (uint32_t ii = current_inst - 1; ii != (uint32_t)-1; --ii) {
+ // This is not an exact algorithm, and it sacrifices accuracy for
+ // generality.
+ // Recognizing "mov" and "ld" instructions –– and which are their source and
+ // destination operands -- is something the disassembler should do for us.
+ InstructionSP instruction_sp =
+ disassembler.GetInstructionList().GetInstructionAtIndex(ii);
+
+ if (is_in_return_register && instruction_sp->IsCall()) {
+ llvm::SmallVector<Instruction::Operand, 1> operands;
+ if (!instruction_sp->ParseOperands(operands) || operands.size() != 1) {
+ continue;
+ }
+
+ switch (operands[0].m_type) {
+ default:
+ break;
+ case Instruction::Operand::Type::Immediate: {
+ SymbolContext sc;
+ Address load_address;
+ if (!frame.CalculateTarget()->ResolveLoadAddress(
+ operands[0].m_immediate, load_address)) {
+ break;
+ }
+ frame.CalculateTarget()->GetImages().ResolveSymbolContextForAddress(
+ load_address, eSymbolContextFunction, sc);
+ if (!sc.function) {
+ break;
+ }
+ CompilerType function_type = sc.function->GetCompilerType();
+ if (!function_type.IsFunctionType()) {
+ break;
+ }
+ CompilerType return_type = function_type.GetFunctionReturnType();
+ RegisterValue return_value;
+ if (!frame.GetRegisterContext()->ReadRegister(&return_register_info,
+ return_value)) {
+ break;
+ }
+ std::string name_str(
+ sc.function->GetName().AsCString("<unknown function>"));
+ name_str.append("()");
+ Address return_value_address(return_value.GetAsUInt64());
+ ValueObjectSP return_value_sp = ValueObjectMemory::Create(
+ &frame, name_str.c_str(), return_value_address, return_type);
+ return GetValueForDereferincingOffset(frame, return_value_sp, offset);
+ }
+ }
+
+ continue;
+ }
+
+ llvm::SmallVector<Instruction::Operand, 2> operands;
+ if (!instruction_sp->ParseOperands(operands) || operands.size() != 2) {
+ continue;
+ }
+
+ Instruction::Operand *register_operand = nullptr;
+ Instruction::Operand *origin_operand = nullptr;
+ if (operands[0].m_type == Instruction::Operand::Type::Register &&
+ operands[0].m_clobbered == true && operands[0].m_register == reg) {
+ register_operand = &operands[0];
+ origin_operand = &operands[1];
+ } else if (operands[1].m_type == Instruction::Operand::Type::Register &&
+ operands[1].m_clobbered == true &&
+ operands[1].m_register == reg) {
+ register_operand = &operands[1];
+ origin_operand = &operands[0];
+ } else {
+ continue;
+ }
+
+ // We have an origin operand. Can we track its value down?
+ switch (origin_operand->m_type) {
+ default:
+ break;
+ case Instruction::Operand::Type::Register:
+ source_path =
+ DoGuessValueAt(frame, origin_operand->m_register, 0, disassembler,
+ variables, instruction_sp->GetAddress());
+ break;
+ case Instruction::Operand::Type::Dereference: {
+ const Instruction::Operand &pointer = origin_operand->m_children[0];
+ switch (pointer.m_type) {
+ default:
+ break;
+ case Instruction::Operand::Type::Register:
+ source_path = DoGuessValueAt(frame, pointer.m_register, 0, disassembler,
+ variables, instruction_sp->GetAddress());
+ if (source_path) {
+ Error err;
+ source_path = source_path->Dereference(err);
+ if (!err.Success()) {
+ source_path.reset();
+ }
+ }
+ break;
+ case Instruction::Operand::Type::Sum: {
+ const Instruction::Operand *origin_register = nullptr;
+ const Instruction::Operand *origin_offset = nullptr;
+ if (pointer.m_children.size() != 2) {
+ break;
+ }
+ if (pointer.m_children[0].m_type ==
+ Instruction::Operand::Type::Register &&
+ pointer.m_children[1].m_type ==
+ Instruction::Operand::Type::Immediate) {
+ origin_register = &pointer.m_children[0];
+ origin_offset = &pointer.m_children[1];
+ } else if (pointer.m_children[1].m_type ==
+ Instruction::Operand::Type::Register &&
+ pointer.m_children[0].m_type ==
+ Instruction::Operand::Type::Immediate) {
+ origin_register = &pointer.m_children[1];
+ origin_offset = &pointer.m_children[0];
+ }
+ if (!origin_register) {
+ break;
+ }
+ int64_t signed_origin_offset =
+ origin_offset->m_negative ? -((int64_t)origin_offset->m_immediate)
+ : origin_offset->m_immediate;
+ source_path = DoGuessValueAt(frame, origin_register->m_register,
+ signed_origin_offset, disassembler,
+ variables, instruction_sp->GetAddress());
+ if (!source_path) {
+ break;
+ }
+ source_path =
+ GetValueForDereferincingOffset(frame, source_path, offset);
+ break;
+ }
+ }
+ }
+ }
+
+ if (source_path) {
+ return source_path;
+ }
+ }
+
+ return ValueObjectSP();
+}
+}
+
+lldb::ValueObjectSP StackFrame::GuessValueForRegisterAndOffset(ConstString reg,
+ int64_t offset) {
+ TargetSP target_sp = CalculateTarget();
- const FormatEntity::Entry *frame_format = nullptr;
- Target *target = exe_ctx.GetTargetPtr();
- if (target)
- frame_format = target->GetDebugger().GetFrameFormat();
- if (frame_format && FormatEntity::Format(*frame_format, s, &m_sc, &exe_ctx, nullptr, nullptr, false, false))
- {
- strm->Write(s.GetData(), s.GetSize());
- }
- else
- {
- Dump (strm, true, false);
- strm->EOL();
- }
-}
+ const ArchSpec &target_arch = target_sp->GetArchitecture();
-void
-StackFrame::Dump (Stream *strm, bool show_frame_index, bool show_fullpaths)
-{
- if (strm == nullptr)
- return;
-
- if (show_frame_index)
- strm->Printf("frame #%u: ", m_frame_index);
- ExecutionContext exe_ctx (shared_from_this());
- Target *target = exe_ctx.GetTargetPtr();
- strm->Printf("0x%0*" PRIx64 " ",
- target ? (target->GetArchitecture().GetAddressByteSize() * 2) : 16,
- GetFrameCodeAddress().GetLoadAddress(target));
- GetSymbolContext(eSymbolContextEverything);
- const bool show_module = true;
- const bool show_inline = true;
- const bool show_function_arguments = true;
- const bool show_function_name = true;
- m_sc.DumpStopContext (strm,
- exe_ctx.GetBestExecutionContextScope(),
- GetFrameCodeAddress(),
- show_fullpaths,
- show_module,
- show_inline,
- show_function_arguments,
- show_function_name);
-}
-
-void
-StackFrame::UpdateCurrentFrameFromPreviousFrame (StackFrame &prev_frame)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- assert (GetStackID() == prev_frame.GetStackID()); // TODO: remove this after some testing
- m_variable_list_sp = prev_frame.m_variable_list_sp;
- m_variable_list_value_objects.Swap (prev_frame.m_variable_list_value_objects);
- if (!m_disassembly.GetString().empty())
- m_disassembly.GetString().swap (m_disassembly.GetString());
-}
-
-void
-StackFrame::UpdatePreviousFrameFromCurrentFrame (StackFrame &curr_frame)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- assert (GetStackID() == curr_frame.GetStackID()); // TODO: remove this after some testing
- m_id.SetPC (curr_frame.m_id.GetPC()); // Update the Stack ID PC value
- assert (GetThread() == curr_frame.GetThread());
- m_frame_index = curr_frame.m_frame_index;
- m_concrete_frame_index = curr_frame.m_concrete_frame_index;
- m_reg_context_sp = curr_frame.m_reg_context_sp;
- m_frame_code_addr = curr_frame.m_frame_code_addr;
- assert (!m_sc.target_sp || !curr_frame.m_sc.target_sp || m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get());
- assert (!m_sc.module_sp || !curr_frame.m_sc.module_sp || m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get());
- assert (m_sc.comp_unit == nullptr || curr_frame.m_sc.comp_unit == nullptr || m_sc.comp_unit == curr_frame.m_sc.comp_unit);
- assert (m_sc.function == nullptr || curr_frame.m_sc.function == nullptr || m_sc.function == curr_frame.m_sc.function);
- m_sc = curr_frame.m_sc;
- m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything);
- m_flags.Set (m_sc.GetResolvedMask());
- m_frame_base.Clear();
- m_frame_base_error.Clear();
-}
-
-bool
-StackFrame::HasCachedData () const
-{
- if (m_variable_list_sp)
- return true;
- if (m_variable_list_value_objects.GetSize() > 0)
- return true;
- if (!m_disassembly.GetString().empty())
- return true;
- return false;
-}
+ Block *frame_block = GetFrameBlock();
-bool
-StackFrame::GetStatus (Stream& strm,
- bool show_frame_info,
- bool show_source,
- const char *frame_marker)
-{
-
- if (show_frame_info)
- {
- strm.Indent();
- DumpUsingSettingsFormat (&strm, frame_marker);
- }
-
- if (show_source)
- {
- ExecutionContext exe_ctx (shared_from_this());
- bool have_source = false, have_debuginfo = false;
- Debugger::StopDisassemblyType disasm_display = Debugger::eStopDisassemblyTypeNever;
- Target *target = exe_ctx.GetTargetPtr();
- if (target)
- {
- Debugger &debugger = target->GetDebugger();
- const uint32_t source_lines_before = debugger.GetStopSourceLineCount(true);
- const uint32_t source_lines_after = debugger.GetStopSourceLineCount(false);
- disasm_display = debugger.GetStopDisassemblyDisplay ();
+ if (!frame_block) {
+ return ValueObjectSP();
+ }
- GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
- if (m_sc.comp_unit && m_sc.line_entry.IsValid())
- {
- have_debuginfo = true;
- if (source_lines_before > 0 || source_lines_after > 0)
- {
- size_t num_lines = target->GetSourceManager().DisplaySourceLinesWithLineNumbers (m_sc.line_entry.file,
- m_sc.line_entry.line,
- source_lines_before,
- source_lines_after,
- "->",
- &strm);
- if (num_lines != 0)
- have_source = true;
- // TODO: Give here a one time warning if source file is missing.
- }
- }
- switch (disasm_display)
- {
- case Debugger::eStopDisassemblyTypeNever:
- break;
+ Function *function = frame_block->CalculateSymbolContextFunction();
+ if (!function) {
+ return ValueObjectSP();
+ }
- case Debugger::eStopDisassemblyTypeNoDebugInfo:
- if (have_debuginfo)
- break;
- LLVM_FALLTHROUGH;
+ AddressRange pc_range = function->GetAddressRange();
- case Debugger::eStopDisassemblyTypeNoSource:
- if (have_source)
- break;
- LLVM_FALLTHROUGH;
+ if (GetFrameCodeAddress().GetFileAddress() <
+ pc_range.GetBaseAddress().GetFileAddress() ||
+ GetFrameCodeAddress().GetFileAddress() -
+ pc_range.GetBaseAddress().GetFileAddress() >=
+ pc_range.GetByteSize()) {
+ return ValueObjectSP();
+ }
- case Debugger::eStopDisassemblyTypeAlways:
- if (target)
- {
- const uint32_t disasm_lines = debugger.GetDisassemblyLineCount();
- if (disasm_lines > 0)
- {
- const ArchSpec &target_arch = target->GetArchitecture();
- AddressRange pc_range;
- pc_range.GetBaseAddress() = GetFrameCodeAddress();
- pc_range.SetByteSize(disasm_lines * target_arch.GetMaximumOpcodeByteSize());
- const char *plugin_name = nullptr;
- const char *flavor = nullptr;
- Disassembler::Disassemble (target->GetDebugger(),
- target_arch,
- plugin_name,
- flavor,
- exe_ctx,
- pc_range,
- disasm_lines,
- 0,
- Disassembler::eOptionMarkPCAddress,
- strm);
- }
- }
- break;
- }
+ ExecutionContext exe_ctx(shared_from_this());
+
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ const bool prefer_file_cache = false;
+ DisassemblerSP disassembler_sp = Disassembler::DisassembleRange(
+ target_arch, plugin_name, flavor, exe_ctx, pc_range, prefer_file_cache);
+
+ if (!disassembler_sp || !disassembler_sp->GetInstructionList().GetSize()) {
+ return ValueObjectSP();
+ }
+
+ const bool get_file_globals = false;
+ VariableList *variables = GetVariableList(get_file_globals);
+
+ if (!variables) {
+ return ValueObjectSP();
+ }
+
+ return DoGuessValueAt(*this, reg, offset, *disassembler_sp, *variables,
+ GetFrameCodeAddress());
+}
+
+TargetSP StackFrame::CalculateTarget() {
+ TargetSP target_sp;
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp) {
+ ProcessSP process_sp(thread_sp->CalculateProcess());
+ if (process_sp)
+ target_sp = process_sp->CalculateTarget();
+ }
+ return target_sp;
+}
+
+ProcessSP StackFrame::CalculateProcess() {
+ ProcessSP process_sp;
+ ThreadSP thread_sp(GetThread());
+ if (thread_sp)
+ process_sp = thread_sp->CalculateProcess();
+ return process_sp;
+}
+
+ThreadSP StackFrame::CalculateThread() { return GetThread(); }
+
+StackFrameSP StackFrame::CalculateStackFrame() { return shared_from_this(); }
+
+void StackFrame::CalculateExecutionContext(ExecutionContext &exe_ctx) {
+ exe_ctx.SetContext(shared_from_this());
+}
+
+void StackFrame::DumpUsingSettingsFormat(Stream *strm,
+ const char *frame_marker) {
+ if (strm == nullptr)
+ return;
+
+ GetSymbolContext(eSymbolContextEverything);
+ ExecutionContext exe_ctx(shared_from_this());
+ StreamString s;
+
+ if (frame_marker)
+ s.PutCString(frame_marker);
+
+ const FormatEntity::Entry *frame_format = nullptr;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target)
+ frame_format = target->GetDebugger().GetFrameFormat();
+ if (frame_format && FormatEntity::Format(*frame_format, s, &m_sc, &exe_ctx,
+ nullptr, nullptr, false, false)) {
+ strm->Write(s.GetData(), s.GetSize());
+ } else {
+ Dump(strm, true, false);
+ strm->EOL();
+ }
+}
+
+void StackFrame::Dump(Stream *strm, bool show_frame_index,
+ bool show_fullpaths) {
+ if (strm == nullptr)
+ return;
+
+ if (show_frame_index)
+ strm->Printf("frame #%u: ", m_frame_index);
+ ExecutionContext exe_ctx(shared_from_this());
+ Target *target = exe_ctx.GetTargetPtr();
+ strm->Printf("0x%0*" PRIx64 " ",
+ target ? (target->GetArchitecture().GetAddressByteSize() * 2)
+ : 16,
+ GetFrameCodeAddress().GetLoadAddress(target));
+ GetSymbolContext(eSymbolContextEverything);
+ const bool show_module = true;
+ const bool show_inline = true;
+ const bool show_function_arguments = true;
+ const bool show_function_name = true;
+ m_sc.DumpStopContext(strm, exe_ctx.GetBestExecutionContextScope(),
+ GetFrameCodeAddress(), show_fullpaths, show_module,
+ show_inline, show_function_arguments,
+ show_function_name);
+}
+
+void StackFrame::UpdateCurrentFrameFromPreviousFrame(StackFrame &prev_frame) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ assert(GetStackID() ==
+ prev_frame.GetStackID()); // TODO: remove this after some testing
+ m_variable_list_sp = prev_frame.m_variable_list_sp;
+ m_variable_list_value_objects.Swap(prev_frame.m_variable_list_value_objects);
+ if (!m_disassembly.GetString().empty())
+ m_disassembly.GetString().swap(m_disassembly.GetString());
+}
+
+void StackFrame::UpdatePreviousFrameFromCurrentFrame(StackFrame &curr_frame) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ assert(GetStackID() ==
+ curr_frame.GetStackID()); // TODO: remove this after some testing
+ m_id.SetPC(curr_frame.m_id.GetPC()); // Update the Stack ID PC value
+ assert(GetThread() == curr_frame.GetThread());
+ m_frame_index = curr_frame.m_frame_index;
+ m_concrete_frame_index = curr_frame.m_concrete_frame_index;
+ m_reg_context_sp = curr_frame.m_reg_context_sp;
+ m_frame_code_addr = curr_frame.m_frame_code_addr;
+ assert(!m_sc.target_sp || !curr_frame.m_sc.target_sp ||
+ m_sc.target_sp.get() == curr_frame.m_sc.target_sp.get());
+ assert(!m_sc.module_sp || !curr_frame.m_sc.module_sp ||
+ m_sc.module_sp.get() == curr_frame.m_sc.module_sp.get());
+ assert(m_sc.comp_unit == nullptr || curr_frame.m_sc.comp_unit == nullptr ||
+ m_sc.comp_unit == curr_frame.m_sc.comp_unit);
+ assert(m_sc.function == nullptr || curr_frame.m_sc.function == nullptr ||
+ m_sc.function == curr_frame.m_sc.function);
+ m_sc = curr_frame.m_sc;
+ m_flags.Clear(GOT_FRAME_BASE | eSymbolContextEverything);
+ m_flags.Set(m_sc.GetResolvedMask());
+ m_frame_base.Clear();
+ m_frame_base_error.Clear();
+}
+
+bool StackFrame::HasCachedData() const {
+ if (m_variable_list_sp)
+ return true;
+ if (m_variable_list_value_objects.GetSize() > 0)
+ return true;
+ if (!m_disassembly.GetString().empty())
+ return true;
+ return false;
+}
+
+bool StackFrame::GetStatus(Stream &strm, bool show_frame_info, bool show_source,
+ const char *frame_marker) {
+
+ if (show_frame_info) {
+ strm.Indent();
+ DumpUsingSettingsFormat(&strm, frame_marker);
+ }
+
+ if (show_source) {
+ ExecutionContext exe_ctx(shared_from_this());
+ bool have_source = false, have_debuginfo = false;
+ Debugger::StopDisassemblyType disasm_display =
+ Debugger::eStopDisassemblyTypeNever;
+ Target *target = exe_ctx.GetTargetPtr();
+ if (target) {
+ Debugger &debugger = target->GetDebugger();
+ const uint32_t source_lines_before =
+ debugger.GetStopSourceLineCount(true);
+ const uint32_t source_lines_after =
+ debugger.GetStopSourceLineCount(false);
+ disasm_display = debugger.GetStopDisassemblyDisplay();
+
+ GetSymbolContext(eSymbolContextCompUnit | eSymbolContextLineEntry);
+ if (m_sc.comp_unit && m_sc.line_entry.IsValid()) {
+ have_debuginfo = true;
+ if (source_lines_before > 0 || source_lines_after > 0) {
+ size_t num_lines =
+ target->GetSourceManager().DisplaySourceLinesWithLineNumbers(
+ m_sc.line_entry.file, m_sc.line_entry.line,
+ source_lines_before, source_lines_after, "->", &strm);
+ if (num_lines != 0)
+ have_source = true;
+ // TODO: Give here a one time warning if source file is missing.
+ }
+ }
+ switch (disasm_display) {
+ case Debugger::eStopDisassemblyTypeNever:
+ break;
+
+ case Debugger::eStopDisassemblyTypeNoDebugInfo:
+ if (have_debuginfo)
+ break;
+ LLVM_FALLTHROUGH;
+
+ case Debugger::eStopDisassemblyTypeNoSource:
+ if (have_source)
+ break;
+ LLVM_FALLTHROUGH;
+
+ case Debugger::eStopDisassemblyTypeAlways:
+ if (target) {
+ const uint32_t disasm_lines = debugger.GetDisassemblyLineCount();
+ if (disasm_lines > 0) {
+ const ArchSpec &target_arch = target->GetArchitecture();
+ AddressRange pc_range;
+ pc_range.GetBaseAddress() = GetFrameCodeAddress();
+ pc_range.SetByteSize(disasm_lines *
+ target_arch.GetMaximumOpcodeByteSize());
+ const char *plugin_name = nullptr;
+ const char *flavor = nullptr;
+ Disassembler::Disassemble(target->GetDebugger(), target_arch,
+ plugin_name, flavor, exe_ctx, pc_range,
+ disasm_lines, 0,
+ Disassembler::eOptionMarkPCAddress, strm);
+ }
}
+ break;
+ }
}
- return true;
+ }
+ return true;
}
Modified: lldb/trunk/source/Target/StackFrameList.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackFrameList.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackFrameList.cpp (original)
+++ lldb/trunk/source/Target/StackFrameList.cpp Tue Sep 6 15:57:50 2016
@@ -12,11 +12,11 @@
// Other libraries and framework includes
// Project includes
#include "lldb/Target/StackFrameList.h"
-#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/Breakpoint.h"
+#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Log.h"
-#include "lldb/Core/StreamFile.h"
#include "lldb/Core/SourceManager.h"
+#include "lldb/Core/StreamFile.h"
#include "lldb/Symbol/Block.h"
#include "lldb/Symbol/Function.h"
#include "lldb/Symbol/Symbol.h"
@@ -36,908 +36,818 @@ using namespace lldb_private;
//----------------------------------------------------------------------
// StackFrameList constructor
//----------------------------------------------------------------------
-StackFrameList::StackFrameList(Thread &thread, const lldb::StackFrameListSP &prev_frames_sp, bool show_inline_frames)
- : m_thread(thread),
- m_prev_frames_sp(prev_frames_sp),
- m_mutex(),
- m_frames(),
- m_selected_frame_idx(0),
- m_concrete_frames_fetched(0),
+StackFrameList::StackFrameList(Thread &thread,
+ const lldb::StackFrameListSP &prev_frames_sp,
+ bool show_inline_frames)
+ : m_thread(thread), m_prev_frames_sp(prev_frames_sp), m_mutex(), m_frames(),
+ m_selected_frame_idx(0), m_concrete_frames_fetched(0),
m_current_inlined_depth(UINT32_MAX),
m_current_inlined_pc(LLDB_INVALID_ADDRESS),
- m_show_inlined_frames(show_inline_frames)
-{
- if (prev_frames_sp)
- {
- m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;
- m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;
- }
-}
-
-StackFrameList::~StackFrameList()
-{
- // Call clear since this takes a lock and clears the stack frame list
- // in case another thread is currently using this stack frame list
- Clear();
-}
+ m_show_inlined_frames(show_inline_frames) {
+ if (prev_frames_sp) {
+ m_current_inlined_depth = prev_frames_sp->m_current_inlined_depth;
+ m_current_inlined_pc = prev_frames_sp->m_current_inlined_pc;
+ }
+}
+
+StackFrameList::~StackFrameList() {
+ // Call clear since this takes a lock and clears the stack frame list
+ // in case another thread is currently using this stack frame list
+ Clear();
+}
+
+void StackFrameList::CalculateCurrentInlinedDepth() {
+ uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
+ if (cur_inlined_depth == UINT32_MAX) {
+ ResetCurrentInlinedDepth();
+ }
+}
+
+uint32_t StackFrameList::GetCurrentInlinedDepth() {
+ if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS) {
+ lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
+ if (cur_pc != m_current_inlined_pc) {
+ m_current_inlined_pc = LLDB_INVALID_ADDRESS;
+ m_current_inlined_depth = UINT32_MAX;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf(
+ "GetCurrentInlinedDepth: invalidating current inlined depth.\n");
+ }
+ return m_current_inlined_depth;
+ } else {
+ return UINT32_MAX;
+ }
+}
+
+void StackFrameList::ResetCurrentInlinedDepth() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ if (m_show_inlined_frames) {
+ GetFramesUpTo(0);
+ if (m_frames.empty())
+ return;
+ if (!m_frames[0]->IsInlined()) {
+ m_current_inlined_depth = UINT32_MAX;
+ m_current_inlined_pc = LLDB_INVALID_ADDRESS;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf(
+ "ResetCurrentInlinedDepth: Invalidating current inlined depth.\n");
+ } else {
+ // We only need to do something special about inlined blocks when we
+ // are at the beginning of an inlined function:
+ // FIXME: We probably also have to do something special if the PC is at
+ // the END
+ // of an inlined function, which coincides with the end of either its
+ // containing
+ // function or another inlined function.
+
+ lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
+ Block *block_ptr = m_frames[0]->GetFrameBlock();
+ if (block_ptr) {
+ Address pc_as_address;
+ pc_as_address.SetLoadAddress(curr_pc,
+ &(m_thread.GetProcess()->GetTarget()));
+ AddressRange containing_range;
+ if (block_ptr->GetRangeContainingAddress(pc_as_address,
+ containing_range)) {
+ if (pc_as_address == containing_range.GetBaseAddress()) {
+ // If we got here because of a breakpoint hit, then set the inlined
+ // depth depending on where
+ // the breakpoint was set.
+ // If we got here because of a crash, then set the inlined depth to
+ // the deepest most block.
+ // Otherwise, we stopped here naturally as the result of a step, so
+ // set ourselves in the
+ // containing frame of the whole set of nested inlines, so the user
+ // can then "virtually"
+ // step into the frames one by one, or next over the whole mess.
+ // Note: We don't have to handle being somewhere in the middle of
+ // the stack here, since
+ // ResetCurrentInlinedDepth doesn't get called if there is a valid
+ // inlined depth set.
+ StopInfoSP stop_info_sp = m_thread.GetStopInfo();
+ if (stop_info_sp) {
+ switch (stop_info_sp->GetStopReason()) {
+ case eStopReasonWatchpoint:
+ case eStopReasonException:
+ case eStopReasonExec:
+ case eStopReasonSignal:
+ // In all these cases we want to stop in the deepest most frame.
+ m_current_inlined_pc = curr_pc;
+ m_current_inlined_depth = 0;
+ break;
+ case eStopReasonBreakpoint: {
+ // FIXME: Figure out what this break point is doing, and set the
+ // inline depth
+ // appropriately. Be careful to take into account breakpoints
+ // that implement
+ // step over prologue, since that should do the default
+ // calculation.
+ // For now, if the breakpoints corresponding to this hit are all
+ // internal,
+ // I set the stop location to the top of the inlined stack,
+ // since that will make
+ // things like stepping over prologues work right. But if there
+ // are any non-internal
+ // breakpoints I do to the bottom of the stack, since that was
+ // the old behavior.
+ uint32_t bp_site_id = stop_info_sp->GetValue();
+ BreakpointSiteSP bp_site_sp(
+ m_thread.GetProcess()->GetBreakpointSiteList().FindByID(
+ bp_site_id));
+ bool all_internal = true;
+ if (bp_site_sp) {
+ uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (uint32_t i = 0; i < num_owners; i++) {
+ Breakpoint &bp_ref =
+ bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
+ if (!bp_ref.IsInternal()) {
+ all_internal = false;
+ }
+ }
+ }
+ if (!all_internal) {
+ m_current_inlined_pc = curr_pc;
+ m_current_inlined_depth = 0;
+ break;
+ }
+ }
+ LLVM_FALLTHROUGH;
+ default: {
+ // Otherwise, we should set ourselves at the container of the
+ // inlining, so that the
+ // user can descend into them.
+ // So first we check whether we have more than one inlined block
+ // sharing this PC:
+ int num_inlined_functions = 0;
+
+ for (Block *container_ptr = block_ptr->GetInlinedParent();
+ container_ptr != nullptr;
+ container_ptr = container_ptr->GetInlinedParent()) {
+ if (!container_ptr->GetRangeContainingAddress(
+ pc_as_address, containing_range))
+ break;
+ if (pc_as_address != containing_range.GetBaseAddress())
+ break;
-void
-StackFrameList::CalculateCurrentInlinedDepth()
-{
- uint32_t cur_inlined_depth = GetCurrentInlinedDepth();
- if (cur_inlined_depth == UINT32_MAX)
- {
- ResetCurrentInlinedDepth();
- }
-}
+ num_inlined_functions++;
+ }
+ m_current_inlined_pc = curr_pc;
+ m_current_inlined_depth = num_inlined_functions + 1;
+ Log *log(
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_STEP));
+ if (log && log->GetVerbose())
+ log->Printf("ResetCurrentInlinedDepth: setting inlined "
+ "depth: %d 0x%" PRIx64 ".\n",
+ m_current_inlined_depth, curr_pc);
-uint32_t
-StackFrameList::GetCurrentInlinedDepth ()
-{
- if (m_show_inlined_frames && m_current_inlined_pc != LLDB_INVALID_ADDRESS)
- {
- lldb::addr_t cur_pc = m_thread.GetRegisterContext()->GetPC();
- if (cur_pc != m_current_inlined_pc)
- {
- m_current_inlined_pc = LLDB_INVALID_ADDRESS;
- m_current_inlined_depth = UINT32_MAX;
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (log && log->GetVerbose())
- log->Printf ("GetCurrentInlinedDepth: invalidating current inlined depth.\n");
+ } break;
+ }
+ }
+ }
}
- return m_current_inlined_depth;
- }
- else
- {
- return UINT32_MAX;
+ }
}
+ }
}
-void
-StackFrameList::ResetCurrentInlinedDepth ()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
-
- if (m_show_inlined_frames)
- {
- GetFramesUpTo(0);
- if (m_frames.empty())
- return;
- if (!m_frames[0]->IsInlined())
- {
- m_current_inlined_depth = UINT32_MAX;
- m_current_inlined_pc = LLDB_INVALID_ADDRESS;
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (log && log->GetVerbose())
- log->Printf ("ResetCurrentInlinedDepth: Invalidating current inlined depth.\n");
- }
- else
- {
- // We only need to do something special about inlined blocks when we
- // are at the beginning of an inlined function:
- // FIXME: We probably also have to do something special if the PC is at the END
- // of an inlined function, which coincides with the end of either its containing
- // function or another inlined function.
-
- lldb::addr_t curr_pc = m_thread.GetRegisterContext()->GetPC();
- Block *block_ptr = m_frames[0]->GetFrameBlock();
- if (block_ptr)
- {
- Address pc_as_address;
- pc_as_address.SetLoadAddress(curr_pc, &(m_thread.GetProcess()->GetTarget()));
- AddressRange containing_range;
- if (block_ptr->GetRangeContainingAddress(pc_as_address, containing_range))
- {
- if (pc_as_address == containing_range.GetBaseAddress())
- {
- // If we got here because of a breakpoint hit, then set the inlined depth depending on where
- // the breakpoint was set.
- // If we got here because of a crash, then set the inlined depth to the deepest most block.
- // Otherwise, we stopped here naturally as the result of a step, so set ourselves in the
- // containing frame of the whole set of nested inlines, so the user can then "virtually"
- // step into the frames one by one, or next over the whole mess.
- // Note: We don't have to handle being somewhere in the middle of the stack here, since
- // ResetCurrentInlinedDepth doesn't get called if there is a valid inlined depth set.
- StopInfoSP stop_info_sp = m_thread.GetStopInfo();
- if (stop_info_sp)
- {
- switch (stop_info_sp->GetStopReason())
- {
- case eStopReasonWatchpoint:
- case eStopReasonException:
- case eStopReasonExec:
- case eStopReasonSignal:
- // In all these cases we want to stop in the deepest most frame.
- m_current_inlined_pc = curr_pc;
- m_current_inlined_depth = 0;
- break;
- case eStopReasonBreakpoint:
- {
- // FIXME: Figure out what this break point is doing, and set the inline depth
- // appropriately. Be careful to take into account breakpoints that implement
- // step over prologue, since that should do the default calculation.
- // For now, if the breakpoints corresponding to this hit are all internal,
- // I set the stop location to the top of the inlined stack, since that will make
- // things like stepping over prologues work right. But if there are any non-internal
- // breakpoints I do to the bottom of the stack, since that was the old behavior.
- uint32_t bp_site_id = stop_info_sp->GetValue();
- BreakpointSiteSP bp_site_sp(m_thread.GetProcess()->GetBreakpointSiteList().FindByID(bp_site_id));
- bool all_internal = true;
- if (bp_site_sp)
- {
- uint32_t num_owners = bp_site_sp->GetNumberOfOwners();
- for (uint32_t i = 0; i < num_owners; i++)
- {
- Breakpoint &bp_ref = bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
- if (!bp_ref.IsInternal())
- {
- all_internal = false;
- }
- }
- }
- if (!all_internal)
- {
- m_current_inlined_pc = curr_pc;
- m_current_inlined_depth = 0;
- break;
- }
- }
- LLVM_FALLTHROUGH;
- default:
- {
- // Otherwise, we should set ourselves at the container of the inlining, so that the
- // user can descend into them.
- // So first we check whether we have more than one inlined block sharing this PC:
- int num_inlined_functions = 0;
-
- for (Block *container_ptr = block_ptr->GetInlinedParent();
- container_ptr != nullptr;
- container_ptr = container_ptr->GetInlinedParent())
- {
- if (!container_ptr->GetRangeContainingAddress(pc_as_address, containing_range))
- break;
- if (pc_as_address != containing_range.GetBaseAddress())
- break;
-
- num_inlined_functions++;
- }
- m_current_inlined_pc = curr_pc;
- m_current_inlined_depth = num_inlined_functions + 1;
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_STEP));
- if (log && log->GetVerbose())
- log->Printf ("ResetCurrentInlinedDepth: setting inlined depth: %d 0x%" PRIx64 ".\n", m_current_inlined_depth, curr_pc);
-
- }
- break;
- }
- }
- }
- }
- }
- }
+bool StackFrameList::DecrementCurrentInlinedDepth() {
+ if (m_show_inlined_frames) {
+ uint32_t current_inlined_depth = GetCurrentInlinedDepth();
+ if (current_inlined_depth != UINT32_MAX) {
+ if (current_inlined_depth > 0) {
+ m_current_inlined_depth--;
+ return true;
+ }
}
+ }
+ return false;
}
-bool
-StackFrameList::DecrementCurrentInlinedDepth ()
-{
- if (m_show_inlined_frames)
- {
- uint32_t current_inlined_depth = GetCurrentInlinedDepth();
- if (current_inlined_depth != UINT32_MAX)
- {
- if (current_inlined_depth > 0)
- {
- m_current_inlined_depth--;
- return true;
- }
- }
- }
- return false;
+void StackFrameList::SetCurrentInlinedDepth(uint32_t new_depth) {
+ m_current_inlined_depth = new_depth;
+ if (new_depth == UINT32_MAX)
+ m_current_inlined_pc = LLDB_INVALID_ADDRESS;
+ else
+ m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();
}
-void
-StackFrameList::SetCurrentInlinedDepth (uint32_t new_depth)
-{
- m_current_inlined_depth = new_depth;
- if (new_depth == UINT32_MAX)
- m_current_inlined_pc = LLDB_INVALID_ADDRESS;
- else
- m_current_inlined_pc = m_thread.GetRegisterContext()->GetPC();
-}
-
-void
-StackFrameList::GetFramesUpTo(uint32_t end_idx)
-{
- // this makes sure we do not fetch frames for an invalid thread
- if (!m_thread.IsValid())
- return;
-
- // We've already gotten more frames than asked for, or we've already finished unwinding, return.
- if (m_frames.size() > end_idx || GetAllFramesFetched())
- return;
-
- Unwind *unwinder = m_thread.GetUnwinder ();
-
- if (m_show_inlined_frames)
- {
-#if defined (DEBUG_STACK_FRAMES)
- StreamFile s(stdout, false);
-#endif
- // If we are hiding some frames from the outside world, we need to add those onto the total count of
- // frames to fetch. However, we don't need to do that if end_idx is 0 since in that case we always
- // get the first concrete frame and all the inlined frames below it... And of course, if end_idx is
- // UINT32_MAX that means get all, so just do that...
-
- uint32_t inlined_depth = 0;
- if (end_idx > 0 && end_idx != UINT32_MAX)
- {
- inlined_depth = GetCurrentInlinedDepth();
- if (inlined_depth != UINT32_MAX)
- {
- if (end_idx > 0)
- end_idx += inlined_depth;
- }
- }
-
- StackFrameSP unwind_frame_sp;
- do
- {
- uint32_t idx = m_concrete_frames_fetched++;
- lldb::addr_t pc = LLDB_INVALID_ADDRESS;
- lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
- if (idx == 0)
- {
- // We might have already created frame zero, only create it
- // if we need to
- if (m_frames.empty())
- {
- RegisterContextSP reg_ctx_sp (m_thread.GetRegisterContext());
-
- if (reg_ctx_sp)
- {
- const bool success = unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
- // There shouldn't be any way not to get the frame info for frame 0.
- // But if the unwinder can't make one, lets make one by hand with the
- // SP as the CFA and see if that gets any further.
- if (!success)
- {
- cfa = reg_ctx_sp->GetSP();
- pc = reg_ctx_sp->GetPC();
- }
-
- unwind_frame_sp.reset(new StackFrame(m_thread.shared_from_this(),
- m_frames.size(),
- idx,
- reg_ctx_sp,
- cfa,
- pc,
- nullptr));
- m_frames.push_back (unwind_frame_sp);
- }
- }
- else
- {
- unwind_frame_sp = m_frames.front();
- cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
- }
- }
- else
- {
- const bool success = unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
- if (!success)
- {
- // We've gotten to the end of the stack.
- SetAllFramesFetched();
- break;
- }
- const bool cfa_is_valid = true;
- const bool stop_id_is_valid = false;
- const bool is_history_frame = false;
- unwind_frame_sp.reset(new StackFrame(m_thread.shared_from_this(), m_frames.size(), idx, cfa, cfa_is_valid, pc,
- 0, stop_id_is_valid, is_history_frame, nullptr));
- m_frames.push_back (unwind_frame_sp);
- }
-
- assert(unwind_frame_sp);
- SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext (eSymbolContextBlock | eSymbolContextFunction);
- Block *unwind_block = unwind_sc.block;
- if (unwind_block)
- {
- Address curr_frame_address (unwind_frame_sp->GetFrameCodeAddress());
- TargetSP target_sp = m_thread.CalculateTarget();
- // Be sure to adjust the frame address to match the address
- // that was used to lookup the symbol context above. If we are
- // in the first concrete frame, then we lookup using the current
- // address, else we decrement the address by one to get the correct
- // location.
- if (idx > 0)
- {
- if (curr_frame_address.GetOffset() == 0)
- {
- // If curr_frame_address points to the first address in a section then after
- // adjustment it will point to an other section. In that case resolve the
- // address again to the correct section plus offset form.
- addr_t load_addr = curr_frame_address.GetOpcodeLoadAddress(target_sp.get(), eAddressClassCode);
- curr_frame_address.SetOpcodeLoadAddress(load_addr - 1, target_sp.get(), eAddressClassCode);
- }
- else
- {
- curr_frame_address.Slide(-1);
- }
- }
-
- SymbolContext next_frame_sc;
- Address next_frame_address;
-
- while (unwind_sc.GetParentOfInlinedScope(curr_frame_address, next_frame_sc, next_frame_address))
- {
- next_frame_sc.line_entry.ApplyFileMappings(target_sp);
- StackFrameSP frame_sp(new StackFrame(m_thread.shared_from_this(),
- m_frames.size(),
- idx,
- unwind_frame_sp->GetRegisterContextSP (),
- cfa,
- next_frame_address,
- &next_frame_sc));
-
- m_frames.push_back (frame_sp);
- unwind_sc = next_frame_sc;
- curr_frame_address = next_frame_address;
- }
- }
- } while (m_frames.size() - 1 < end_idx);
+void StackFrameList::GetFramesUpTo(uint32_t end_idx) {
+ // this makes sure we do not fetch frames for an invalid thread
+ if (!m_thread.IsValid())
+ return;
- // Don't try to merge till you've calculated all the frames in this stack.
- if (GetAllFramesFetched() && m_prev_frames_sp)
- {
- StackFrameList *prev_frames = m_prev_frames_sp.get();
- StackFrameList *curr_frames = this;
-
- //curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth;
- //curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc;
- //printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n", curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc);
-
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("\nprev_frames:\n");
- prev_frames->Dump (&s);
- s.PutCString("\ncurr_frames:\n");
- curr_frames->Dump (&s);
- s.EOL();
-#endif
- size_t curr_frame_num, prev_frame_num;
-
- for (curr_frame_num = curr_frames->m_frames.size(), prev_frame_num = prev_frames->m_frames.size();
- curr_frame_num > 0 && prev_frame_num > 0;
- --curr_frame_num, --prev_frame_num)
- {
- const size_t curr_frame_idx = curr_frame_num-1;
- const size_t prev_frame_idx = prev_frame_num-1;
- StackFrameSP curr_frame_sp (curr_frames->m_frames[curr_frame_idx]);
- StackFrameSP prev_frame_sp (prev_frames->m_frames[prev_frame_idx]);
-
-#if defined (DEBUG_STACK_FRAMES)
- s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
- if (curr_frame_sp)
- curr_frame_sp->Dump (&s, true, false);
- else
- s.PutCString("NULL");
- s.Printf("\nPrev frame #%u ", prev_frame_idx);
- if (prev_frame_sp)
- prev_frame_sp->Dump (&s, true, false);
- else
- s.PutCString("NULL");
-#endif
-
- StackFrame *curr_frame = curr_frame_sp.get();
- StackFrame *prev_frame = prev_frame_sp.get();
-
- if (curr_frame == nullptr || prev_frame == nullptr)
- break;
+ // We've already gotten more frames than asked for, or we've already finished
+ // unwinding, return.
+ if (m_frames.size() > end_idx || GetAllFramesFetched())
+ return;
- // Check the stack ID to make sure they are equal
- if (curr_frame->GetStackID() != prev_frame->GetStackID())
- break;
+ Unwind *unwinder = m_thread.GetUnwinder();
- prev_frame->UpdatePreviousFrameFromCurrentFrame (*curr_frame);
- // Now copy the fixed up previous frame into the current frames
- // so the pointer doesn't change
- m_frames[curr_frame_idx] = prev_frame_sp;
- //curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
-
-#if defined (DEBUG_STACK_FRAMES)
- s.Printf("\n Copying previous frame to current frame");
+ if (m_show_inlined_frames) {
+#if defined(DEBUG_STACK_FRAMES)
+ StreamFile s(stdout, false);
#endif
+ // If we are hiding some frames from the outside world, we need to add those
+ // onto the total count of
+ // frames to fetch. However, we don't need to do that if end_idx is 0 since
+ // in that case we always
+ // get the first concrete frame and all the inlined frames below it... And
+ // of course, if end_idx is
+ // UINT32_MAX that means get all, so just do that...
+
+ uint32_t inlined_depth = 0;
+ if (end_idx > 0 && end_idx != UINT32_MAX) {
+ inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX) {
+ if (end_idx > 0)
+ end_idx += inlined_depth;
+ }
+ }
+
+ StackFrameSP unwind_frame_sp;
+ do {
+ uint32_t idx = m_concrete_frames_fetched++;
+ lldb::addr_t pc = LLDB_INVALID_ADDRESS;
+ lldb::addr_t cfa = LLDB_INVALID_ADDRESS;
+ if (idx == 0) {
+ // We might have already created frame zero, only create it
+ // if we need to
+ if (m_frames.empty()) {
+ RegisterContextSP reg_ctx_sp(m_thread.GetRegisterContext());
+
+ if (reg_ctx_sp) {
+ const bool success =
+ unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
+ // There shouldn't be any way not to get the frame info for frame 0.
+ // But if the unwinder can't make one, lets make one by hand with
+ // the
+ // SP as the CFA and see if that gets any further.
+ if (!success) {
+ cfa = reg_ctx_sp->GetSP();
+ pc = reg_ctx_sp->GetPC();
}
- // We are done with the old stack frame list, we can release it now
- m_prev_frames_sp.reset();
- }
-
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("\n\nNew frames:\n");
- Dump (&s);
- s.EOL();
-#endif
- }
- else
- {
- if (end_idx < m_concrete_frames_fetched)
- return;
-
- if (unwinder)
- {
- uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
- if (num_frames <= end_idx + 1)
- {
- //Done unwinding.
- m_concrete_frames_fetched = UINT32_MAX;
- }
- m_frames.resize(num_frames);
- }
- }
-}
-uint32_t
-StackFrameList::GetNumFrames (bool can_create)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ unwind_frame_sp.reset(new StackFrame(m_thread.shared_from_this(),
+ m_frames.size(), idx,
+ reg_ctx_sp, cfa, pc, nullptr));
+ m_frames.push_back(unwind_frame_sp);
+ }
+ } else {
+ unwind_frame_sp = m_frames.front();
+ cfa = unwind_frame_sp->m_id.GetCallFrameAddress();
+ }
+ } else {
+ const bool success =
+ unwinder && unwinder->GetFrameInfoAtIndex(idx, cfa, pc);
+ if (!success) {
+ // We've gotten to the end of the stack.
+ SetAllFramesFetched();
+ break;
+ }
+ const bool cfa_is_valid = true;
+ const bool stop_id_is_valid = false;
+ const bool is_history_frame = false;
+ unwind_frame_sp.reset(new StackFrame(
+ m_thread.shared_from_this(), m_frames.size(), idx, cfa,
+ cfa_is_valid, pc, 0, stop_id_is_valid, is_history_frame, nullptr));
+ m_frames.push_back(unwind_frame_sp);
+ }
+
+ assert(unwind_frame_sp);
+ SymbolContext unwind_sc = unwind_frame_sp->GetSymbolContext(
+ eSymbolContextBlock | eSymbolContextFunction);
+ Block *unwind_block = unwind_sc.block;
+ if (unwind_block) {
+ Address curr_frame_address(unwind_frame_sp->GetFrameCodeAddress());
+ TargetSP target_sp = m_thread.CalculateTarget();
+ // Be sure to adjust the frame address to match the address
+ // that was used to lookup the symbol context above. If we are
+ // in the first concrete frame, then we lookup using the current
+ // address, else we decrement the address by one to get the correct
+ // location.
+ if (idx > 0) {
+ if (curr_frame_address.GetOffset() == 0) {
+ // If curr_frame_address points to the first address in a section
+ // then after
+ // adjustment it will point to an other section. In that case
+ // resolve the
+ // address again to the correct section plus offset form.
+ addr_t load_addr = curr_frame_address.GetOpcodeLoadAddress(
+ target_sp.get(), eAddressClassCode);
+ curr_frame_address.SetOpcodeLoadAddress(
+ load_addr - 1, target_sp.get(), eAddressClassCode);
+ } else {
+ curr_frame_address.Slide(-1);
+ }
+ }
+
+ SymbolContext next_frame_sc;
+ Address next_frame_address;
+
+ while (unwind_sc.GetParentOfInlinedScope(
+ curr_frame_address, next_frame_sc, next_frame_address)) {
+ next_frame_sc.line_entry.ApplyFileMappings(target_sp);
+ StackFrameSP frame_sp(
+ new StackFrame(m_thread.shared_from_this(), m_frames.size(), idx,
+ unwind_frame_sp->GetRegisterContextSP(), cfa,
+ next_frame_address, &next_frame_sc));
+
+ m_frames.push_back(frame_sp);
+ unwind_sc = next_frame_sc;
+ curr_frame_address = next_frame_address;
+ }
+ }
+ } while (m_frames.size() - 1 < end_idx);
+
+ // Don't try to merge till you've calculated all the frames in this stack.
+ if (GetAllFramesFetched() && m_prev_frames_sp) {
+ StackFrameList *prev_frames = m_prev_frames_sp.get();
+ StackFrameList *curr_frames = this;
+
+// curr_frames->m_current_inlined_depth = prev_frames->m_current_inlined_depth;
+// curr_frames->m_current_inlined_pc = prev_frames->m_current_inlined_pc;
+// printf ("GetFramesUpTo: Copying current inlined depth: %d 0x%" PRIx64 ".\n",
+// curr_frames->m_current_inlined_depth, curr_frames->m_current_inlined_pc);
+
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString("\nprev_frames:\n");
+ prev_frames->Dump(&s);
+ s.PutCString("\ncurr_frames:\n");
+ curr_frames->Dump(&s);
+ s.EOL();
+#endif
+ size_t curr_frame_num, prev_frame_num;
+
+ for (curr_frame_num = curr_frames->m_frames.size(),
+ prev_frame_num = prev_frames->m_frames.size();
+ curr_frame_num > 0 && prev_frame_num > 0;
+ --curr_frame_num, --prev_frame_num) {
+ const size_t curr_frame_idx = curr_frame_num - 1;
+ const size_t prev_frame_idx = prev_frame_num - 1;
+ StackFrameSP curr_frame_sp(curr_frames->m_frames[curr_frame_idx]);
+ StackFrameSP prev_frame_sp(prev_frames->m_frames[prev_frame_idx]);
+
+#if defined(DEBUG_STACK_FRAMES)
+ s.Printf("\n\nCurr frame #%u ", curr_frame_idx);
+ if (curr_frame_sp)
+ curr_frame_sp->Dump(&s, true, false);
+ else
+ s.PutCString("NULL");
+ s.Printf("\nPrev frame #%u ", prev_frame_idx);
+ if (prev_frame_sp)
+ prev_frame_sp->Dump(&s, true, false);
+ else
+ s.PutCString("NULL");
+#endif
- if (can_create)
- GetFramesUpTo (UINT32_MAX);
+ StackFrame *curr_frame = curr_frame_sp.get();
+ StackFrame *prev_frame = prev_frame_sp.get();
- uint32_t inlined_depth = GetCurrentInlinedDepth();
- if (inlined_depth == UINT32_MAX)
- return m_frames.size();
- else
- return m_frames.size() - inlined_depth;
-}
+ if (curr_frame == nullptr || prev_frame == nullptr)
+ break;
-void
-StackFrameList::Dump (Stream *s)
-{
- if (s == nullptr)
- return;
+ // Check the stack ID to make sure they are equal
+ if (curr_frame->GetStackID() != prev_frame->GetStackID())
+ break;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ prev_frame->UpdatePreviousFrameFromCurrentFrame(*curr_frame);
+ // Now copy the fixed up previous frame into the current frames
+ // so the pointer doesn't change
+ m_frames[curr_frame_idx] = prev_frame_sp;
+// curr_frame->UpdateCurrentFrameFromPreviousFrame (*prev_frame);
- const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
- for (pos = begin; pos != end; ++pos)
- {
- StackFrame *frame = (*pos).get();
- s->Printf("%p: ", static_cast<void*>(frame));
- if (frame)
- {
- frame->GetStackID().Dump (s);
- frame->DumpUsingSettingsFormat (s);
- }
- else
- s->Printf("frame #%u", (uint32_t)std::distance (begin, pos));
- s->EOL();
+#if defined(DEBUG_STACK_FRAMES)
+ s.Printf("\n Copying previous frame to current frame");
+#endif
+ }
+ // We are done with the old stack frame list, we can release it now
+ m_prev_frames_sp.reset();
}
+
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString("\n\nNew frames:\n");
+ Dump(&s);
+ s.EOL();
+#endif
+ } else {
+ if (end_idx < m_concrete_frames_fetched)
+ return;
+
+ if (unwinder) {
+ uint32_t num_frames = unwinder->GetFramesUpTo(end_idx);
+ if (num_frames <= end_idx + 1) {
+ // Done unwinding.
+ m_concrete_frames_fetched = UINT32_MAX;
+ }
+ m_frames.resize(num_frames);
+ }
+ }
+}
+
+uint32_t StackFrameList::GetNumFrames(bool can_create) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ if (can_create)
+ GetFramesUpTo(UINT32_MAX);
+
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth == UINT32_MAX)
+ return m_frames.size();
+ else
+ return m_frames.size() - inlined_depth;
+}
+
+void StackFrameList::Dump(Stream *s) {
+ if (s == nullptr)
+ return;
+
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+
+ const_iterator pos, begin = m_frames.begin(), end = m_frames.end();
+ for (pos = begin; pos != end; ++pos) {
+ StackFrame *frame = (*pos).get();
+ s->Printf("%p: ", static_cast<void *>(frame));
+ if (frame) {
+ frame->GetStackID().Dump(s);
+ frame->DumpUsingSettingsFormat(s);
+ } else
+ s->Printf("frame #%u", (uint32_t)std::distance(begin, pos));
s->EOL();
+ }
+ s->EOL();
}
-StackFrameSP
-StackFrameList::GetFrameAtIndex (uint32_t idx)
-{
- StackFrameSP frame_sp;
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- uint32_t original_idx = idx;
-
- uint32_t inlined_depth = GetCurrentInlinedDepth();
- if (inlined_depth != UINT32_MAX)
- idx += inlined_depth;
-
- if (idx < m_frames.size())
- frame_sp = m_frames[idx];
-
- if (frame_sp)
- return frame_sp;
-
- // GetFramesUpTo will fill m_frames with as many frames as you asked for,
- // if there are that many. If there weren't then you asked for too many
- // frames.
- GetFramesUpTo (idx);
- if (idx < m_frames.size())
- {
- if (m_show_inlined_frames)
- {
- // When inline frames are enabled we actually create all the frames in GetFramesUpTo.
- frame_sp = m_frames[idx];
- }
- else
- {
- Unwind *unwinder = m_thread.GetUnwinder ();
- if (unwinder)
- {
- addr_t pc, cfa;
- if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc))
- {
- const bool cfa_is_valid = true;
- const bool stop_id_is_valid = false;
- const bool is_history_frame = false;
- frame_sp.reset(new StackFrame(m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 0,
- stop_id_is_valid, is_history_frame, nullptr));
-
- Function *function = frame_sp->GetSymbolContext (eSymbolContextFunction).function;
- if (function)
- {
- // When we aren't showing inline functions we always use
- // the top most function block as the scope.
- frame_sp->SetSymbolContextScope (&function->GetBlock(false));
- }
- else
- {
- // Set the symbol scope from the symbol regardless if it is nullptr or valid.
- frame_sp->SetSymbolContextScope (frame_sp->GetSymbolContext (eSymbolContextSymbol).symbol);
- }
- SetFrameAtIndex(idx, frame_sp);
- }
- }
- }
- }
- else if (original_idx == 0)
- {
- // There should ALWAYS be a frame at index 0. If something went wrong with the CurrentInlinedDepth such that
- // there weren't as many frames as we thought taking that into account, then reset the current inlined depth
- // and return the real zeroth frame.
- if (m_frames.empty())
- {
- // Why do we have a thread with zero frames, that should not ever happen...
- if (m_thread.IsValid())
- assert ("A valid thread has no frames.");
- }
- else
- {
- ResetCurrentInlinedDepth();
- frame_sp = m_frames[original_idx];
- }
- }
-
- return frame_sp;
-}
+StackFrameSP StackFrameList::GetFrameAtIndex(uint32_t idx) {
+ StackFrameSP frame_sp;
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ uint32_t original_idx = idx;
-StackFrameSP
-StackFrameList::GetFrameWithConcreteFrameIndex (uint32_t unwind_idx)
-{
- // First try assuming the unwind index is the same as the frame index. The
- // unwind index is always greater than or equal to the frame index, so it
- // is a good place to start. If we have inlined frames we might have 5
- // concrete frames (frame unwind indexes go from 0-4), but we might have 15
- // frames after we make all the inlined frames. Most of the time the unwind
- // frame index (or the concrete frame index) is the same as the frame index.
- uint32_t frame_idx = unwind_idx;
- StackFrameSP frame_sp (GetFrameAtIndex (frame_idx));
- while (frame_sp)
- {
- if (frame_sp->GetFrameIndex() == unwind_idx)
- break;
- frame_sp = GetFrameAtIndex (++frame_idx);
- }
- return frame_sp;
-}
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX)
+ idx += inlined_depth;
-static bool
-CompareStackID (const StackFrameSP &stack_sp, const StackID &stack_id)
-{
- return stack_sp->GetStackID() < stack_id;
-}
+ if (idx < m_frames.size())
+ frame_sp = m_frames[idx];
-StackFrameSP
-StackFrameList::GetFrameWithStackID (const StackID &stack_id)
-{
- StackFrameSP frame_sp;
-
- if (stack_id.IsValid())
- {
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- uint32_t frame_idx = 0;
- // Do a binary search in case the stack frame is already in our cache
- collection::const_iterator begin = m_frames.begin();
- collection::const_iterator end = m_frames.end();
- if (begin != end)
- {
- collection::const_iterator pos = std::lower_bound (begin, end, stack_id, CompareStackID);
- if (pos != end)
- {
- if ((*pos)->GetStackID() == stack_id)
- return *pos;
- }
-
-// if (m_frames.back()->GetStackID() < stack_id)
-// frame_idx = m_frames.size();
- }
- do
- {
- frame_sp = GetFrameAtIndex (frame_idx);
- if (frame_sp && frame_sp->GetStackID() == stack_id)
- break;
- frame_idx++;
- }
- while (frame_sp);
- }
+ if (frame_sp)
return frame_sp;
-}
-bool
-StackFrameList::SetFrameAtIndex (uint32_t idx, StackFrameSP &frame_sp)
-{
- if (idx >= m_frames.size())
- m_frames.resize(idx + 1);
- // Make sure allocation succeeded by checking bounds again
- if (idx < m_frames.size())
- {
- m_frames[idx] = frame_sp;
- return true;
+ // GetFramesUpTo will fill m_frames with as many frames as you asked for,
+ // if there are that many. If there weren't then you asked for too many
+ // frames.
+ GetFramesUpTo(idx);
+ if (idx < m_frames.size()) {
+ if (m_show_inlined_frames) {
+ // When inline frames are enabled we actually create all the frames in
+ // GetFramesUpTo.
+ frame_sp = m_frames[idx];
+ } else {
+ Unwind *unwinder = m_thread.GetUnwinder();
+ if (unwinder) {
+ addr_t pc, cfa;
+ if (unwinder->GetFrameInfoAtIndex(idx, cfa, pc)) {
+ const bool cfa_is_valid = true;
+ const bool stop_id_is_valid = false;
+ const bool is_history_frame = false;
+ frame_sp.reset(new StackFrame(
+ m_thread.shared_from_this(), idx, idx, cfa, cfa_is_valid, pc, 0,
+ stop_id_is_valid, is_history_frame, nullptr));
+
+ Function *function =
+ frame_sp->GetSymbolContext(eSymbolContextFunction).function;
+ if (function) {
+ // When we aren't showing inline functions we always use
+ // the top most function block as the scope.
+ frame_sp->SetSymbolContextScope(&function->GetBlock(false));
+ } else {
+ // Set the symbol scope from the symbol regardless if it is nullptr
+ // or valid.
+ frame_sp->SetSymbolContextScope(
+ frame_sp->GetSymbolContext(eSymbolContextSymbol).symbol);
+ }
+ SetFrameAtIndex(idx, frame_sp);
+ }
+ }
+ }
+ } else if (original_idx == 0) {
+ // There should ALWAYS be a frame at index 0. If something went wrong with
+ // the CurrentInlinedDepth such that
+ // there weren't as many frames as we thought taking that into account, then
+ // reset the current inlined depth
+ // and return the real zeroth frame.
+ if (m_frames.empty()) {
+ // Why do we have a thread with zero frames, that should not ever
+ // happen...
+ if (m_thread.IsValid())
+ assert("A valid thread has no frames.");
+ } else {
+ ResetCurrentInlinedDepth();
+ frame_sp = m_frames[original_idx];
}
- return false; // resize failed, out of memory?
+ }
+
+ return frame_sp;
}
-uint32_t
-StackFrameList::GetSelectedFrameIndex () const
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- return m_selected_frame_idx;
+StackFrameSP
+StackFrameList::GetFrameWithConcreteFrameIndex(uint32_t unwind_idx) {
+ // First try assuming the unwind index is the same as the frame index. The
+ // unwind index is always greater than or equal to the frame index, so it
+ // is a good place to start. If we have inlined frames we might have 5
+ // concrete frames (frame unwind indexes go from 0-4), but we might have 15
+ // frames after we make all the inlined frames. Most of the time the unwind
+ // frame index (or the concrete frame index) is the same as the frame index.
+ uint32_t frame_idx = unwind_idx;
+ StackFrameSP frame_sp(GetFrameAtIndex(frame_idx));
+ while (frame_sp) {
+ if (frame_sp->GetFrameIndex() == unwind_idx)
+ break;
+ frame_sp = GetFrameAtIndex(++frame_idx);
+ }
+ return frame_sp;
+}
+
+static bool CompareStackID(const StackFrameSP &stack_sp,
+ const StackID &stack_id) {
+ return stack_sp->GetStackID() < stack_id;
}
-uint32_t
-StackFrameList::SetSelectedFrame (lldb_private::StackFrame *frame)
-{
+StackFrameSP StackFrameList::GetFrameWithStackID(const StackID &stack_id) {
+ StackFrameSP frame_sp;
+
+ if (stack_id.IsValid()) {
std::lock_guard<std::recursive_mutex> guard(m_mutex);
- const_iterator pos;
- const_iterator begin = m_frames.begin();
- const_iterator end = m_frames.end();
- m_selected_frame_idx = 0;
- for (pos = begin; pos != end; ++pos)
- {
- if (pos->get() == frame)
- {
- m_selected_frame_idx = std::distance (begin, pos);
- uint32_t inlined_depth = GetCurrentInlinedDepth();
- if (inlined_depth != UINT32_MAX)
- m_selected_frame_idx -= inlined_depth;
- break;
- }
- }
- SetDefaultFileAndLineToSelectedFrame();
- return m_selected_frame_idx;
+ uint32_t frame_idx = 0;
+ // Do a binary search in case the stack frame is already in our cache
+ collection::const_iterator begin = m_frames.begin();
+ collection::const_iterator end = m_frames.end();
+ if (begin != end) {
+ collection::const_iterator pos =
+ std::lower_bound(begin, end, stack_id, CompareStackID);
+ if (pos != end) {
+ if ((*pos)->GetStackID() == stack_id)
+ return *pos;
+ }
+
+ // if (m_frames.back()->GetStackID() < stack_id)
+ // frame_idx = m_frames.size();
+ }
+ do {
+ frame_sp = GetFrameAtIndex(frame_idx);
+ if (frame_sp && frame_sp->GetStackID() == stack_id)
+ break;
+ frame_idx++;
+ } while (frame_sp);
+ }
+ return frame_sp;
+}
+
+bool StackFrameList::SetFrameAtIndex(uint32_t idx, StackFrameSP &frame_sp) {
+ if (idx >= m_frames.size())
+ m_frames.resize(idx + 1);
+ // Make sure allocation succeeded by checking bounds again
+ if (idx < m_frames.size()) {
+ m_frames[idx] = frame_sp;
+ return true;
+ }
+ return false; // resize failed, out of memory?
+}
+
+uint32_t StackFrameList::GetSelectedFrameIndex() const {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ return m_selected_frame_idx;
+}
+
+uint32_t StackFrameList::SetSelectedFrame(lldb_private::StackFrame *frame) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ const_iterator pos;
+ const_iterator begin = m_frames.begin();
+ const_iterator end = m_frames.end();
+ m_selected_frame_idx = 0;
+ for (pos = begin; pos != end; ++pos) {
+ if (pos->get() == frame) {
+ m_selected_frame_idx = std::distance(begin, pos);
+ uint32_t inlined_depth = GetCurrentInlinedDepth();
+ if (inlined_depth != UINT32_MAX)
+ m_selected_frame_idx -= inlined_depth;
+ break;
+ }
+ }
+ SetDefaultFileAndLineToSelectedFrame();
+ return m_selected_frame_idx;
}
// Mark a stack frame as the current frame using the frame index
-bool
-StackFrameList::SetSelectedFrameByIndex (uint32_t idx)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- StackFrameSP frame_sp (GetFrameAtIndex (idx));
- if (frame_sp)
- {
- SetSelectedFrame(frame_sp.get());
- return true;
- }
- else
- return false;
+bool StackFrameList::SetSelectedFrameByIndex(uint32_t idx) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ StackFrameSP frame_sp(GetFrameAtIndex(idx));
+ if (frame_sp) {
+ SetSelectedFrame(frame_sp.get());
+ return true;
+ } else
+ return false;
}
-void
-StackFrameList::SetDefaultFileAndLineToSelectedFrame()
-{
- if (m_thread.GetID() == m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID())
- {
- StackFrameSP frame_sp (GetFrameAtIndex (GetSelectedFrameIndex()));
- if (frame_sp)
- {
- SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
- if (sc.line_entry.file)
- m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine (sc.line_entry.file,
- sc.line_entry.line);
- }
+void StackFrameList::SetDefaultFileAndLineToSelectedFrame() {
+ if (m_thread.GetID() ==
+ m_thread.GetProcess()->GetThreadList().GetSelectedThread()->GetID()) {
+ StackFrameSP frame_sp(GetFrameAtIndex(GetSelectedFrameIndex()));
+ if (frame_sp) {
+ SymbolContext sc = frame_sp->GetSymbolContext(eSymbolContextLineEntry);
+ if (sc.line_entry.file)
+ m_thread.CalculateTarget()->GetSourceManager().SetDefaultFileAndLine(
+ sc.line_entry.file, sc.line_entry.line);
}
+ }
}
// The thread has been run, reset the number stack frames to zero so we can
// determine how many frames we have lazily.
-void
-StackFrameList::Clear ()
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- m_frames.clear();
- m_concrete_frames_fetched = 0;
+void StackFrameList::Clear() {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ m_frames.clear();
+ m_concrete_frames_fetched = 0;
}
-void
-StackFrameList::InvalidateFrames (uint32_t start_idx)
-{
- std::lock_guard<std::recursive_mutex> guard(m_mutex);
- if (m_show_inlined_frames)
- {
- Clear();
- }
- else
- {
- const size_t num_frames = m_frames.size();
- while (start_idx < num_frames)
- {
- m_frames[start_idx].reset();
- ++start_idx;
- }
- }
-}
-
-void
-StackFrameList::Merge (std::unique_ptr<StackFrameList>& curr_ap, lldb::StackFrameListSP& prev_sp)
-{
- std::unique_lock<std::recursive_mutex> current_lock, previous_lock;
- if (curr_ap)
- current_lock = std::unique_lock<std::recursive_mutex>(curr_ap->m_mutex);
- if (prev_sp)
- previous_lock = std::unique_lock<std::recursive_mutex>(prev_sp->m_mutex);
-
-#if defined (DEBUG_STACK_FRAMES)
- StreamFile s(stdout, false);
- s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n");
- if (prev_sp)
- prev_sp->Dump (&s);
- else
- s.PutCString ("NULL");
- s.PutCString("\nCurr:\n");
- if (curr_ap)
- curr_ap->Dump (&s);
- else
- s.PutCString ("NULL");
- s.EOL();
-#endif
-
- if (!curr_ap || curr_ap->GetNumFrames(false) == 0)
- {
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("No current frames, leave previous frames alone...\n");
-#endif
- curr_ap.release();
- return;
- }
-
- if (!prev_sp || prev_sp->GetNumFrames(false) == 0)
- {
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("No previous frames, so use current frames...\n");
-#endif
- // We either don't have any previous frames, or since we have more than
- // one current frames it means we have all the frames and can safely
- // replace our previous frames.
- prev_sp.reset (curr_ap.release());
- return;
- }
-
- const uint32_t num_curr_frames = curr_ap->GetNumFrames (false);
-
- if (num_curr_frames > 1)
- {
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("We have more than one current frame, so use current frames...\n");
-#endif
- // We have more than one current frames it means we have all the frames
- // and can safely replace our previous frames.
- prev_sp.reset (curr_ap.release());
-
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("\nMerged:\n");
- prev_sp->Dump (&s);
-#endif
- return;
- }
-
- StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex (0));
- StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex (0));
- StackID curr_stack_id (curr_frame_zero_sp->GetStackID());
- StackID prev_stack_id (prev_frame_zero_sp->GetStackID());
-
-#if defined (DEBUG_STACK_FRAMES)
- const uint32_t num_prev_frames = prev_sp->GetNumFrames (false);
- s.Printf("\n%u previous frames with one current frame\n", num_prev_frames);
+void StackFrameList::InvalidateFrames(uint32_t start_idx) {
+ std::lock_guard<std::recursive_mutex> guard(m_mutex);
+ if (m_show_inlined_frames) {
+ Clear();
+ } else {
+ const size_t num_frames = m_frames.size();
+ while (start_idx < num_frames) {
+ m_frames[start_idx].reset();
+ ++start_idx;
+ }
+ }
+}
+
+void StackFrameList::Merge(std::unique_ptr<StackFrameList> &curr_ap,
+ lldb::StackFrameListSP &prev_sp) {
+ std::unique_lock<std::recursive_mutex> current_lock, previous_lock;
+ if (curr_ap)
+ current_lock = std::unique_lock<std::recursive_mutex>(curr_ap->m_mutex);
+ if (prev_sp)
+ previous_lock = std::unique_lock<std::recursive_mutex>(prev_sp->m_mutex);
+
+#if defined(DEBUG_STACK_FRAMES)
+ StreamFile s(stdout, false);
+ s.PutCString("\n\nStackFrameList::Merge():\nPrev:\n");
+ if (prev_sp)
+ prev_sp->Dump(&s);
+ else
+ s.PutCString("NULL");
+ s.PutCString("\nCurr:\n");
+ if (curr_ap)
+ curr_ap->Dump(&s);
+ else
+ s.PutCString("NULL");
+ s.EOL();
+#endif
+
+ if (!curr_ap || curr_ap->GetNumFrames(false) == 0) {
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString("No current frames, leave previous frames alone...\n");
#endif
+ curr_ap.release();
+ return;
+ }
- // We have only a single current frame
- // Our previous stack frames only had a single frame as well...
- if (curr_stack_id == prev_stack_id)
- {
-#if defined (DEBUG_STACK_FRAMES)
- s.Printf("\nPrevious frame #0 is same as current frame #0, merge the cached data\n");
-#endif
+ if (!prev_sp || prev_sp->GetNumFrames(false) == 0) {
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString("No previous frames, so use current frames...\n");
+#endif
+ // We either don't have any previous frames, or since we have more than
+ // one current frames it means we have all the frames and can safely
+ // replace our previous frames.
+ prev_sp.reset(curr_ap.release());
+ return;
+ }
+
+ const uint32_t num_curr_frames = curr_ap->GetNumFrames(false);
+
+ if (num_curr_frames > 1) {
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString(
+ "We have more than one current frame, so use current frames...\n");
+#endif
+ // We have more than one current frames it means we have all the frames
+ // and can safely replace our previous frames.
+ prev_sp.reset(curr_ap.release());
- curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame (*prev_frame_zero_sp);
-// prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame (*curr_frame_zero_sp);
-// prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp);
- }
- else if (curr_stack_id < prev_stack_id)
- {
-#if defined (DEBUG_STACK_FRAMES)
- s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous frame #0, insert current frame zero in front of previous\n");
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString("\nMerged:\n");
+ prev_sp->Dump(&s);
#endif
- prev_sp->m_frames.insert (prev_sp->m_frames.begin(), curr_frame_zero_sp);
- }
-
- curr_ap.release();
+ return;
+ }
-#if defined (DEBUG_STACK_FRAMES)
- s.PutCString("\nMerged:\n");
- prev_sp->Dump (&s);
+ StackFrameSP prev_frame_zero_sp(prev_sp->GetFrameAtIndex(0));
+ StackFrameSP curr_frame_zero_sp(curr_ap->GetFrameAtIndex(0));
+ StackID curr_stack_id(curr_frame_zero_sp->GetStackID());
+ StackID prev_stack_id(prev_frame_zero_sp->GetStackID());
+
+#if defined(DEBUG_STACK_FRAMES)
+ const uint32_t num_prev_frames = prev_sp->GetNumFrames(false);
+ s.Printf("\n%u previous frames with one current frame\n", num_prev_frames);
+#endif
+
+ // We have only a single current frame
+ // Our previous stack frames only had a single frame as well...
+ if (curr_stack_id == prev_stack_id) {
+#if defined(DEBUG_STACK_FRAMES)
+ s.Printf("\nPrevious frame #0 is same as current frame #0, merge the "
+ "cached data\n");
+#endif
+
+ curr_frame_zero_sp->UpdateCurrentFrameFromPreviousFrame(
+ *prev_frame_zero_sp);
+ // prev_frame_zero_sp->UpdatePreviousFrameFromCurrentFrame
+ // (*curr_frame_zero_sp);
+ // prev_sp->SetFrameAtIndex (0, prev_frame_zero_sp);
+ } else if (curr_stack_id < prev_stack_id) {
+#if defined(DEBUG_STACK_FRAMES)
+ s.Printf("\nCurrent frame #0 has a stack ID that is less than the previous "
+ "frame #0, insert current frame zero in front of previous\n");
+#endif
+ prev_sp->m_frames.insert(prev_sp->m_frames.begin(), curr_frame_zero_sp);
+ }
+
+ curr_ap.release();
+
+#if defined(DEBUG_STACK_FRAMES)
+ s.PutCString("\nMerged:\n");
+ prev_sp->Dump(&s);
#endif
}
lldb::StackFrameSP
-StackFrameList::GetStackFrameSPForStackFramePtr (StackFrame *stack_frame_ptr)
-{
- const_iterator pos;
- const_iterator begin = m_frames.begin();
- const_iterator end = m_frames.end();
- lldb::StackFrameSP ret_sp;
-
- for (pos = begin; pos != end; ++pos)
- {
- if (pos->get() == stack_frame_ptr)
- {
- ret_sp = (*pos);
- break;
- }
- }
- return ret_sp;
-}
+StackFrameList::GetStackFrameSPForStackFramePtr(StackFrame *stack_frame_ptr) {
+ const_iterator pos;
+ const_iterator begin = m_frames.begin();
+ const_iterator end = m_frames.end();
+ lldb::StackFrameSP ret_sp;
+
+ for (pos = begin; pos != end; ++pos) {
+ if (pos->get() == stack_frame_ptr) {
+ ret_sp = (*pos);
+ break;
+ }
+ }
+ return ret_sp;
+}
+
+size_t StackFrameList::GetStatus(Stream &strm, uint32_t first_frame,
+ uint32_t num_frames, bool show_frame_info,
+ uint32_t num_frames_with_source,
+ const char *selected_frame_marker) {
+ size_t num_frames_displayed = 0;
+
+ if (num_frames == 0)
+ return 0;
+
+ StackFrameSP frame_sp;
+ uint32_t frame_idx = 0;
+ uint32_t last_frame;
+
+ // Don't let the last frame wrap around...
+ if (num_frames == UINT32_MAX)
+ last_frame = UINT32_MAX;
+ else
+ last_frame = first_frame + num_frames;
+
+ StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame();
+ const char *unselected_marker = nullptr;
+ std::string buffer;
+ if (selected_frame_marker) {
+ size_t len = strlen(selected_frame_marker);
+ buffer.insert(buffer.begin(), len, ' ');
+ unselected_marker = buffer.c_str();
+ }
+ const char *marker = nullptr;
+
+ for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx) {
+ frame_sp = GetFrameAtIndex(frame_idx);
+ if (!frame_sp)
+ break;
+
+ if (selected_frame_marker != nullptr) {
+ if (frame_sp == selected_frame_sp)
+ marker = selected_frame_marker;
+ else
+ marker = unselected_marker;
+ }
+
+ if (!frame_sp->GetStatus(strm, show_frame_info,
+ num_frames_with_source > (first_frame - frame_idx),
+ marker))
+ break;
+ ++num_frames_displayed;
+ }
-size_t
-StackFrameList::GetStatus (Stream& strm,
- uint32_t first_frame,
- uint32_t num_frames,
- bool show_frame_info,
- uint32_t num_frames_with_source,
- const char *selected_frame_marker)
-{
- size_t num_frames_displayed = 0;
-
- if (num_frames == 0)
- return 0;
-
- StackFrameSP frame_sp;
- uint32_t frame_idx = 0;
- uint32_t last_frame;
-
- // Don't let the last frame wrap around...
- if (num_frames == UINT32_MAX)
- last_frame = UINT32_MAX;
- else
- last_frame = first_frame + num_frames;
-
- StackFrameSP selected_frame_sp = m_thread.GetSelectedFrame();
- const char *unselected_marker = nullptr;
- std::string buffer;
- if (selected_frame_marker)
- {
- size_t len = strlen(selected_frame_marker);
- buffer.insert(buffer.begin(), len, ' ');
- unselected_marker = buffer.c_str();
- }
- const char *marker = nullptr;
-
- for (frame_idx = first_frame; frame_idx < last_frame; ++frame_idx)
- {
- frame_sp = GetFrameAtIndex(frame_idx);
- if (!frame_sp)
- break;
-
- if (selected_frame_marker != nullptr)
- {
- if (frame_sp == selected_frame_sp)
- marker = selected_frame_marker;
- else
- marker = unselected_marker;
- }
-
- if (!frame_sp->GetStatus (strm,
- show_frame_info,
- num_frames_with_source > (first_frame - frame_idx), marker))
- break;
- ++num_frames_displayed;
- }
-
- strm.IndentLess();
- return num_frames_displayed;
+ strm.IndentLess();
+ return num_frames_displayed;
}
Modified: lldb/trunk/source/Target/StackID.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StackID.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/StackID.cpp (original)
+++ lldb/trunk/source/Target/StackID.cpp Tue Sep 6 15:57:50 2016
@@ -19,91 +19,85 @@
using namespace lldb_private;
-void
-StackID::Dump (Stream *s)
-{
- s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64 ", symbol_scope = %p",
- m_pc, m_cfa, static_cast<void*>(m_symbol_scope));
- if (m_symbol_scope)
- {
- SymbolContext sc;
-
- m_symbol_scope->CalculateSymbolContext (&sc);
- if (sc.block)
- s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID());
- else if (sc.symbol)
- s->Printf(" (Symbol{0x%8.8x})", sc.symbol->GetID());
- }
- s->PutCString(") ");
+void StackID::Dump(Stream *s) {
+ s->Printf("StackID (pc = 0x%16.16" PRIx64 ", cfa = 0x%16.16" PRIx64
+ ", symbol_scope = %p",
+ m_pc, m_cfa, static_cast<void *>(m_symbol_scope));
+ if (m_symbol_scope) {
+ SymbolContext sc;
+
+ m_symbol_scope->CalculateSymbolContext(&sc);
+ if (sc.block)
+ s->Printf(" (Block {0x%8.8" PRIx64 "})", sc.block->GetID());
+ else if (sc.symbol)
+ s->Printf(" (Symbol{0x%8.8x})", sc.symbol->GetID());
+ }
+ s->PutCString(") ");
}
-bool
-lldb_private::operator== (const StackID& lhs, const StackID& rhs)
-{
- if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
- return false;
-
- SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
- SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
-
- // Only compare the PC values if both symbol context scopes are nullptr
- if (lhs_scope == nullptr && rhs_scope == nullptr)
- return lhs.GetPC() == rhs.GetPC();
-
- return lhs_scope == rhs_scope;
+bool lldb_private::operator==(const StackID &lhs, const StackID &rhs) {
+ if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
+ return false;
+
+ SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
+ SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
+
+ // Only compare the PC values if both symbol context scopes are nullptr
+ if (lhs_scope == nullptr && rhs_scope == nullptr)
+ return lhs.GetPC() == rhs.GetPC();
+
+ return lhs_scope == rhs_scope;
}
-bool
-lldb_private::operator!= (const StackID& lhs, const StackID& rhs)
-{
- if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
- return true;
+bool lldb_private::operator!=(const StackID &lhs, const StackID &rhs) {
+ if (lhs.GetCallFrameAddress() != rhs.GetCallFrameAddress())
+ return true;
- SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
- SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
+ SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
+ SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
- if (lhs_scope == nullptr && rhs_scope == nullptr)
- return lhs.GetPC() != rhs.GetPC();
+ if (lhs_scope == nullptr && rhs_scope == nullptr)
+ return lhs.GetPC() != rhs.GetPC();
- return lhs_scope != rhs_scope;
+ return lhs_scope != rhs_scope;
}
-bool
-lldb_private::operator< (const StackID& lhs, const StackID& rhs)
-{
- const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress();
- const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress();
-
- // FIXME: We are assuming that the stacks grow downward in memory. That's not necessary, but true on
- // all the machines we care about at present. If this changes, we'll have to deal with that. The ABI is the
- // agent who knows this ordering, but the StackID has no access to the ABI. The most straightforward way
- // to handle this is to add a "m_grows_downward" bool to the StackID, and set it in the constructor.
- // But I'm not going to waste a bool per StackID on this till we need it.
-
- if (lhs_cfa != rhs_cfa)
- return lhs_cfa < rhs_cfa;
-
- SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
- SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
-
- if (lhs_scope != nullptr && rhs_scope != nullptr)
- {
- // Same exact scope, lhs is not less than (younger than rhs)
- if (lhs_scope == rhs_scope)
- return false;
-
- SymbolContext lhs_sc;
- SymbolContext rhs_sc;
- lhs_scope->CalculateSymbolContext (&lhs_sc);
- rhs_scope->CalculateSymbolContext (&rhs_sc);
-
- // Items with the same function can only be compared
- if (lhs_sc.function == rhs_sc.function &&
- lhs_sc.function != nullptr && lhs_sc.block != nullptr &&
- rhs_sc.function != nullptr && rhs_sc.block != nullptr)
- {
- return rhs_sc.block->Contains (lhs_sc.block);
- }
+bool lldb_private::operator<(const StackID &lhs, const StackID &rhs) {
+ const lldb::addr_t lhs_cfa = lhs.GetCallFrameAddress();
+ const lldb::addr_t rhs_cfa = rhs.GetCallFrameAddress();
+
+ // FIXME: We are assuming that the stacks grow downward in memory. That's not
+ // necessary, but true on
+ // all the machines we care about at present. If this changes, we'll have to
+ // deal with that. The ABI is the
+ // agent who knows this ordering, but the StackID has no access to the ABI.
+ // The most straightforward way
+ // to handle this is to add a "m_grows_downward" bool to the StackID, and set
+ // it in the constructor.
+ // But I'm not going to waste a bool per StackID on this till we need it.
+
+ if (lhs_cfa != rhs_cfa)
+ return lhs_cfa < rhs_cfa;
+
+ SymbolContextScope *lhs_scope = lhs.GetSymbolContextScope();
+ SymbolContextScope *rhs_scope = rhs.GetSymbolContextScope();
+
+ if (lhs_scope != nullptr && rhs_scope != nullptr) {
+ // Same exact scope, lhs is not less than (younger than rhs)
+ if (lhs_scope == rhs_scope)
+ return false;
+
+ SymbolContext lhs_sc;
+ SymbolContext rhs_sc;
+ lhs_scope->CalculateSymbolContext(&lhs_sc);
+ rhs_scope->CalculateSymbolContext(&rhs_sc);
+
+ // Items with the same function can only be compared
+ if (lhs_sc.function == rhs_sc.function && lhs_sc.function != nullptr &&
+ lhs_sc.block != nullptr && rhs_sc.function != nullptr &&
+ rhs_sc.block != nullptr) {
+ return rhs_sc.block->Contains(lhs_sc.block);
}
- return false;
+ }
+ return false;
}
Modified: lldb/trunk/source/Target/StopInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StopInfo.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/StopInfo.cpp (original)
+++ lldb/trunk/source/Target/StopInfo.cpp Tue Sep 6 15:57:50 2016
@@ -13,1255 +13,1131 @@
// Other libraries and framework includes
// Project includes
-#include "lldb/Target/StopInfo.h"
-#include "lldb/Core/Log.h"
#include "lldb/Breakpoint/Breakpoint.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/Watchpoint.h"
#include "lldb/Core/Debugger.h"
+#include "lldb/Core/Log.h"
#include "lldb/Core/StreamString.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Expression/UserExpression.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/StopInfo.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
-#include "lldb/Target/Process.h"
#include "lldb/Target/UnixSignals.h"
using namespace lldb;
using namespace lldb_private;
-StopInfo::StopInfo (Thread &thread, uint64_t value) :
- m_thread_wp (thread.shared_from_this()),
- m_stop_id (thread.GetProcess()->GetStopID()),
- m_resume_id (thread.GetProcess()->GetResumeID()),
- m_value (value),
- m_description (),
- m_override_should_notify (eLazyBoolCalculate),
- m_override_should_stop (eLazyBoolCalculate),
- m_extended_info()
-{
+StopInfo::StopInfo(Thread &thread, uint64_t value)
+ : m_thread_wp(thread.shared_from_this()),
+ m_stop_id(thread.GetProcess()->GetStopID()),
+ m_resume_id(thread.GetProcess()->GetResumeID()), m_value(value),
+ m_description(), m_override_should_notify(eLazyBoolCalculate),
+ m_override_should_stop(eLazyBoolCalculate), m_extended_info() {}
+
+bool StopInfo::IsValid() const {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ return thread_sp->GetProcess()->GetStopID() == m_stop_id;
+ return false;
}
-bool
-StopInfo::IsValid () const
-{
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- return thread_sp->GetProcess()->GetStopID() == m_stop_id;
- return false;
-}
-
-void
-StopInfo::MakeStopInfoValid ()
-{
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- m_stop_id = thread_sp->GetProcess()->GetStopID();
- m_resume_id = thread_sp->GetProcess()->GetResumeID();
- }
+void StopInfo::MakeStopInfoValid() {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ m_stop_id = thread_sp->GetProcess()->GetStopID();
+ m_resume_id = thread_sp->GetProcess()->GetResumeID();
+ }
}
-bool
-StopInfo::HasTargetRunSinceMe ()
-{
- ThreadSP thread_sp (m_thread_wp.lock());
+bool StopInfo::HasTargetRunSinceMe() {
+ ThreadSP thread_sp(m_thread_wp.lock());
- if (thread_sp)
- {
- lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState();
- if (ret_type == eStateRunning)
- {
- return true;
- }
- else if (ret_type == eStateStopped)
- {
- // This is a little tricky. We want to count "run and stopped again before you could
- // ask this question as a "TRUE" answer to HasTargetRunSinceMe. But we don't want to
- // include any running of the target done for expressions. So we track both resumes,
- // and resumes caused by expressions, and check if there are any resumes NOT caused
- // by expressions.
-
- uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID();
- uint32_t last_user_expression_id = thread_sp->GetProcess()->GetLastUserExpressionResumeID ();
- if (curr_resume_id == m_resume_id)
- {
- return false;
- }
- else if (curr_resume_id > last_user_expression_id)
- {
- return true;
- }
- }
+ if (thread_sp) {
+ lldb::StateType ret_type = thread_sp->GetProcess()->GetPrivateState();
+ if (ret_type == eStateRunning) {
+ return true;
+ } else if (ret_type == eStateStopped) {
+ // This is a little tricky. We want to count "run and stopped again
+ // before you could
+ // ask this question as a "TRUE" answer to HasTargetRunSinceMe. But we
+ // don't want to
+ // include any running of the target done for expressions. So we track
+ // both resumes,
+ // and resumes caused by expressions, and check if there are any resumes
+ // NOT caused
+ // by expressions.
+
+ uint32_t curr_resume_id = thread_sp->GetProcess()->GetResumeID();
+ uint32_t last_user_expression_id =
+ thread_sp->GetProcess()->GetLastUserExpressionResumeID();
+ if (curr_resume_id == m_resume_id) {
+ return false;
+ } else if (curr_resume_id > last_user_expression_id) {
+ return true;
+ }
}
- return false;
+ }
+ return false;
}
//----------------------------------------------------------------------
// StopInfoBreakpoint
//----------------------------------------------------------------------
-namespace lldb_private
-{
-class StopInfoBreakpoint : public StopInfo
-{
+namespace lldb_private {
+class StopInfoBreakpoint : public StopInfo {
public:
- StopInfoBreakpoint (Thread &thread, break_id_t break_id) :
- StopInfo (thread, break_id),
- m_should_stop (false),
- m_should_stop_is_valid (false),
- m_should_perform_action (true),
- m_address (LLDB_INVALID_ADDRESS),
- m_break_id(LLDB_INVALID_BREAK_ID),
- m_was_one_shot (false)
- {
- StoreBPInfo();
+ StopInfoBreakpoint(Thread &thread, break_id_t break_id)
+ : StopInfo(thread, break_id), m_should_stop(false),
+ m_should_stop_is_valid(false), m_should_perform_action(true),
+ m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID),
+ m_was_one_shot(false) {
+ StoreBPInfo();
+ }
+
+ StopInfoBreakpoint(Thread &thread, break_id_t break_id, bool should_stop)
+ : StopInfo(thread, break_id), m_should_stop(should_stop),
+ m_should_stop_is_valid(true), m_should_perform_action(true),
+ m_address(LLDB_INVALID_ADDRESS), m_break_id(LLDB_INVALID_BREAK_ID),
+ m_was_one_shot(false) {
+ StoreBPInfo();
+ }
+
+ ~StopInfoBreakpoint() override = default;
+
+ void StoreBPInfo() {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ BreakpointSiteSP bp_site_sp(
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ if (bp_site_sp) {
+ if (bp_site_sp->GetNumberOfOwners() == 1) {
+ BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0);
+ if (bp_loc_sp) {
+ m_break_id = bp_loc_sp->GetBreakpoint().GetID();
+ m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot();
+ }
+ }
+ m_address = bp_site_sp->GetLoadAddress();
+ }
}
+ }
- StopInfoBreakpoint (Thread &thread, break_id_t break_id, bool should_stop) :
- StopInfo (thread, break_id),
- m_should_stop (should_stop),
- m_should_stop_is_valid (true),
- m_should_perform_action (true),
- m_address (LLDB_INVALID_ADDRESS),
- m_break_id(LLDB_INVALID_BREAK_ID),
- m_was_one_shot (false)
- {
- StoreBPInfo();
+ bool IsValidForOperatingSystemThread(Thread &thread) override {
+ ProcessSP process_sp(thread.GetProcess());
+ if (process_sp) {
+ BreakpointSiteSP bp_site_sp(
+ process_sp->GetBreakpointSiteList().FindByID(m_value));
+ if (bp_site_sp)
+ return bp_site_sp->ValidForThisThread(&thread);
}
+ return false;
+ }
- ~StopInfoBreakpoint() override = default;
+ StopReason GetStopReason() const override { return eStopReasonBreakpoint; }
- void
- StoreBPInfo ()
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
- if (bp_site_sp)
- {
- if (bp_site_sp->GetNumberOfOwners() == 1)
- {
- BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(0);
- if (bp_loc_sp)
- {
- m_break_id = bp_loc_sp->GetBreakpoint().GetID();
- m_was_one_shot = bp_loc_sp->GetBreakpoint().IsOneShot();
- }
- }
- m_address = bp_site_sp->GetLoadAddress();
- }
+ bool ShouldStopSynchronous(Event *event_ptr) override {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ if (!m_should_stop_is_valid) {
+ // Only check once if we should stop at a breakpoint
+ BreakpointSiteSP bp_site_sp(
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ if (bp_site_sp) {
+ ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
+ StoppointCallbackContext context(event_ptr, exe_ctx, true);
+ bp_site_sp->BumpHitCounts();
+ m_should_stop = bp_site_sp->ShouldStop(&context);
+ } else {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf(
+ "Process::%s could not find breakpoint site id: %" PRId64 "...",
+ __FUNCTION__, m_value);
+
+ m_should_stop = true;
}
+ m_should_stop_is_valid = true;
+ }
+ return m_should_stop;
}
+ return false;
+ }
- bool
- IsValidForOperatingSystemThread(Thread &thread) override
- {
- ProcessSP process_sp (thread.GetProcess());
- if (process_sp)
- {
- BreakpointSiteSP bp_site_sp (process_sp->GetBreakpointSiteList().FindByID (m_value));
- if (bp_site_sp)
- return bp_site_sp->ValidForThisThread (&thread);
+ bool DoShouldNotify(Event *event_ptr) override {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ BreakpointSiteSP bp_site_sp(
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ if (bp_site_sp) {
+ bool all_internal = true;
+
+ for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++) {
+ if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal()) {
+ all_internal = false;
+ break;
+ }
}
- return false;
+ return !all_internal;
+ }
}
+ return true;
+ }
- StopReason
- GetStopReason() const override
- {
- return eStopReasonBreakpoint;
- }
+ const char *GetDescription() override {
+ if (m_description.empty()) {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ BreakpointSiteSP bp_site_sp(
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ if (bp_site_sp) {
+ StreamString strm;
+ // If we have just hit an internal breakpoint, and it has a kind
+ // description, print that instead of the
+ // full breakpoint printing:
+ if (bp_site_sp->IsInternal()) {
+ size_t num_owners = bp_site_sp->GetNumberOfOwners();
+ for (size_t idx = 0; idx < num_owners; idx++) {
+ const char *kind = bp_site_sp->GetOwnerAtIndex(idx)
+ ->GetBreakpoint()
+ .GetBreakpointKind();
+ if (kind != nullptr) {
+ m_description.assign(kind);
+ return kind;
+ }
+ }
+ }
- bool
- ShouldStopSynchronous(Event *event_ptr) override
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- if (!m_should_stop_is_valid)
- {
- // Only check once if we should stop at a breakpoint
- BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
- if (bp_site_sp)
- {
- ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
- StoppointCallbackContext context (event_ptr, exe_ctx, true);
- bp_site_sp->BumpHitCounts();
- m_should_stop = bp_site_sp->ShouldStop (&context);
- }
+ strm.Printf("breakpoint ");
+ bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
+ m_description.swap(strm.GetString());
+ } else {
+ StreamString strm;
+ if (m_break_id != LLDB_INVALID_BREAK_ID) {
+ BreakpointSP break_sp =
+ thread_sp->GetProcess()->GetTarget().GetBreakpointByID(
+ m_break_id);
+ if (break_sp) {
+ if (break_sp->IsInternal()) {
+ const char *kind = break_sp->GetBreakpointKind();
+ if (kind)
+ strm.Printf("internal %s breakpoint(%d).", kind, m_break_id);
else
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
-
- if (log)
- log->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
-
- m_should_stop = true;
- }
- m_should_stop_is_valid = true;
+ strm.Printf("internal breakpoint(%d).", m_break_id);
+ } else {
+ strm.Printf("breakpoint %d.", m_break_id);
+ }
+ } else {
+ if (m_was_one_shot)
+ strm.Printf("one-shot breakpoint %d", m_break_id);
+ else
+ strm.Printf("breakpoint %d which has been deleted.",
+ m_break_id);
}
- return m_should_stop;
+ } else if (m_address == LLDB_INVALID_ADDRESS)
+ strm.Printf("breakpoint site %" PRIi64
+ " which has been deleted - unknown address",
+ m_value);
+ else
+ strm.Printf("breakpoint site %" PRIi64
+ " which has been deleted - was at 0x%" PRIx64,
+ m_value, m_address);
+
+ m_description.swap(strm.GetString());
}
- return false;
+ }
}
+ return m_description.c_str();
+ }
- bool
- DoShouldNotify(Event *event_ptr) override
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
- if (bp_site_sp)
- {
- bool all_internal = true;
-
- for (uint32_t i = 0; i < bp_site_sp->GetNumberOfOwners(); i++)
- {
- if (!bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint().IsInternal())
- {
- all_internal = false;
- break;
- }
- }
- return !all_internal;
- }
+protected:
+ bool ShouldStop(Event *event_ptr) override {
+ // This just reports the work done by PerformAction or the synchronous stop.
+ // It should
+ // only ever get called after they have had a chance to run.
+ assert(m_should_stop_is_valid);
+ return m_should_stop;
+ }
+
+ void PerformAction(Event *event_ptr) override {
+ if (!m_should_perform_action)
+ return;
+ m_should_perform_action = false;
+
+ ThreadSP thread_sp(m_thread_wp.lock());
+
+ if (thread_sp) {
+ Log *log = lldb_private::GetLogIfAnyCategoriesSet(
+ LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP);
+
+ if (!thread_sp->IsValid()) {
+ // This shouldn't ever happen, but just in case, don't do more harm.
+ if (log) {
+ log->Printf("PerformAction got called with an invalid thread.");
}
- return true;
- }
+ m_should_stop = true;
+ m_should_stop_is_valid = true;
+ return;
+ }
- const char *
- GetDescription() override
- {
- if (m_description.empty())
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
- if (bp_site_sp)
- {
- StreamString strm;
- // If we have just hit an internal breakpoint, and it has a kind description, print that instead of the
- // full breakpoint printing:
- if (bp_site_sp->IsInternal())
- {
- size_t num_owners = bp_site_sp->GetNumberOfOwners();
- for (size_t idx = 0; idx < num_owners; idx++)
- {
- const char *kind = bp_site_sp->GetOwnerAtIndex(idx)->GetBreakpoint().GetBreakpointKind();
- if (kind != nullptr)
- {
- m_description.assign (kind);
- return kind;
- }
- }
- }
-
- strm.Printf("breakpoint ");
- bp_site_sp->GetDescription(&strm, eDescriptionLevelBrief);
- m_description.swap (strm.GetString());
- }
- else
- {
- StreamString strm;
- if (m_break_id != LLDB_INVALID_BREAK_ID)
- {
- BreakpointSP break_sp = thread_sp->GetProcess()->GetTarget().GetBreakpointByID(m_break_id);
- if (break_sp)
- {
- if (break_sp->IsInternal())
- {
- const char *kind = break_sp->GetBreakpointKind();
- if (kind)
- strm.Printf ("internal %s breakpoint(%d).", kind, m_break_id);
- else
- strm.Printf ("internal breakpoint(%d).", m_break_id);
- }
- else
- {
- strm.Printf ("breakpoint %d.", m_break_id);
- }
- }
- else
- {
- if (m_was_one_shot)
- strm.Printf ("one-shot breakpoint %d", m_break_id);
- else
- strm.Printf ("breakpoint %d which has been deleted.", m_break_id);
- }
- }
- else if (m_address == LLDB_INVALID_ADDRESS)
- strm.Printf("breakpoint site %" PRIi64 " which has been deleted - unknown address", m_value);
- else
- strm.Printf("breakpoint site %" PRIi64 " which has been deleted - was at 0x%" PRIx64, m_value, m_address);
+ BreakpointSiteSP bp_site_sp(
+ thread_sp->GetProcess()->GetBreakpointSiteList().FindByID(m_value));
+ std::unordered_set<break_id_t> precondition_breakpoints;
+
+ if (bp_site_sp) {
+ // Let's copy the owners list out of the site and store them in a local
+ // list. That way if
+ // one of the breakpoint actions changes the site, then we won't be
+ // operating on a bad list.
+ BreakpointLocationCollection site_locations;
+ size_t num_owners = bp_site_sp->CopyOwnersList(site_locations);
+
+ if (num_owners == 0) {
+ m_should_stop = true;
+ } else {
+ // We go through each location, and test first its precondition - this
+ // overrides everything. Note,
+ // we only do this once per breakpoint - not once per location...
+ // Then check the condition. If the condition says to stop,
+ // then we run the callback for that location. If that callback says
+ // to stop as well, then
+ // we set m_should_stop to true; we are going to stop.
+ // But we still want to give all the breakpoints whose conditions say
+ // we are going to stop a
+ // chance to run their callbacks.
+ // Of course if any callback restarts the target by putting "continue"
+ // in the callback, then
+ // we're going to restart, without running the rest of the callbacks.
+ // And in this case we will
+ // end up not stopping even if another location said we should stop.
+ // But that's better than not
+ // running all the callbacks.
+
+ m_should_stop = false;
+
+ // We don't select threads as we go through them testing breakpoint
+ // conditions and running commands.
+ // So we need to set the thread for expression evaluation here:
+ ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp);
+
+ ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
+ Process *process = exe_ctx.GetProcessPtr();
+ if (process->GetModIDRef().IsLastResumeForUserExpression()) {
+ // If we are in the middle of evaluating an expression, don't run
+ // asynchronous breakpoint commands or
+ // expressions. That could lead to infinite recursion if the
+ // command or condition re-calls the function
+ // with this breakpoint.
+ // TODO: We can keep a list of the breakpoints we've seen while
+ // running expressions in the nested
+ // PerformAction calls that can arise when the action runs a
+ // function that hits another breakpoint,
+ // and only stop running commands when we see the same breakpoint
+ // hit a second time.
- m_description.swap (strm.GetString());
+ m_should_stop_is_valid = true;
+ if (log)
+ log->Printf("StopInfoBreakpoint::PerformAction - Hit a "
+ "breakpoint while running an expression,"
+ " not running commands to avoid recursion.");
+ bool ignoring_breakpoints =
+ process->GetIgnoreBreakpointsInExpressions();
+ if (ignoring_breakpoints) {
+ m_should_stop = false;
+ // Internal breakpoints will always stop.
+ for (size_t j = 0; j < num_owners; j++) {
+ lldb::BreakpointLocationSP bp_loc_sp =
+ bp_site_sp->GetOwnerAtIndex(j);
+ if (bp_loc_sp->GetBreakpoint().IsInternal()) {
+ m_should_stop = true;
+ break;
}
+ }
+ } else {
+ m_should_stop = true;
}
- }
- return m_description.c_str();
- }
-
-protected:
- bool
- ShouldStop(Event *event_ptr) override
- {
- // This just reports the work done by PerformAction or the synchronous stop. It should
- // only ever get called after they have had a chance to run.
- assert (m_should_stop_is_valid);
- return m_should_stop;
- }
-
- void
- PerformAction(Event *event_ptr) override
- {
- if (!m_should_perform_action)
+ if (log)
+ log->Printf("StopInfoBreakpoint::PerformAction - in expression, "
+ "continuing: %s.",
+ m_should_stop ? "true" : "false");
+ process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf(
+ "Warning: hit breakpoint while "
+ "running function, skipping commands and conditions to prevent "
+ "recursion.");
return;
- m_should_perform_action = false;
+ }
- ThreadSP thread_sp (m_thread_wp.lock());
+ StoppointCallbackContext context(event_ptr, exe_ctx, false);
- if (thread_sp)
- {
- Log *log = lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_BREAKPOINTS | LIBLLDB_LOG_STEP);
+ // For safety's sake let's also grab an extra reference to the
+ // breakpoint owners of the locations we're
+ // going to examine, since the locations are going to have to get back
+ // to their breakpoints, and the
+ // locations don't keep their owners alive. I'm just sticking the
+ // BreakpointSP's in a vector since
+ // I'm only using it to locally increment their retain counts.
+
+ std::vector<lldb::BreakpointSP> location_owners;
+
+ for (size_t j = 0; j < num_owners; j++) {
+ BreakpointLocationSP loc(site_locations.GetByIndex(j));
+ location_owners.push_back(loc->GetBreakpoint().shared_from_this());
+ }
+
+ for (size_t j = 0; j < num_owners; j++) {
+ lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
+
+ // If another action disabled this breakpoint or its location, then
+ // don't run the actions.
+ if (!bp_loc_sp->IsEnabled() ||
+ !bp_loc_sp->GetBreakpoint().IsEnabled())
+ continue;
+
+ // The breakpoint site may have many locations associated with it,
+ // not all of them valid for
+ // this thread. Skip the ones that aren't:
+ if (!bp_loc_sp->ValidForThisThread(thread_sp.get())) {
+ if (log) {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
+ log->Printf("Breakpoint %s hit on thread 0x%llx but it was not "
+ "for this thread, continuing.",
+ s.GetData(), static_cast<unsigned long long>(
+ thread_sp->GetID()));
+ }
+ continue;
+ }
- if (!thread_sp->IsValid())
- {
- // This shouldn't ever happen, but just in case, don't do more harm.
+ // First run the precondition, but since the precondition is per
+ // breakpoint, only run it once
+ // per breakpoint.
+ std::pair<std::unordered_set<break_id_t>::iterator, bool> result =
+ precondition_breakpoints.insert(
+ bp_loc_sp->GetBreakpoint().GetID());
+ if (!result.second)
+ continue;
+
+ bool precondition_result =
+ bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context);
+ if (!precondition_result)
+ continue;
+
+ // Next run the condition for the breakpoint. If that says we
+ // should stop, then we'll run
+ // the callback for the breakpoint. If the callback says we
+ // shouldn't stop that will win.
+
+ if (bp_loc_sp->GetConditionText() != nullptr) {
+ Error condition_error;
+ bool condition_says_stop =
+ bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
+
+ if (!condition_error.Success()) {
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP error_sp = debugger.GetAsyncErrorStream();
+ error_sp->Printf("Stopped due to an error evaluating condition "
+ "of breakpoint ");
+ bp_loc_sp->GetDescription(error_sp.get(),
+ eDescriptionLevelBrief);
+ error_sp->Printf(": \"%s\"", bp_loc_sp->GetConditionText());
+ error_sp->EOL();
+ const char *err_str =
+ condition_error.AsCString("<Unknown Error>");
if (log)
- {
- log->Printf ("PerformAction got called with an invalid thread.");
+ log->Printf("Error evaluating condition: \"%s\"\n", err_str);
+
+ error_sp->PutCString(err_str);
+ error_sp->EOL();
+ error_sp->Flush();
+ } else {
+ if (log) {
+ StreamString s;
+ bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
+ log->Printf("Condition evaluated for breakpoint %s on thread "
+ "0x%llx conditon_says_stop: %i.",
+ s.GetData(), static_cast<unsigned long long>(
+ thread_sp->GetID()),
+ condition_says_stop);
}
- m_should_stop = true;
- m_should_stop_is_valid = true;
- return;
+ if (!condition_says_stop) {
+ // We don't want to increment the hit count of breakpoints if
+ // the condition fails.
+ // We've already bumped it by the time we get here, so undo
+ // the bump:
+ bp_loc_sp->UndoBumpHitCount();
+ continue;
+ }
+ }
}
- BreakpointSiteSP bp_site_sp (thread_sp->GetProcess()->GetBreakpointSiteList().FindByID (m_value));
- std::unordered_set<break_id_t> precondition_breakpoints;
+ bool callback_says_stop;
- if (bp_site_sp)
- {
- // Let's copy the owners list out of the site and store them in a local list. That way if
- // one of the breakpoint actions changes the site, then we won't be operating on a bad list.
- BreakpointLocationCollection site_locations;
- size_t num_owners = bp_site_sp->CopyOwnersList(site_locations);
-
- if (num_owners == 0)
- {
- m_should_stop = true;
- }
- else
- {
- // We go through each location, and test first its precondition - this overrides everything. Note,
- // we only do this once per breakpoint - not once per location...
- // Then check the condition. If the condition says to stop,
- // then we run the callback for that location. If that callback says to stop as well, then
- // we set m_should_stop to true; we are going to stop.
- // But we still want to give all the breakpoints whose conditions say we are going to stop a
- // chance to run their callbacks.
- // Of course if any callback restarts the target by putting "continue" in the callback, then
- // we're going to restart, without running the rest of the callbacks. And in this case we will
- // end up not stopping even if another location said we should stop. But that's better than not
- // running all the callbacks.
-
- m_should_stop = false;
-
- // We don't select threads as we go through them testing breakpoint conditions and running commands.
- // So we need to set the thread for expression evaluation here:
- ThreadList::ExpressionExecutionThreadPusher thread_pusher(thread_sp);
-
- ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
- Process *process = exe_ctx.GetProcessPtr();
- if (process->GetModIDRef().IsLastResumeForUserExpression())
- {
- // If we are in the middle of evaluating an expression, don't run asynchronous breakpoint commands or
- // expressions. That could lead to infinite recursion if the command or condition re-calls the function
- // with this breakpoint.
- // TODO: We can keep a list of the breakpoints we've seen while running expressions in the nested
- // PerformAction calls that can arise when the action runs a function that hits another breakpoint,
- // and only stop running commands when we see the same breakpoint hit a second time.
-
- m_should_stop_is_valid = true;
- if (log)
- log->Printf ("StopInfoBreakpoint::PerformAction - Hit a breakpoint while running an expression,"
- " not running commands to avoid recursion.");
- bool ignoring_breakpoints = process->GetIgnoreBreakpointsInExpressions();
- if (ignoring_breakpoints)
- {
- m_should_stop = false;
- // Internal breakpoints will always stop.
- for (size_t j = 0; j < num_owners; j++)
- {
- lldb::BreakpointLocationSP bp_loc_sp = bp_site_sp->GetOwnerAtIndex(j);
- if (bp_loc_sp->GetBreakpoint().IsInternal())
- {
- m_should_stop = true;
- break;
- }
- }
- }
- else
- {
- m_should_stop = true;
- }
- if (log)
- log->Printf ("StopInfoBreakpoint::PerformAction - in expression, continuing: %s.",
- m_should_stop ? "true" : "false");
- process->GetTarget().GetDebugger().GetAsyncOutputStream()->Printf("Warning: hit breakpoint while "
- "running function, skipping commands and conditions to prevent recursion.");
- return;
- }
-
- StoppointCallbackContext context (event_ptr, exe_ctx, false);
-
- // For safety's sake let's also grab an extra reference to the breakpoint owners of the locations we're
- // going to examine, since the locations are going to have to get back to their breakpoints, and the
- // locations don't keep their owners alive. I'm just sticking the BreakpointSP's in a vector since
- // I'm only using it to locally increment their retain counts.
-
- std::vector<lldb::BreakpointSP> location_owners;
-
- for (size_t j = 0; j < num_owners; j++)
- {
- BreakpointLocationSP loc(site_locations.GetByIndex(j));
- location_owners.push_back(loc->GetBreakpoint().shared_from_this());
-
- }
-
- for (size_t j = 0; j < num_owners; j++)
- {
- lldb::BreakpointLocationSP bp_loc_sp = site_locations.GetByIndex(j);
-
- // If another action disabled this breakpoint or its location, then don't run the actions.
- if (!bp_loc_sp->IsEnabled() || !bp_loc_sp->GetBreakpoint().IsEnabled())
- continue;
-
- // The breakpoint site may have many locations associated with it, not all of them valid for
- // this thread. Skip the ones that aren't:
- if (!bp_loc_sp->ValidForThisThread(thread_sp.get()))
- {
- if (log)
- {
- StreamString s;
- bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
- log->Printf ("Breakpoint %s hit on thread 0x%llx but it was not for this thread, continuing.",
- s.GetData(),
- static_cast<unsigned long long>(thread_sp->GetID()));
- }
- continue;
- }
-
- // First run the precondition, but since the precondition is per breakpoint, only run it once
- // per breakpoint.
- std::pair<std::unordered_set<break_id_t>::iterator, bool> result
- = precondition_breakpoints.insert(bp_loc_sp->GetBreakpoint().GetID());
- if (!result.second)
- continue;
-
- bool precondition_result = bp_loc_sp->GetBreakpoint().EvaluatePrecondition(context);
- if (!precondition_result)
- continue;
-
- // Next run the condition for the breakpoint. If that says we should stop, then we'll run
- // the callback for the breakpoint. If the callback says we shouldn't stop that will win.
-
- if (bp_loc_sp->GetConditionText() != nullptr)
- {
- Error condition_error;
- bool condition_says_stop = bp_loc_sp->ConditionSaysStop(exe_ctx, condition_error);
-
- if (!condition_error.Success())
- {
- Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
- StreamSP error_sp = debugger.GetAsyncErrorStream ();
- error_sp->Printf ("Stopped due to an error evaluating condition of breakpoint ");
- bp_loc_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
- error_sp->Printf (": \"%s\"",
- bp_loc_sp->GetConditionText());
- error_sp->EOL();
- const char *err_str = condition_error.AsCString("<Unknown Error>");
- if (log)
- log->Printf("Error evaluating condition: \"%s\"\n", err_str);
-
- error_sp->PutCString (err_str);
- error_sp->EOL();
- error_sp->Flush();
- }
- else
- {
- if (log)
- {
- StreamString s;
- bp_loc_sp->GetDescription(&s, eDescriptionLevelBrief);
- log->Printf ("Condition evaluated for breakpoint %s on thread 0x%llx conditon_says_stop: %i.",
- s.GetData(),
- static_cast<unsigned long long>(thread_sp->GetID()),
- condition_says_stop);
- }
- if (!condition_says_stop)
- {
- // We don't want to increment the hit count of breakpoints if the condition fails.
- // We've already bumped it by the time we get here, so undo the bump:
- bp_loc_sp->UndoBumpHitCount();
- continue;
- }
- }
- }
-
- bool callback_says_stop;
-
- // FIXME: For now the callbacks have to run in async mode - the first time we restart we need
- // to get out of there. So set it here.
- // When we figure out how to nest breakpoint hits then this will change.
-
- Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();
- bool old_async = debugger.GetAsyncExecution();
- debugger.SetAsyncExecution (true);
-
- callback_says_stop = bp_loc_sp->InvokeCallback (&context);
-
- debugger.SetAsyncExecution (old_async);
-
- if (callback_says_stop)
- m_should_stop = true;
-
- // If we are going to stop for this breakpoint, then remove the breakpoint.
- if (callback_says_stop && bp_loc_sp && bp_loc_sp->GetBreakpoint().IsOneShot())
- {
- thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID (bp_loc_sp->GetBreakpoint().GetID());
- }
-
- // Also make sure that the callback hasn't continued the target.
- // If it did, when we'll set m_should_start to false and get out of here.
- if (HasTargetRunSinceMe ())
- {
- m_should_stop = false;
- break;
- }
- }
- }
- // We've figured out what this stop wants to do, so mark it as valid so we don't compute it again.
- m_should_stop_is_valid = true;
+ // FIXME: For now the callbacks have to run in async mode - the
+ // first time we restart we need
+ // to get out of there. So set it here.
+ // When we figure out how to nest breakpoint hits then this will
+ // change.
+
+ Debugger &debugger = thread_sp->CalculateTarget()->GetDebugger();
+ bool old_async = debugger.GetAsyncExecution();
+ debugger.SetAsyncExecution(true);
+
+ callback_says_stop = bp_loc_sp->InvokeCallback(&context);
+
+ debugger.SetAsyncExecution(old_async);
+
+ if (callback_says_stop)
+ m_should_stop = true;
+
+ // If we are going to stop for this breakpoint, then remove the
+ // breakpoint.
+ if (callback_says_stop && bp_loc_sp &&
+ bp_loc_sp->GetBreakpoint().IsOneShot()) {
+ thread_sp->GetProcess()->GetTarget().RemoveBreakpointByID(
+ bp_loc_sp->GetBreakpoint().GetID());
}
- else
- {
- m_should_stop = true;
- m_should_stop_is_valid = true;
- Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if (log_process)
- log_process->Printf ("Process::%s could not find breakpoint site id: %" PRId64 "...", __FUNCTION__, m_value);
+ // Also make sure that the callback hasn't continued the target.
+ // If it did, when we'll set m_should_start to false and get out of
+ // here.
+ if (HasTargetRunSinceMe()) {
+ m_should_stop = false;
+ break;
}
- if (log)
- log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
+ }
}
+ // We've figured out what this stop wants to do, so mark it as valid so
+ // we don't compute it again.
+ m_should_stop_is_valid = true;
+ } else {
+ m_should_stop = true;
+ m_should_stop_is_valid = true;
+ Log *log_process(
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (log_process)
+ log_process->Printf(
+ "Process::%s could not find breakpoint site id: %" PRId64 "...",
+ __FUNCTION__, m_value);
+ }
+ if (log)
+ log->Printf("Process::%s returning from action with m_should_stop: %d.",
+ __FUNCTION__, m_should_stop);
}
+ }
private:
- bool m_should_stop;
- bool m_should_stop_is_valid;
- bool m_should_perform_action; // Since we are trying to preserve the "state" of the system even if we run functions
- // etc. behind the users backs, we need to make sure we only REALLY perform the action once.
- lldb::addr_t m_address; // We use this to capture the breakpoint site address when we create the StopInfo,
- // in case somebody deletes it between the time the StopInfo is made and the
- // description is asked for.
- lldb::break_id_t m_break_id;
- bool m_was_one_shot;
+ bool m_should_stop;
+ bool m_should_stop_is_valid;
+ bool m_should_perform_action; // Since we are trying to preserve the "state"
+ // of the system even if we run functions
+ // etc. behind the users backs, we need to make sure we only REALLY perform
+ // the action once.
+ lldb::addr_t m_address; // We use this to capture the breakpoint site address
+ // when we create the StopInfo,
+ // in case somebody deletes it between the time the StopInfo is made and the
+ // description is asked for.
+ lldb::break_id_t m_break_id;
+ bool m_was_one_shot;
};
//----------------------------------------------------------------------
// StopInfoWatchpoint
//----------------------------------------------------------------------
-class StopInfoWatchpoint : public StopInfo
-{
+class StopInfoWatchpoint : public StopInfo {
public:
- // Make sure watchpoint is properly disabled and subsequently enabled while performing watchpoint actions.
- class WatchpointSentry {
- public:
- WatchpointSentry(Process *p, Watchpoint *w):
- process(p),
- watchpoint(w)
- {
- if (process && watchpoint)
- {
- const bool notify = false;
- watchpoint->TurnOnEphemeralMode();
- process->DisableWatchpoint(watchpoint, notify);
- }
+ // Make sure watchpoint is properly disabled and subsequently enabled while
+ // performing watchpoint actions.
+ class WatchpointSentry {
+ public:
+ WatchpointSentry(Process *p, Watchpoint *w) : process(p), watchpoint(w) {
+ if (process && watchpoint) {
+ const bool notify = false;
+ watchpoint->TurnOnEphemeralMode();
+ process->DisableWatchpoint(watchpoint, notify);
+ }
+ }
+
+ ~WatchpointSentry() {
+ if (process && watchpoint) {
+ if (!watchpoint->IsDisabledDuringEphemeralMode()) {
+ const bool notify = false;
+ process->EnableWatchpoint(watchpoint, notify);
}
+ watchpoint->TurnOffEphemeralMode();
+ }
+ }
- ~WatchpointSentry()
- {
- if (process && watchpoint)
- {
- if (!watchpoint->IsDisabledDuringEphemeralMode())
- {
- const bool notify = false;
- process->EnableWatchpoint(watchpoint, notify);
- }
- watchpoint->TurnOffEphemeralMode();
- }
- }
+ private:
+ Process *process;
+ Watchpoint *watchpoint;
+ };
- private:
- Process *process;
- Watchpoint *watchpoint;
- };
-
- StopInfoWatchpoint (Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr) :
- StopInfo(thread, watch_id),
- m_should_stop(false),
- m_should_stop_is_valid(false),
- m_watch_hit_addr(watch_hit_addr)
- {
- }
+ StopInfoWatchpoint(Thread &thread, break_id_t watch_id,
+ lldb::addr_t watch_hit_addr)
+ : StopInfo(thread, watch_id), m_should_stop(false),
+ m_should_stop_is_valid(false), m_watch_hit_addr(watch_hit_addr) {}
- ~StopInfoWatchpoint() override = default;
+ ~StopInfoWatchpoint() override = default;
- StopReason
- GetStopReason() const override
- {
- return eStopReasonWatchpoint;
- }
+ StopReason GetStopReason() const override { return eStopReasonWatchpoint; }
- const char *
- GetDescription() override
- {
- if (m_description.empty())
- {
- StreamString strm;
- strm.Printf("watchpoint %" PRIi64, m_value);
- m_description.swap (strm.GetString());
- }
- return m_description.c_str();
+ const char *GetDescription() override {
+ if (m_description.empty()) {
+ StreamString strm;
+ strm.Printf("watchpoint %" PRIi64, m_value);
+ m_description.swap(strm.GetString());
}
+ return m_description.c_str();
+ }
protected:
- bool
- ShouldStopSynchronous(Event *event_ptr) override
- {
- // ShouldStop() method is idempotent and should not affect hit count.
- // See Process::RunPrivateStateThread()->Process()->HandlePrivateEvent()
- // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()->
- // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()->
- // StopInfoWatchpoint::ShouldStop() and
- // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()->
- // StopInfoWatchpoint::PerformAction().
- if (m_should_stop_is_valid)
- return m_should_stop;
+ bool ShouldStopSynchronous(Event *event_ptr) override {
+ // ShouldStop() method is idempotent and should not affect hit count.
+ // See Process::RunPrivateStateThread()->Process()->HandlePrivateEvent()
+ // -->Process()::ShouldBroadcastEvent()->ThreadList::ShouldStop()->
+ // Thread::ShouldStop()->ThreadPlanBase::ShouldStop()->
+ // StopInfoWatchpoint::ShouldStop() and
+ // Event::DoOnRemoval()->Process::ProcessEventData::DoOnRemoval()->
+ // StopInfoWatchpoint::PerformAction().
+ if (m_should_stop_is_valid)
+ return m_should_stop;
+
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ WatchpointSP wp_sp(
+ thread_sp->CalculateTarget()->GetWatchpointList().FindByID(
+ GetValue()));
+ if (wp_sp) {
+ // Check if we should stop at a watchpoint.
+ ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
+ StoppointCallbackContext context(event_ptr, exe_ctx, true);
+ m_should_stop = wp_sp->ShouldStop(&context);
+ } else {
+ Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (log)
+ log->Printf(
+ "Process::%s could not find watchpoint location id: %" PRId64
+ "...",
+ __FUNCTION__, GetValue());
+
+ m_should_stop = true;
+ }
+ }
+ m_should_stop_is_valid = true;
+ return m_should_stop;
+ }
+
+ bool ShouldStop(Event *event_ptr) override {
+ // This just reports the work done by PerformAction or the synchronous stop.
+ // It should
+ // only ever get called after they have had a chance to run.
+ assert(m_should_stop_is_valid);
+ return m_should_stop;
+ }
+
+ void PerformAction(Event *event_ptr) override {
+ Log *log = lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_WATCHPOINTS);
+ // We're going to calculate if we should stop or not in some way during the
+ // course of
+ // this code. Also by default we're going to stop, so set that here.
+ m_should_stop = true;
+
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+
+ WatchpointSP wp_sp(
+ thread_sp->CalculateTarget()->GetWatchpointList().FindByID(
+ GetValue()));
+ if (wp_sp) {
+ ExecutionContext exe_ctx(thread_sp->GetStackFrameAtIndex(0));
+ Process *process = exe_ctx.GetProcessPtr();
+
+ // This sentry object makes sure the current watchpoint is disabled
+ // while performing watchpoint actions,
+ // and it is then enabled after we are finished.
+ WatchpointSentry sentry(process, wp_sp.get());
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
{
- WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
- if (wp_sp)
- {
- // Check if we should stop at a watchpoint.
- ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
- StoppointCallbackContext context (event_ptr, exe_ctx, true);
- m_should_stop = wp_sp->ShouldStop (&context);
+ // check if this process is running on an architecture where
+ // watchpoints trigger
+ // before the associated instruction runs. if so, disable the WP,
+ // single-step and then
+ // re-enable the watchpoint
+ if (process) {
+ uint32_t num;
+ bool wp_triggers_after;
+ if (process->GetWatchpointSupportInfo(num, wp_triggers_after)
+ .Success()) {
+ if (!wp_triggers_after) {
+ StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo();
+ assert(stored_stop_info_sp.get() == this);
+
+ ThreadPlanSP new_plan_sp(
+ thread_sp->QueueThreadPlanForStepSingleInstruction(
+ false, // step-over
+ false, // abort_other_plans
+ true)); // stop_other_threads
+ new_plan_sp->SetIsMasterPlan(true);
+ new_plan_sp->SetOkayToDiscard(false);
+ new_plan_sp->SetPrivate(true);
+ process->GetThreadList().SetSelectedThreadByID(
+ thread_sp->GetID());
+ process->ResumeSynchronous(nullptr);
+ process->GetThreadList().SetSelectedThreadByID(
+ thread_sp->GetID());
+ thread_sp->SetStopInfo(stored_stop_info_sp);
+ }
}
- else
- {
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ }
+ }
- if (log)
- log->Printf ("Process::%s could not find watchpoint location id: %" PRId64 "...",
- __FUNCTION__, GetValue());
+ /*
+ * MIPS: Last 3bits of the watchpoint address are masked by the kernel.
+ * For example:
+ * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is
+ * set at 'm', then
+ * watch exception is generated even when 'n' is read/written. To handle
+ * this case,
+ * server emulates the instruction at PC and finds the base address of
+ * the load/store
+ * instruction and appends it in the description of the stop-info
+ * packet. If watchpoint
+ * is not set on this address by user then this do not stop.
+ */
+ if (m_watch_hit_addr != LLDB_INVALID_ADDRESS) {
+ WatchpointSP wp_hit_sp =
+ thread_sp->CalculateTarget()->GetWatchpointList().FindByAddress(
+ m_watch_hit_addr);
+ if (!wp_hit_sp) {
+ m_should_stop = false;
+ wp_sp->IncrementFalseAlarmsAndReviseHitCount();
+ }
+ }
+ // TODO: This condition should be checked in the synchronous part of the
+ // watchpoint code
+ // (Watchpoint::ShouldStop), so that we avoid pulling an event even if
+ // the watchpoint fails
+ // the ignore count condition. It is moved here temporarily, because for
+ // archs with
+ // watchpoint_exceptions_received=before, the code in the previous lines
+ // takes care of moving
+ // the inferior to next PC. We have to check the ignore count condition
+ // after this is done,
+ // otherwise we will hit same watchpoint multiple times until we pass
+ // ignore condition, but we
+ // won't actually be ignoring them.
+ if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount())
+ m_should_stop = false;
+
+ if (m_should_stop && wp_sp->GetConditionText() != nullptr) {
+ // We need to make sure the user sees any parse errors in their
+ // condition, so we'll hook the
+ // constructor errors up to the debugger's Async I/O.
+ ExpressionResults result_code;
+ EvaluateExpressionOptions expr_options;
+ expr_options.SetUnwindOnError(true);
+ expr_options.SetIgnoreBreakpoints(true);
+ ValueObjectSP result_value_sp;
+ Error error;
+ result_code = UserExpression::Evaluate(
+ exe_ctx, expr_options, wp_sp->GetConditionText(), nullptr,
+ result_value_sp, error);
+
+ if (result_code == eExpressionCompleted) {
+ if (result_value_sp) {
+ Scalar scalar_value;
+ if (result_value_sp->ResolveValue(scalar_value)) {
+ if (scalar_value.ULongLong(1) == 0) {
+ // We have been vetoed. This takes precedence over querying
+ // the watchpoint whether it should stop (aka ignore count and
+ // friends). See also StopInfoWatchpoint::ShouldStop() as
+ // well
+ // as Process::ProcessEventData::DoOnRemoval().
+ m_should_stop = false;
+ } else
+ m_should_stop = true;
+ if (log)
+ log->Printf(
+ "Condition successfully evaluated, result is %s.\n",
+ m_should_stop ? "true" : "false");
+ } else {
m_should_stop = true;
+ if (log)
+ log->Printf(
+ "Failed to get an integer result from the expression.");
+ }
}
- }
- m_should_stop_is_valid = true;
- return m_should_stop;
- }
-
- bool
- ShouldStop(Event *event_ptr) override
- {
- // This just reports the work done by PerformAction or the synchronous stop. It should
- // only ever get called after they have had a chance to run.
- assert (m_should_stop_is_valid);
- return m_should_stop;
- }
-
- void
- PerformAction(Event *event_ptr) override
- {
- Log *log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_WATCHPOINTS);
- // We're going to calculate if we should stop or not in some way during the course of
- // this code. Also by default we're going to stop, so set that here.
- m_should_stop = true;
-
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
-
- WatchpointSP wp_sp (thread_sp->CalculateTarget()->GetWatchpointList().FindByID(GetValue()));
- if (wp_sp)
- {
- ExecutionContext exe_ctx (thread_sp->GetStackFrameAtIndex(0));
- Process* process = exe_ctx.GetProcessPtr();
-
- // This sentry object makes sure the current watchpoint is disabled while performing watchpoint actions,
- // and it is then enabled after we are finished.
- WatchpointSentry sentry(process, wp_sp.get());
-
- {
- // check if this process is running on an architecture where watchpoints trigger
- // before the associated instruction runs. if so, disable the WP, single-step and then
- // re-enable the watchpoint
- if (process)
- {
- uint32_t num;
- bool wp_triggers_after;
- if (process->GetWatchpointSupportInfo(num, wp_triggers_after).Success())
- {
- if (!wp_triggers_after)
- {
- StopInfoSP stored_stop_info_sp = thread_sp->GetStopInfo();
- assert (stored_stop_info_sp.get() == this);
-
- ThreadPlanSP new_plan_sp(thread_sp->QueueThreadPlanForStepSingleInstruction(false, // step-over
- false, // abort_other_plans
- true)); // stop_other_threads
- new_plan_sp->SetIsMasterPlan (true);
- new_plan_sp->SetOkayToDiscard (false);
- new_plan_sp->SetPrivate (true);
- process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
- process->ResumeSynchronous(nullptr);
- process->GetThreadList().SetSelectedThreadByID (thread_sp->GetID());
- thread_sp->SetStopInfo(stored_stop_info_sp);
- }
- }
- }
- }
+ } else {
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP error_sp = debugger.GetAsyncErrorStream();
+ error_sp->Printf(
+ "Stopped due to an error evaluating condition of watchpoint ");
+ wp_sp->GetDescription(error_sp.get(), eDescriptionLevelBrief);
+ error_sp->Printf(": \"%s\"", wp_sp->GetConditionText());
+ error_sp->EOL();
+ const char *err_str = error.AsCString("<Unknown Error>");
+ if (log)
+ log->Printf("Error evaluating condition: \"%s\"\n", err_str);
- /*
- * MIPS: Last 3bits of the watchpoint address are masked by the kernel. For example:
- * 'n' is at 0x120010d00 and 'm' is 0x120010d04. When a watchpoint is set at 'm', then
- * watch exception is generated even when 'n' is read/written. To handle this case,
- * server emulates the instruction at PC and finds the base address of the load/store
- * instruction and appends it in the description of the stop-info packet. If watchpoint
- * is not set on this address by user then this do not stop.
- */
- if (m_watch_hit_addr != LLDB_INVALID_ADDRESS)
- {
- WatchpointSP wp_hit_sp = thread_sp->CalculateTarget()->GetWatchpointList().FindByAddress(m_watch_hit_addr);
- if (!wp_hit_sp)
- {
- m_should_stop = false;
- wp_sp->IncrementFalseAlarmsAndReviseHitCount();
- }
- }
+ error_sp->PutCString(err_str);
+ error_sp->EOL();
+ error_sp->Flush();
+ // If the condition fails to be parsed or run, we should stop.
+ m_should_stop = true;
+ }
+ }
- // TODO: This condition should be checked in the synchronous part of the watchpoint code
- // (Watchpoint::ShouldStop), so that we avoid pulling an event even if the watchpoint fails
- // the ignore count condition. It is moved here temporarily, because for archs with
- // watchpoint_exceptions_received=before, the code in the previous lines takes care of moving
- // the inferior to next PC. We have to check the ignore count condition after this is done,
- // otherwise we will hit same watchpoint multiple times until we pass ignore condition, but we
- // won't actually be ignoring them.
- if (wp_sp->GetHitCount() <= wp_sp->GetIgnoreCount())
- m_should_stop = false;
-
- if (m_should_stop && wp_sp->GetConditionText() != nullptr)
- {
- // We need to make sure the user sees any parse errors in their condition, so we'll hook the
- // constructor errors up to the debugger's Async I/O.
- ExpressionResults result_code;
- EvaluateExpressionOptions expr_options;
- expr_options.SetUnwindOnError(true);
- expr_options.SetIgnoreBreakpoints(true);
- ValueObjectSP result_value_sp;
- Error error;
- result_code = UserExpression::Evaluate(exe_ctx,
- expr_options,
- wp_sp->GetConditionText(),
- nullptr,
- result_value_sp,
- error);
-
- if (result_code == eExpressionCompleted)
- {
- if (result_value_sp)
- {
- Scalar scalar_value;
- if (result_value_sp->ResolveValue (scalar_value))
- {
- if (scalar_value.ULongLong(1) == 0)
- {
- // We have been vetoed. This takes precedence over querying
- // the watchpoint whether it should stop (aka ignore count and
- // friends). See also StopInfoWatchpoint::ShouldStop() as well
- // as Process::ProcessEventData::DoOnRemoval().
- m_should_stop = false;
- }
- else
- m_should_stop = true;
- if (log)
- log->Printf("Condition successfully evaluated, result is %s.\n",
- m_should_stop ? "true" : "false");
- }
- else
- {
- m_should_stop = true;
- if (log)
- log->Printf("Failed to get an integer result from the expression.");
- }
- }
- }
- else
- {
- Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
- StreamSP error_sp = debugger.GetAsyncErrorStream ();
- error_sp->Printf ("Stopped due to an error evaluating condition of watchpoint ");
- wp_sp->GetDescription (error_sp.get(), eDescriptionLevelBrief);
- error_sp->Printf (": \"%s\"",
- wp_sp->GetConditionText());
- error_sp->EOL();
- const char *err_str = error.AsCString("<Unknown Error>");
- if (log)
- log->Printf("Error evaluating condition: \"%s\"\n", err_str);
-
- error_sp->PutCString (err_str);
- error_sp->EOL();
- error_sp->Flush();
- // If the condition fails to be parsed or run, we should stop.
- m_should_stop = true;
- }
- }
+ // If the condition says to stop, we run the callback to further decide
+ // whether to stop.
+ if (m_should_stop) {
+ StoppointCallbackContext context(event_ptr, exe_ctx, false);
+ bool stop_requested = wp_sp->InvokeCallback(&context);
+ // Also make sure that the callback hasn't continued the target.
+ // If it did, when we'll set m_should_stop to false and get out of
+ // here.
+ if (HasTargetRunSinceMe())
+ m_should_stop = false;
+
+ if (m_should_stop && !stop_requested) {
+ // We have been vetoed by the callback mechanism.
+ m_should_stop = false;
+ }
+ }
+ // Finally, if we are going to stop, print out the new & old values:
+ if (m_should_stop) {
+ wp_sp->CaptureWatchedValue(exe_ctx);
+
+ Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
+ StreamSP output_sp = debugger.GetAsyncOutputStream();
+ wp_sp->DumpSnapshots(output_sp.get());
+ output_sp->EOL();
+ output_sp->Flush();
+ }
- // If the condition says to stop, we run the callback to further decide whether to stop.
- if (m_should_stop)
- {
- StoppointCallbackContext context (event_ptr, exe_ctx, false);
- bool stop_requested = wp_sp->InvokeCallback (&context);
- // Also make sure that the callback hasn't continued the target.
- // If it did, when we'll set m_should_stop to false and get out of here.
- if (HasTargetRunSinceMe ())
- m_should_stop = false;
-
- if (m_should_stop && !stop_requested)
- {
- // We have been vetoed by the callback mechanism.
- m_should_stop = false;
- }
- }
- // Finally, if we are going to stop, print out the new & old values:
- if (m_should_stop)
- {
- wp_sp->CaptureWatchedValue(exe_ctx);
-
- Debugger &debugger = exe_ctx.GetTargetRef().GetDebugger();
- StreamSP output_sp = debugger.GetAsyncOutputStream ();
- wp_sp->DumpSnapshots(output_sp.get());
- output_sp->EOL();
- output_sp->Flush();
- }
-
- }
- else
- {
- Log * log_process(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ } else {
+ Log *log_process(
+ lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_PROCESS));
+
+ if (log_process)
+ log_process->Printf(
+ "Process::%s could not find watchpoint id: %" PRId64 "...",
+ __FUNCTION__, m_value);
+ }
+ if (log)
+ log->Printf("Process::%s returning from action with m_should_stop: %d.",
+ __FUNCTION__, m_should_stop);
- if (log_process)
- log_process->Printf ("Process::%s could not find watchpoint id: %" PRId64 "...", __FUNCTION__, m_value);
- }
- if (log)
- log->Printf ("Process::%s returning from action with m_should_stop: %d.", __FUNCTION__, m_should_stop);
-
- m_should_stop_is_valid = true;
- }
+ m_should_stop_is_valid = true;
}
-
+ }
+
private:
- bool m_should_stop;
- bool m_should_stop_is_valid;
- lldb::addr_t m_watch_hit_addr;
+ bool m_should_stop;
+ bool m_should_stop_is_valid;
+ lldb::addr_t m_watch_hit_addr;
};
//----------------------------------------------------------------------
// StopInfoUnixSignal
//----------------------------------------------------------------------
-class StopInfoUnixSignal : public StopInfo
-{
+class StopInfoUnixSignal : public StopInfo {
public:
- StopInfoUnixSignal (Thread &thread, int signo, const char *description) :
- StopInfo (thread, signo)
- {
- SetDescription (description);
- }
-
- ~StopInfoUnixSignal() override = default;
-
- StopReason
- GetStopReason() const override
- {
- return eStopReasonSignal;
- }
+ StopInfoUnixSignal(Thread &thread, int signo, const char *description)
+ : StopInfo(thread, signo) {
+ SetDescription(description);
+ }
- bool
- ShouldStopSynchronous(Event *event_ptr) override
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value);
- return false;
- }
+ ~StopInfoUnixSignal() override = default;
- bool
- ShouldStop(Event *event_ptr) override
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value);
- return false;
- }
+ StopReason GetStopReason() const override { return eStopReasonSignal; }
- // If should stop returns false, check if we should notify of this event
- bool
- DoShouldNotify(Event *event_ptr) override
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- bool should_notify = thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value);
- if (should_notify)
- {
- StreamString strm;
- strm.Printf ("thread %d received signal: %s",
- thread_sp->GetIndexID(),
- thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(m_value));
- Process::ProcessEventData::AddRestartedReason(event_ptr, strm.GetData());
- }
- return should_notify;
- }
- return true;
- }
+ bool ShouldStopSynchronous(Event *event_ptr) override {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value);
+ return false;
+ }
- void
- WillResume(lldb::StateType resume_state) override
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress(m_value))
- thread_sp->SetResumeSignal(m_value);
- }
- }
+ bool ShouldStop(Event *event_ptr) override {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ return thread_sp->GetProcess()->GetUnixSignals()->GetShouldStop(m_value);
+ return false;
+ }
- const char *
- GetDescription() override
- {
- if (m_description.empty())
- {
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- {
- StreamString strm;
- const char *signal_name = thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(m_value);
- if (signal_name)
- strm.Printf("signal %s", signal_name);
- else
- strm.Printf("signal %" PRIi64, m_value);
- m_description.swap (strm.GetString());
- }
- }
- return m_description.c_str();
+ // If should stop returns false, check if we should notify of this event
+ bool DoShouldNotify(Event *event_ptr) override {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ bool should_notify =
+ thread_sp->GetProcess()->GetUnixSignals()->GetShouldNotify(m_value);
+ if (should_notify) {
+ StreamString strm;
+ strm.Printf(
+ "thread %d received signal: %s", thread_sp->GetIndexID(),
+ thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(
+ m_value));
+ Process::ProcessEventData::AddRestartedReason(event_ptr,
+ strm.GetData());
+ }
+ return should_notify;
+ }
+ return true;
+ }
+
+ void WillResume(lldb::StateType resume_state) override {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ if (!thread_sp->GetProcess()->GetUnixSignals()->GetShouldSuppress(
+ m_value))
+ thread_sp->SetResumeSignal(m_value);
+ }
+ }
+
+ const char *GetDescription() override {
+ if (m_description.empty()) {
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp) {
+ StreamString strm;
+ const char *signal_name =
+ thread_sp->GetProcess()->GetUnixSignals()->GetSignalAsCString(
+ m_value);
+ if (signal_name)
+ strm.Printf("signal %s", signal_name);
+ else
+ strm.Printf("signal %" PRIi64, m_value);
+ m_description.swap(strm.GetString());
+ }
}
+ return m_description.c_str();
+ }
};
//----------------------------------------------------------------------
// StopInfoTrace
//----------------------------------------------------------------------
-class StopInfoTrace : public StopInfo
-{
+class StopInfoTrace : public StopInfo {
public:
- StopInfoTrace (Thread &thread) :
- StopInfo (thread, LLDB_INVALID_UID)
- {
- }
+ StopInfoTrace(Thread &thread) : StopInfo(thread, LLDB_INVALID_UID) {}
- ~StopInfoTrace() override = default;
+ ~StopInfoTrace() override = default;
- StopReason
- GetStopReason() const override
- {
- return eStopReasonTrace;
- }
+ StopReason GetStopReason() const override { return eStopReasonTrace; }
- const char *
- GetDescription() override
- {
- if (m_description.empty())
- return "trace";
- else
- return m_description.c_str();
- }
+ const char *GetDescription() override {
+ if (m_description.empty())
+ return "trace";
+ else
+ return m_description.c_str();
+ }
};
//----------------------------------------------------------------------
// StopInfoException
//----------------------------------------------------------------------
-class StopInfoException : public StopInfo
-{
+class StopInfoException : public StopInfo {
public:
- StopInfoException (Thread &thread, const char *description) :
- StopInfo (thread, LLDB_INVALID_UID)
- {
- if (description)
- SetDescription (description);
- }
-
- ~StopInfoException() override = default;
-
- StopReason
- GetStopReason() const override
- {
- return eStopReasonException;
- }
-
- const char *
- GetDescription() override
- {
- if (m_description.empty())
- return "exception";
- else
- return m_description.c_str();
- }
+ StopInfoException(Thread &thread, const char *description)
+ : StopInfo(thread, LLDB_INVALID_UID) {
+ if (description)
+ SetDescription(description);
+ }
+
+ ~StopInfoException() override = default;
+
+ StopReason GetStopReason() const override { return eStopReasonException; }
+
+ const char *GetDescription() override {
+ if (m_description.empty())
+ return "exception";
+ else
+ return m_description.c_str();
+ }
};
//----------------------------------------------------------------------
// StopInfoThreadPlan
//----------------------------------------------------------------------
-class StopInfoThreadPlan : public StopInfo
-{
+class StopInfoThreadPlan : public StopInfo {
public:
- StopInfoThreadPlan (ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp, ExpressionVariableSP &expression_variable_sp) :
- StopInfo (plan_sp->GetThread(), LLDB_INVALID_UID),
- m_plan_sp (plan_sp),
- m_return_valobj_sp (return_valobj_sp),
- m_expression_variable_sp (expression_variable_sp)
- {
- }
-
- ~StopInfoThreadPlan() override = default;
-
- StopReason
- GetStopReason() const override
- {
- return eStopReasonPlanComplete;
- }
+ StopInfoThreadPlan(ThreadPlanSP &plan_sp, ValueObjectSP &return_valobj_sp,
+ ExpressionVariableSP &expression_variable_sp)
+ : StopInfo(plan_sp->GetThread(), LLDB_INVALID_UID), m_plan_sp(plan_sp),
+ m_return_valobj_sp(return_valobj_sp),
+ m_expression_variable_sp(expression_variable_sp) {}
+
+ ~StopInfoThreadPlan() override = default;
+
+ StopReason GetStopReason() const override { return eStopReasonPlanComplete; }
+
+ const char *GetDescription() override {
+ if (m_description.empty()) {
+ StreamString strm;
+ m_plan_sp->GetDescription(&strm, eDescriptionLevelBrief);
+ m_description.swap(strm.GetString());
+ }
+ return m_description.c_str();
+ }
+
+ ValueObjectSP GetReturnValueObject() { return m_return_valobj_sp; }
+
+ ExpressionVariableSP GetExpressionVariable() {
+ return m_expression_variable_sp;
+ }
- const char *
- GetDescription() override
- {
- if (m_description.empty())
- {
- StreamString strm;
- m_plan_sp->GetDescription (&strm, eDescriptionLevelBrief);
- m_description.swap (strm.GetString());
- }
- return m_description.c_str();
- }
-
- ValueObjectSP
- GetReturnValueObject()
- {
- return m_return_valobj_sp;
- }
-
- ExpressionVariableSP
- GetExpressionVariable()
- {
- return m_expression_variable_sp;
- }
-
protected:
- bool
- ShouldStop(Event *event_ptr) override
- {
- if (m_plan_sp)
- return m_plan_sp->ShouldStop(event_ptr);
- else
- return StopInfo::ShouldStop(event_ptr);
- }
+ bool ShouldStop(Event *event_ptr) override {
+ if (m_plan_sp)
+ return m_plan_sp->ShouldStop(event_ptr);
+ else
+ return StopInfo::ShouldStop(event_ptr);
+ }
private:
- ThreadPlanSP m_plan_sp;
- ValueObjectSP m_return_valobj_sp;
- ExpressionVariableSP m_expression_variable_sp;
+ ThreadPlanSP m_plan_sp;
+ ValueObjectSP m_return_valobj_sp;
+ ExpressionVariableSP m_expression_variable_sp;
};
-
-class StopInfoExec : public StopInfo
-{
+
+class StopInfoExec : public StopInfo {
public:
- StopInfoExec (Thread &thread) :
- StopInfo (thread, LLDB_INVALID_UID),
- m_performed_action (false)
- {
- }
+ StopInfoExec(Thread &thread)
+ : StopInfo(thread, LLDB_INVALID_UID), m_performed_action(false) {}
- ~StopInfoExec() override = default;
+ ~StopInfoExec() override = default;
- StopReason
- GetStopReason() const override
- {
- return eStopReasonExec;
- }
-
- const char *
- GetDescription() override
- {
- return "exec";
- }
+ StopReason GetStopReason() const override { return eStopReasonExec; }
+
+ const char *GetDescription() override { return "exec"; }
protected:
- void
- PerformAction(Event *event_ptr) override
- {
- // Only perform the action once
- if (m_performed_action)
- return;
- m_performed_action = true;
- ThreadSP thread_sp (m_thread_wp.lock());
- if (thread_sp)
- thread_sp->GetProcess()->DidExec();
- }
-
- bool m_performed_action;
+ void PerformAction(Event *event_ptr) override {
+ // Only perform the action once
+ if (m_performed_action)
+ return;
+ m_performed_action = true;
+ ThreadSP thread_sp(m_thread_wp.lock());
+ if (thread_sp)
+ thread_sp->GetProcess()->DidExec();
+ }
+
+ bool m_performed_action;
};
} // namespace lldb_private
-StopInfoSP
-StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id)
-{
- return StopInfoSP (new StopInfoBreakpoint (thread, break_id));
+StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
+ break_id_t break_id) {
+ return StopInfoSP(new StopInfoBreakpoint(thread, break_id));
}
-StopInfoSP
-StopInfo::CreateStopReasonWithBreakpointSiteID (Thread &thread, break_id_t break_id, bool should_stop)
-{
- return StopInfoSP (new StopInfoBreakpoint (thread, break_id, should_stop));
+StopInfoSP StopInfo::CreateStopReasonWithBreakpointSiteID(Thread &thread,
+ break_id_t break_id,
+ bool should_stop) {
+ return StopInfoSP(new StopInfoBreakpoint(thread, break_id, should_stop));
}
StopInfoSP
-StopInfo::CreateStopReasonWithWatchpointID (Thread &thread, break_id_t watch_id, lldb::addr_t watch_hit_addr)
-{
- return StopInfoSP (new StopInfoWatchpoint (thread, watch_id, watch_hit_addr));
+StopInfo::CreateStopReasonWithWatchpointID(Thread &thread, break_id_t watch_id,
+ lldb::addr_t watch_hit_addr) {
+ return StopInfoSP(new StopInfoWatchpoint(thread, watch_id, watch_hit_addr));
}
-StopInfoSP
-StopInfo::CreateStopReasonWithSignal (Thread &thread, int signo, const char *description)
-{
- return StopInfoSP (new StopInfoUnixSignal (thread, signo, description));
+StopInfoSP StopInfo::CreateStopReasonWithSignal(Thread &thread, int signo,
+ const char *description) {
+ return StopInfoSP(new StopInfoUnixSignal(thread, signo, description));
}
-StopInfoSP
-StopInfo::CreateStopReasonToTrace (Thread &thread)
-{
- return StopInfoSP (new StopInfoTrace (thread));
+StopInfoSP StopInfo::CreateStopReasonToTrace(Thread &thread) {
+ return StopInfoSP(new StopInfoTrace(thread));
}
-StopInfoSP
-StopInfo::CreateStopReasonWithPlan (ThreadPlanSP &plan_sp,
- ValueObjectSP return_valobj_sp,
- ExpressionVariableSP expression_variable_sp)
-{
- return StopInfoSP (new StopInfoThreadPlan (plan_sp, return_valobj_sp, expression_variable_sp));
+StopInfoSP StopInfo::CreateStopReasonWithPlan(
+ ThreadPlanSP &plan_sp, ValueObjectSP return_valobj_sp,
+ ExpressionVariableSP expression_variable_sp) {
+ return StopInfoSP(new StopInfoThreadPlan(plan_sp, return_valobj_sp,
+ expression_variable_sp));
}
-StopInfoSP
-StopInfo::CreateStopReasonWithException (Thread &thread, const char *description)
-{
- return StopInfoSP (new StopInfoException (thread, description));
+StopInfoSP StopInfo::CreateStopReasonWithException(Thread &thread,
+ const char *description) {
+ return StopInfoSP(new StopInfoException(thread, description));
}
-StopInfoSP
-StopInfo::CreateStopReasonWithExec (Thread &thread)
-{
- return StopInfoSP (new StopInfoExec (thread));
+StopInfoSP StopInfo::CreateStopReasonWithExec(Thread &thread) {
+ return StopInfoSP(new StopInfoExec(thread));
}
-ValueObjectSP
-StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp)
-{
- if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete)
- {
- StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
- return plan_stop_info->GetReturnValueObject();
- }
- else
- return ValueObjectSP();
+ValueObjectSP StopInfo::GetReturnValueObject(StopInfoSP &stop_info_sp) {
+ if (stop_info_sp &&
+ stop_info_sp->GetStopReason() == eStopReasonPlanComplete) {
+ StopInfoThreadPlan *plan_stop_info =
+ static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
+ return plan_stop_info->GetReturnValueObject();
+ } else
+ return ValueObjectSP();
}
-ExpressionVariableSP
-StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp)
-{
- if (stop_info_sp && stop_info_sp->GetStopReason() == eStopReasonPlanComplete)
- {
- StopInfoThreadPlan *plan_stop_info = static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
- return plan_stop_info->GetExpressionVariable();
- }
- else
- return ExpressionVariableSP();
+ExpressionVariableSP StopInfo::GetExpressionVariable(StopInfoSP &stop_info_sp) {
+ if (stop_info_sp &&
+ stop_info_sp->GetStopReason() == eStopReasonPlanComplete) {
+ StopInfoThreadPlan *plan_stop_info =
+ static_cast<StopInfoThreadPlan *>(stop_info_sp.get());
+ return plan_stop_info->GetExpressionVariable();
+ } else
+ return ExpressionVariableSP();
}
lldb::ValueObjectSP
-StopInfo::GetCrashingDereference (StopInfoSP &stop_info_sp, lldb::addr_t *crashing_address)
-{
- if (!stop_info_sp)
- {
- return ValueObjectSP();
- }
-
- const char *description = stop_info_sp->GetDescription();
- if (!description)
- {
- return ValueObjectSP();
- }
-
- ThreadSP thread_sp = stop_info_sp->GetThread();
- if (!thread_sp)
- {
- return ValueObjectSP();
- }
-
- StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
-
- if (!frame_sp)
- {
- return ValueObjectSP();
- }
+StopInfo::GetCrashingDereference(StopInfoSP &stop_info_sp,
+ lldb::addr_t *crashing_address) {
+ if (!stop_info_sp) {
+ return ValueObjectSP();
+ }
+
+ const char *description = stop_info_sp->GetDescription();
+ if (!description) {
+ return ValueObjectSP();
+ }
+
+ ThreadSP thread_sp = stop_info_sp->GetThread();
+ if (!thread_sp) {
+ return ValueObjectSP();
+ }
+
+ StackFrameSP frame_sp = thread_sp->GetSelectedFrame();
+
+ if (!frame_sp) {
+ return ValueObjectSP();
+ }
+
+ const char address_string[] = "address=";
+
+ const char *address_loc = strstr(description, address_string);
+ if (!address_loc) {
+ return ValueObjectSP();
+ }
+
+ address_loc += (sizeof(address_string) - 1);
+
+ uint64_t address = strtoull(address_loc, 0, 0);
+ if (crashing_address) {
+ *crashing_address = address;
+ }
- const char address_string[] = "address=";
-
- const char *address_loc = strstr(description, address_string);
- if (!address_loc)
- {
- return ValueObjectSP();
- }
-
- address_loc += (sizeof(address_string) - 1);
-
- uint64_t address = strtoull(address_loc, 0, 0);
- if (crashing_address)
- {
- *crashing_address = address;
- }
-
- return frame_sp->GuessValueForAddress(address);
+ return frame_sp->GuessValueForAddress(address);
}
Modified: lldb/trunk/source/Target/StructuredDataPlugin.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/StructuredDataPlugin.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/StructuredDataPlugin.cpp (original)
+++ lldb/trunk/source/Target/StructuredDataPlugin.cpp Tue Sep 6 15:57:50 2016
@@ -16,75 +16,53 @@
using namespace lldb;
using namespace lldb_private;
-namespace
-{
- class CommandStructuredData : public CommandObjectMultiword
- {
- public:
- CommandStructuredData(CommandInterpreter &interpreter) :
- CommandObjectMultiword(interpreter,
- "structured-data",
+namespace {
+class CommandStructuredData : public CommandObjectMultiword {
+public:
+ CommandStructuredData(CommandInterpreter &interpreter)
+ : CommandObjectMultiword(interpreter, "structured-data",
"Parent for per-plugin structured data commands",
- "plugin structured-data <plugin>")
- {
- }
-
- ~CommandStructuredData()
- {
- }
- };
-}
+ "plugin structured-data <plugin>") {}
-StructuredDataPlugin::StructuredDataPlugin(const ProcessWP &process_wp) :
- PluginInterface(),
- m_process_wp(process_wp)
-{
+ ~CommandStructuredData() {}
+};
}
-StructuredDataPlugin::~StructuredDataPlugin()
-{
-}
+StructuredDataPlugin::StructuredDataPlugin(const ProcessWP &process_wp)
+ : PluginInterface(), m_process_wp(process_wp) {}
+
+StructuredDataPlugin::~StructuredDataPlugin() {}
-bool
-StructuredDataPlugin::GetEnabled(const ConstString &type_name) const
-{
- // By default, plugins are always enabled. Plugin authors should override
- // this if there is an enabled/disabled state for their plugin.
- return true;
+bool StructuredDataPlugin::GetEnabled(const ConstString &type_name) const {
+ // By default, plugins are always enabled. Plugin authors should override
+ // this if there is an enabled/disabled state for their plugin.
+ return true;
}
-ProcessSP
-StructuredDataPlugin::GetProcess() const
-{
- return m_process_wp.lock();
+ProcessSP StructuredDataPlugin::GetProcess() const {
+ return m_process_wp.lock();
}
-void
-StructuredDataPlugin::InitializeBasePluginForDebugger(Debugger &debugger)
-{
- // Create our mutliword command anchor if it doesn't already exist.
- auto &interpreter = debugger.GetCommandInterpreter();
- if (!interpreter.GetCommandObject("plugin structured-data"))
- {
- // Find the parent command.
- auto parent_command =
- debugger.GetCommandInterpreter().GetCommandObject("plugin");
- if (!parent_command)
- return;
-
- // Create the structured-data ommand object.
- auto command_name = "structured-data";
- auto command_sp =
- CommandObjectSP(new CommandStructuredData(interpreter));
-
- // Hook it up under the top-level plugin command.
- parent_command->LoadSubCommand(command_name,
- command_sp);
- }
+void StructuredDataPlugin::InitializeBasePluginForDebugger(Debugger &debugger) {
+ // Create our mutliword command anchor if it doesn't already exist.
+ auto &interpreter = debugger.GetCommandInterpreter();
+ if (!interpreter.GetCommandObject("plugin structured-data")) {
+ // Find the parent command.
+ auto parent_command =
+ debugger.GetCommandInterpreter().GetCommandObject("plugin");
+ if (!parent_command)
+ return;
+
+ // Create the structured-data ommand object.
+ auto command_name = "structured-data";
+ auto command_sp = CommandObjectSP(new CommandStructuredData(interpreter));
+
+ // Hook it up under the top-level plugin command.
+ parent_command->LoadSubCommand(command_name, command_sp);
+ }
}
-void
-StructuredDataPlugin::ModulesDidLoad(Process &process, ModuleList &module_list)
-{
- // Default implementation does nothing.
+void StructuredDataPlugin::ModulesDidLoad(Process &process,
+ ModuleList &module_list) {
+ // Default implementation does nothing.
}
Modified: lldb/trunk/source/Target/SystemRuntime.cpp
URL: http://llvm.org/viewvc/llvm-project/lldb/trunk/source/Target/SystemRuntime.cpp?rev=280751&r1=280750&r2=280751&view=diff
==============================================================================
--- lldb/trunk/source/Target/SystemRuntime.cpp (original)
+++ lldb/trunk/source/Target/SystemRuntime.cpp Tue Sep 6 15:57:50 2016
@@ -11,66 +11,48 @@
// C++ Includes
// Other libraries and framework includes
// Project includes
-#include "lldb/lldb-private.h"
#include "lldb/Target/SystemRuntime.h"
-#include "lldb/Target/Process.h"
#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/Process.h"
+#include "lldb/lldb-private.h"
using namespace lldb;
using namespace lldb_private;
-SystemRuntime*
-SystemRuntime::FindPlugin (Process *process)
-{
- SystemRuntimeCreateInstance create_callback = nullptr;
- for (uint32_t idx = 0; (create_callback = PluginManager::GetSystemRuntimeCreateCallbackAtIndex(idx)) != nullptr; ++idx)
- {
- std::unique_ptr<SystemRuntime> instance_ap(create_callback(process));
- if (instance_ap)
- return instance_ap.release();
- }
- return nullptr;
+SystemRuntime *SystemRuntime::FindPlugin(Process *process) {
+ SystemRuntimeCreateInstance create_callback = nullptr;
+ for (uint32_t idx = 0;
+ (create_callback = PluginManager::GetSystemRuntimeCreateCallbackAtIndex(
+ idx)) != nullptr;
+ ++idx) {
+ std::unique_ptr<SystemRuntime> instance_ap(create_callback(process));
+ if (instance_ap)
+ return instance_ap.release();
+ }
+ return nullptr;
}
//----------------------------------------------------------------------
// SystemRuntime constructor
//----------------------------------------------------------------------
-SystemRuntime::SystemRuntime(Process *process) :
- m_process (process),
- m_types ()
-{
-}
+SystemRuntime::SystemRuntime(Process *process)
+ : m_process(process), m_types() {}
SystemRuntime::~SystemRuntime() = default;
-void
-SystemRuntime::DidAttach ()
-{
-}
+void SystemRuntime::DidAttach() {}
-void
-SystemRuntime::DidLaunch()
-{
-}
+void SystemRuntime::DidLaunch() {}
-void
-SystemRuntime::Detach()
-{
-}
+void SystemRuntime::Detach() {}
-void
-SystemRuntime::ModulesDidLoad (ModuleList &module_list)
-{
-}
+void SystemRuntime::ModulesDidLoad(ModuleList &module_list) {}
-const std::vector<ConstString> &
-SystemRuntime::GetExtendedBacktraceTypes ()
-{
- return m_types;
+const std::vector<ConstString> &SystemRuntime::GetExtendedBacktraceTypes() {
+ return m_types;
}
-ThreadSP
-SystemRuntime::GetExtendedBacktraceThread (ThreadSP thread, ConstString type)
-{
- return ThreadSP();
+ThreadSP SystemRuntime::GetExtendedBacktraceThread(ThreadSP thread,
+ ConstString type) {
+ return ThreadSP();
}
More information about the lldb-commits
mailing list