aboutsummaryrefslogtreecommitdiff
path: root/source/Target/Process.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'source/Target/Process.cpp')
-rw-r--r--source/Target/Process.cpp570
1 files changed, 368 insertions, 202 deletions
diff --git a/source/Target/Process.cpp b/source/Target/Process.cpp
index f7a26f676aba..41942829ca55 100644
--- a/source/Target/Process.cpp
+++ b/source/Target/Process.cpp
@@ -7,22 +7,19 @@
//
//===----------------------------------------------------------------------===//
-#include "lldb/lldb-python.h"
-
#include "lldb/Target/Process.h"
-
-#include "lldb/lldb-private-log.h"
-
#include "lldb/Breakpoint/StoppointCallbackContext.h"
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Event.h"
#include "lldb/Core/Debugger.h"
#include "lldb/Core/Log.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/ModuleSpec.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/State.h"
#include "lldb/Core/StreamFile.h"
#include "lldb/Expression/ClangUserExpression.h"
+#include "lldb/Expression/IRDynamicChecks.h"
#include "lldb/Host/ConnectionFileDescriptor.h"
#include "lldb/Host/Host.h"
#include "lldb/Host/HostInfo.h"
@@ -30,11 +27,15 @@
#include "lldb/Host/Terminal.h"
#include "lldb/Host/ThreadLauncher.h"
#include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionValueProperties.h"
#include "lldb/Symbol/Symbol.h"
#include "lldb/Target/ABI.h"
#include "lldb/Target/DynamicLoader.h"
+#include "lldb/Target/InstrumentationRuntime.h"
#include "lldb/Target/JITLoader.h"
+#include "lldb/Target/JITLoaderList.h"
#include "lldb/Target/MemoryHistory.h"
+#include "lldb/Target/MemoryRegionInfo.h"
#include "lldb/Target/OperatingSystem.h"
#include "lldb/Target/LanguageRuntime.h"
#include "lldb/Target/CPPLanguageRuntime.h"
@@ -48,7 +49,8 @@
#include "lldb/Target/Thread.h"
#include "lldb/Target/ThreadPlan.h"
#include "lldb/Target/ThreadPlanBase.h"
-#include "lldb/Target/InstrumentationRuntime.h"
+#include "lldb/Target/UnixSignals.h"
+#include "lldb/Utility/NameMatches.h"
#include "Plugins/Process/Utility/InferiorCallPOSIX.h"
using namespace lldb;
@@ -430,7 +432,7 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'i': // STDIN for read only
{
FileAction action;
- if (action.Open (STDIN_FILENO, option_arg, true, false))
+ if (action.Open(STDIN_FILENO, FileSpec{option_arg, false}, true, false))
launch_info.AppendFileAction (action);
break;
}
@@ -438,7 +440,7 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'o': // Open STDOUT for write only
{
FileAction action;
- if (action.Open (STDOUT_FILENO, option_arg, false, true))
+ if (action.Open(STDOUT_FILENO, FileSpec{option_arg, false}, false, true))
launch_info.AppendFileAction (action);
break;
}
@@ -446,7 +448,7 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'e': // STDERR for write only
{
FileAction action;
- if (action.Open (STDERR_FILENO, option_arg, false, true))
+ if (action.Open(STDERR_FILENO, FileSpec{option_arg, false}, false, true))
launch_info.AppendFileAction (action);
break;
}
@@ -458,17 +460,18 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
case 'n': // Disable STDIO
{
FileAction action;
- if (action.Open (STDIN_FILENO, "/dev/null", true, false))
+ const FileSpec dev_null{"/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))
+ if (action.Open(STDOUT_FILENO, dev_null, false, true))
launch_info.AppendFileAction (action);
- if (action.Open (STDERR_FILENO, "/dev/null", false, true))
+ if (action.Open(STDERR_FILENO, dev_null, false, true))
launch_info.AppendFileAction (action);
break;
}
case 'w':
- launch_info.SetWorkingDirectory (option_arg);
+ launch_info.SetWorkingDirectory(FileSpec{option_arg, false});
break;
case 't': // Open process in new terminal window
@@ -491,6 +494,17 @@ ProcessLaunchCommandOptions::SetOptionValue (uint32_t option_idx, const char *op
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));
@@ -518,7 +532,7 @@ ProcessLaunchCommandOptions::g_option_table[] =
{ LLDB_OPT_SET_ALL, false, "working-dir", 'w', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeDirectoryName, "Set the current working directory to <path> when running the inferior."},
{ LLDB_OPT_SET_ALL, false, "arch", 'a', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeArchitecture, "Set the architecture for the process to launch when ambiguous."},
{ LLDB_OPT_SET_ALL, false, "environment", 'v', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeNone, "Specify an environment variable name/value string (--environment NAME=VALUE). Can be specified multiple times for subsequent environment entries."},
-{ LLDB_OPT_SET_ALL, false, "shell", 'c', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
+{ LLDB_OPT_SET_1|LLDB_OPT_SET_2|LLDB_OPT_SET_3, false, "shell", 'c', OptionParser::eOptionalArgument, NULL, NULL, 0, eArgTypeFilename, "Run the process in a shell (not supported on all platforms)."},
{ LLDB_OPT_SET_1 , false, "stdin", 'i', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stdin for the process to <filename>."},
{ LLDB_OPT_SET_1 , false, "stdout", 'o', OptionParser::eRequiredArgument, NULL, NULL, 0, eArgTypeFilename, "Redirect stdout for the process to <filename>."},
@@ -527,7 +541,7 @@ ProcessLaunchCommandOptions::g_option_table[] =
{ LLDB_OPT_SET_2 , false, "tty", 't', OptionParser::eNoArgument, NULL, NULL, 0, eArgTypeNone, "Start the process in a terminal (not supported on all platforms)."},
{ LLDB_OPT_SET_3 , false, "no-stdio", 'n', OptionParser::eNoArgument, NULL, NULL, 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, NULL, NULL, 0, eArgTypeBoolean, "Set whether to shell expand arguments to the process when launching."},
{ 0 , false, NULL, 0, 0, NULL, NULL, 0, eArgTypeNone, NULL }
};
@@ -688,7 +702,7 @@ Process::Process(Target &target, Listener &listener) :
Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_signals_sp) :
ProcessProperties (this),
UserID (LLDB_INVALID_PROCESS_ID),
- Broadcaster (&(target.GetDebugger()), "lldb.process"),
+ Broadcaster (&(target.GetDebugger()), Process::GetStaticBroadcasterClass().AsCString()),
m_target (target),
m_public_state (eStateUnloaded),
m_private_state (eStateUnloaded),
@@ -720,12 +734,12 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_process_input_reader (),
m_stdio_communication ("process.stdio"),
m_stdio_communication_mutex (Mutex::eMutexTypeRecursive),
- m_stdio_disable(true),
+ m_stdin_forward (false),
m_stdout_data (),
m_stderr_data (),
m_profile_data_comm_mutex (Mutex::eMutexTypeRecursive),
m_profile_data (),
- m_iohandler_sync (false),
+ m_iohandler_sync (0),
m_memory_cache (*this),
m_allocated_memory_cache (*this),
m_should_detach (false),
@@ -734,9 +748,10 @@ Process::Process(Target &target, Listener &listener, const UnixSignalsSP &unix_s
m_private_run_lock (),
m_currently_handling_event(false),
m_stop_info_override_callback (NULL),
- m_finalize_called(false),
+ m_finalizing (false),
+ m_finalize_called (false),
m_clear_thread_plans_on_stop (false),
- m_force_next_event_delivery(false),
+ m_force_next_event_delivery (false),
m_last_broadcast_state (eStateInvalid),
m_destroy_in_process (false),
m_can_jit(eCanJITDontKnow)
@@ -807,6 +822,9 @@ Process::GetGlobalProperties()
void
Process::Finalize()
{
+ m_finalizing = true;
+
+ // Destroy this process if needed
switch (GetPrivateState())
{
case eStateConnected:
@@ -817,14 +835,7 @@ Process::Finalize()
case eStateStepping:
case eStateCrashed:
case eStateSuspended:
- if (GetShouldDetach())
- {
- // FIXME: This will have to be a process setting:
- bool keep_stopped = false;
- Detach(keep_stopped);
- }
- else
- Destroy();
+ Destroy(false);
break;
case eStateInvalid:
@@ -862,6 +873,9 @@ Process::Finalize()
m_instrumentation_runtimes.clear();
m_next_event_action_ap.reset();
m_stop_info_override_callback = NULL;
+ // 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;
@@ -937,33 +951,21 @@ Process::GetNextEvent (EventSP &event_sp)
return state;
}
-bool
-Process::SyncIOHandler (uint64_t timeout_msec)
+void
+Process::SyncIOHandler (uint32_t iohandler_id, uint64_t timeout_msec)
{
- bool timed_out = false;
-
// don't sync (potentially context switch) in case where there is no process IO
- if (m_process_input_reader)
- {
- TimeValue timeout = TimeValue::Now();
- timeout.OffsetWithMicroSeconds(timeout_msec*1000);
-
- m_iohandler_sync.WaitForValueEqualTo(true, &timeout, &timed_out);
-
- Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
- if(log)
- {
- if(timed_out)
- log->Printf ("Process::%s pid %" PRIu64 " (timeout=%" PRIu64 "ms): FAIL", __FUNCTION__, GetID (), timeout_msec);
- else
- log->Printf ("Process::%s pid %" PRIu64 ": SUCCESS", __FUNCTION__, GetID ());
- }
+ if (! m_process_input_reader)
+ return;
- // reset sync one-shot so it will be ready for next launch
- m_iohandler_sync.SetValue(false, eBroadcastNever);
- }
+ TimeValue timeout = TimeValue::Now();
+ timeout.OffsetWithMicroSeconds(timeout_msec*1000);
+ uint32_t new_iohandler_id = 0;
+ m_iohandler_sync.WaitForValueNotEqualTo(iohandler_id, new_iohandler_id, &timeout);
- return !timed_out;
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s waited for m_iohandler_sync to change from %u, new value is %u", __FUNCTION__, iohandler_id, new_iohandler_id);
}
StateType
@@ -991,10 +993,15 @@ Process::WaitForProcessToStop (const TimeValue *timeout,
if (!wait_always &&
StateIsStoppedState(state, true) &&
- StateIsStoppedState(GetPrivateState(), 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)
+ m_public_run_lock.SetStopped();
return state;
}
@@ -1422,6 +1429,9 @@ Process::GetExitDescription ()
bool
Process::SetExitStatus (int status, const char *cstr)
{
+ // Use a mutex to protect setting the exit status.
+ Mutex::Locker locker (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)",
@@ -1437,21 +1447,35 @@ Process::SetExitStatus (int status, const char *cstr)
log->Printf("Process::SetExitStatus () ignoring exit status because state was already set to eStateExited");
return false;
}
-
- // use a mutex to protect the status and string during updating
- {
- Mutex::Locker locker (m_exit_status_mutex);
- m_exit_status = status;
- if (cstr)
- m_exit_string = cstr;
- else
- m_exit_string.clear();
+ m_exit_status = status;
+ if (cstr)
+ m_exit_string = cstr;
+ else
+ m_exit_string.clear();
+
+ // When we exit, we no longer need to the communication channel
+ m_stdio_communication.Disconnect();
+ m_stdio_communication.StopReadThread();
+ m_stdin_forward = false;
+
+ // And we don't need the input reader anymore as well
+ if (m_process_input_reader)
+ {
+ m_process_input_reader->SetIsDone(true);
+ m_process_input_reader->Cancel();
+ m_process_input_reader.reset();
}
- DidExit ();
+ // 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;
}
@@ -1531,10 +1555,24 @@ Process::UpdateThreadListIfNeeded ()
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
{
@@ -1714,15 +1752,17 @@ Process::ResumeSynchronous (Stream *stream)
HijackProcessEvents(listener_sp.get());
Error error = PrivateResume();
-
- StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), stream);
+ if (error.Success())
+ {
+ StateType state = WaitForProcessToStop (NULL, NULL, true, listener_sp.get(), 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();
- if (error.Success() && !StateIsStoppedState(state, false))
- error.SetErrorStringWithFormat("process not in stopped state after synchronous resume: %s", StateAsCString(state));
-
return error;
}
@@ -1763,6 +1803,7 @@ Process::SetPrivateState (StateType new_state)
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
@@ -1779,15 +1820,18 @@ Process::SetPrivateState (StateType new_state)
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() == false)
- BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state));
+ BroadcastEvent (event_sp);
else
- m_private_state_broadcaster.BroadcastEvent (eBroadcastBitStateChanged, new ProcessEventData (shared_from_this(), new_state));
+ m_private_state_broadcaster.BroadcastEvent (event_sp);
}
else
{
@@ -1819,6 +1863,12 @@ Process::GetImageInfoAddress()
uint32_t
Process::LoadImage (const FileSpec &image_spec, Error &error)
{
+ if (m_finalizing)
+ {
+ error.SetErrorString("process is tearing itself down");
+ return LLDB_INVALID_IMAGE_TOKEN;
+ }
+
char path[PATH_MAX];
image_spec.GetPath(path, sizeof(path));
@@ -1938,6 +1988,13 @@ Error
Process::UnloadImage (uint32_t image_token)
{
Error error;
+
+ if (m_finalizing)
+ {
+ error.SetErrorString("process is tearing itself down");
+ return error;
+ }
+
if (image_token < m_image_tokens.size())
{
const addr_t image_addr = m_image_tokens[image_token];
@@ -2020,6 +2077,9 @@ Process::GetABI()
LanguageRuntime *
Process::GetLanguageRuntime(lldb::LanguageType language, bool retry_if_null)
{
+ if (m_finalizing)
+ return nullptr;
+
LanguageRuntimeCollection::iterator pos;
pos = m_language_runtimes.find (language);
if (pos == m_language_runtimes.end() || (retry_if_null && !(*pos).second))
@@ -2054,6 +2114,9 @@ Process::GetObjCLanguageRuntime (bool retry_if_null)
bool
Process::IsPossibleDynamicValue (ValueObject& in_value)
{
+ if (m_finalizing)
+ return false;
+
if (in_value.IsDynamic())
return false;
LanguageType known_type = in_value.GetObjectRuntimeLanguage();
@@ -2072,6 +2135,12 @@ Process::IsPossibleDynamicValue (ValueObject& in_value)
return objc_runtime ? objc_runtime->CouldHaveDynamicValue(in_value) : false;
}
+void
+Process::SetDynamicCheckers(DynamicCheckerFunctions *dynamic_checkers)
+{
+ m_dynamic_checkers_ap.reset(dynamic_checkers);
+}
+
BreakpointSiteList &
Process::GetBreakpointSiteList()
{
@@ -2177,11 +2246,12 @@ Process::CreateBreakpointSite (const BreakpointLocationSP &owner, bool use_hardw
if (symbol && symbol->IsIndirect())
{
Error error;
- load_addr = ResolveIndirectFunction (&symbol->GetAddress(), error);
+ Address symbol_address = symbol->GetAddress();
+ load_addr = ResolveIndirectFunction (&symbol_address, error);
if (!error.Success() && show_error)
{
m_target.GetDebugger().GetErrorFile()->Printf ("warning: failed to resolve indirect function at 0x%" PRIx64 " for breakpoint %i.%i: %s\n",
- symbol->GetAddress().GetLoadAddress(&m_target),
+ symbol->GetLoadAddress(&m_target),
owner->GetBreakpoint().GetID(),
owner->GetID(),
error.AsCString() ? error.AsCString() : "unknown error");
@@ -2403,7 +2473,7 @@ Process::DisableSoftwareBreakpoint (BreakpointSite *bp_site)
if (DoReadMemory (bp_addr, curr_break_op, break_op_size, error) == break_op_size)
{
bool verify = false;
- // Make sure we have the a breakpoint opcode exists at this address
+ // Make sure the breakpoint opcode exists at this address
if (::memcmp (curr_break_op, break_op, break_op_size) == 0)
{
break_op_found = true;
@@ -2968,6 +3038,33 @@ Process::ReadModuleFromMemory (const FileSpec& file_spec,
return ModuleSP();
}
+bool
+Process::GetLoadAddressPermissions (lldb::addr_t load_addr, uint32_t &permissions)
+{
+ MemoryRegionInfo range_info;
+ permissions = 0;
+ Error error (GetMemoryRegionInfo (load_addr, range_info));
+ if (!error.Success())
+ return false;
+ if (range_info.GetReadable() == MemoryRegionInfo::eDontKnow
+ || range_info.GetWritable() == MemoryRegionInfo::eDontKnow
+ || range_info.GetExecutable() == MemoryRegionInfo::eDontKnow)
+ {
+ return false;
+ }
+
+ if (range_info.GetReadable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsReadable;
+
+ if (range_info.GetWritable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsWritable;
+
+ if (range_info.GetExecutable() == MemoryRegionInfo::eYes)
+ permissions |= lldb::ePermissionsExecutable;
+
+ return true;
+}
+
Error
Process::EnableWatchpoint (Watchpoint *watchpoint, bool notify)
{
@@ -3090,8 +3187,9 @@ Process::Launch (ProcessLaunchInfo &launch_info)
{
// 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();
+ Destroy(false);
}
else if (state == eStateStopped || state == eStateCrashed)
{
@@ -3125,7 +3223,7 @@ Process::Launch (ProcessLaunchInfo &launch_info)
// Target was stopped at entry as was intended. Need to notify the listeners
// about it.
- if (launch_info.GetFlags().Test(eLaunchFlagStopAtEntry) == true)
+ if (state == eStateStopped && launch_info.GetFlags().Test(eLaunchFlagStopAtEntry))
HandlePrivateEvent(event_sp);
}
else if (state == eStateExited)
@@ -3152,6 +3250,9 @@ Process::LoadCore ()
Error error = DoLoadCore();
if (error.Success())
{
+ Listener listener ("lldb.process.load_core_listener");
+ HijackProcessEvents(&listener);
+
if (PrivateStateThreadIsValid ())
ResumePrivateStateThread ();
else
@@ -3172,7 +3273,20 @@ Process::LoadCore ()
// 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.WaitForEvent (NULL, 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 ();
}
return error;
}
@@ -3230,6 +3344,9 @@ Process::AttachCompletionHandler::PerformAction (lldb::EventSP &event_sp)
switch (state)
{
+ case eStateAttaching:
+ return eEventActionSuccess;
+
case eStateRunning:
case eStateConnected:
return eEventActionRetry;
@@ -3702,7 +3819,7 @@ Process::Halt (bool clear_thread_plans)
RestorePrivateProcessEvents();
restored_process_events = true;
SetExitStatus(SIGKILL, "Cancelled async attach.");
- Destroy ();
+ Destroy (false);
}
else
{
@@ -3876,13 +3993,23 @@ Process::Detach (bool keep_stopped)
}
Error
-Process::Destroy ()
+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());
@@ -3910,9 +4037,9 @@ Process::Destroy ()
DidDestroy();
StopPrivateStateThread();
}
- m_stdio_communication.StopReadThread();
m_stdio_communication.Disconnect();
- m_stdio_disable = true;
+ m_stdio_communication.StopReadThread();
+ m_stdin_forward = false;
if (m_process_input_reader)
{
@@ -3954,6 +4081,20 @@ Process::Signal (int signal)
return error;
}
+void
+Process::SetUnixSignals (const UnixSignalsSP &signals_sp)
+{
+ assert (signals_sp && "null signals_sp");
+ m_unix_signals_sp = signals_sp;
+}
+
+UnixSignals &
+Process::GetUnixSignals ()
+{
+ assert (m_unix_signals_sp && "null m_unix_signals_sp");
+ return *m_unix_signals_sp;
+}
+
lldb::ByteOrder
Process::GetByteOrder () const
{
@@ -3976,12 +4117,14 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
switch (state)
{
- case eStateConnected:
- case eStateAttaching:
- case eStateLaunching:
case eStateDetached:
case eStateExited:
case eStateUnloaded:
+ m_stdio_communication.SynchronizeWithReadThread();
+ // fall-through
+ case eStateConnected:
+ case eStateAttaching:
+ case eStateLaunching:
// These events indicate changes in the state of the debugging session, always report them.
return_value = true;
break;
@@ -4041,6 +4184,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
// 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))
{
@@ -4128,7 +4272,7 @@ Process::ShouldBroadcastEvent (Event *event_ptr)
bool
-Process::StartPrivateStateThread (bool force)
+Process::StartPrivateStateThread (bool is_secondary_thread)
{
Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_EVENTS));
@@ -4136,7 +4280,7 @@ Process::StartPrivateStateThread (bool force)
if (log)
log->Printf ("Process::%s()%s ", __FUNCTION__, already_running ? " already running" : " starting private state thread");
- if (!force && already_running)
+ if (!is_secondary_thread && already_running)
return true;
// Create a thread that watches our internal state and controls which
@@ -4160,7 +4304,8 @@ Process::StartPrivateStateThread (bool force)
}
// Create the private state thread, and start it running.
- m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, this, NULL);
+ PrivateStateThreadArgs args = {this, is_secondary_thread};
+ m_private_state_thread = ThreadLauncher::LaunchThread(thread_name, Process::PrivateStateThread, (void *) &args, NULL);
if (m_private_state_thread.IsJoinable())
{
ResumePrivateStateThread();
@@ -4324,13 +4469,17 @@ Process::HandlePrivateEvent (EventSP &event_sp)
// Only push the input handler if we aren't fowarding events,
// as this means the curses GUI is in use...
// Or don't push it if we are launching since it will come up stopped.
- if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching)
+ if (!GetTarget().GetDebugger().IsForwardingEvents() && new_state != eStateLaunching &&
+ new_state != eStateAttaching)
+ {
PushProcessIOHandler ();
- m_iohandler_sync.SetValue(true, eBroadcastAlways);
+ 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))
{
- m_iohandler_sync.SetValue(false, eBroadcastNever);
if (!Process::ProcessEventData::GetRestartedFromEvent(event_sp.get()))
{
// If the lldb_private::Debugger is handling the events, we don't
@@ -4386,13 +4535,13 @@ Process::HandlePrivateEvent (EventSP &event_sp)
thread_result_t
Process::PrivateStateThread (void *arg)
{
- Process *proc = static_cast<Process*> (arg);
- thread_result_t result = proc->RunPrivateStateThread();
+ PrivateStateThreadArgs *real_args = static_cast<PrivateStateThreadArgs *> (arg);
+ thread_result_t result = real_args->process->RunPrivateStateThread(real_args->is_secondary_thread);
return result;
}
thread_result_t
-Process::RunPrivateStateThread ()
+Process::RunPrivateStateThread (bool is_secondary_thread)
{
bool control_only = true;
m_private_state_control_wait.SetValue (false, eBroadcastNever);
@@ -4484,7 +4633,11 @@ Process::RunPrivateStateThread ()
log->Printf ("Process::%s (arg = %p, pid = %" PRIu64 ") thread exiting...",
__FUNCTION__, static_cast<void*>(this), GetID());
- m_public_run_lock.SetStopped();
+ // 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();
m_private_state_control_wait.SetValue (true, eBroadcastAlways);
m_private_state_thread.Reset();
return NULL;
@@ -4496,7 +4649,7 @@ Process::RunPrivateStateThread ()
Process::ProcessEventData::ProcessEventData () :
EventData (),
- m_process_sp (),
+ m_process_wp (),
m_state (eStateInvalid),
m_restarted (false),
m_update_state (0),
@@ -4506,12 +4659,14 @@ Process::ProcessEventData::ProcessEventData () :
Process::ProcessEventData::ProcessEventData (const ProcessSP &process_sp, StateType state) :
EventData (),
- m_process_sp (process_sp),
+ m_process_wp (),
m_state (state),
m_restarted (false),
m_update_state (0),
m_interrupted (false)
{
+ if (process_sp)
+ m_process_wp = process_sp;
}
Process::ProcessEventData::~ProcessEventData()
@@ -4534,6 +4689,11 @@ Process::ProcessEventData::GetFlavor () const
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
@@ -4543,7 +4703,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
if (m_update_state != 1)
return;
- m_process_sp->SetPublicState (m_state, Process::ProcessEventData::GetRestartedFromEvent(event_ptr));
+ 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
@@ -4554,7 +4714,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
// If we're stopped and haven't restarted, then do the StopInfo actions here:
if (m_state == eStateStopped && ! m_restarted)
{
- ThreadList &curr_thread_list = m_process_sp->GetThreadList();
+ ThreadList &curr_thread_list = process_sp->GetThreadList();
uint32_t num_threads = curr_thread_list.GetSize();
uint32_t idx;
@@ -4584,7 +4744,7 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
for (idx = 0; idx < num_threads; ++idx)
{
- curr_thread_list = m_process_sp->GetThreadList();
+ curr_thread_list = process_sp->GetThreadList();
if (curr_thread_list.GetSize() != num_threads)
{
Log *log(lldb_private::GetLogIfAnyCategoriesSet (LIBLLDB_LOG_STEP | LIBLLDB_LOG_PROCESS));
@@ -4647,14 +4807,14 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
SetRestarted(true);
// Use the public resume method here, since this is just
// extending a public resume.
- m_process_sp->PrivateResume();
+ process_sp->PrivateResume();
}
else
{
// If we didn't restart, run the Stop Hooks here:
// They might also restart the target, so watch for that.
- m_process_sp->GetTarget().RunStopHooks();
- if (m_process_sp->GetPrivateState() == eStateRunning)
+ process_sp->GetTarget().RunStopHooks();
+ if (process_sp->GetPrivateState() == eStateRunning)
SetRestarted(true);
}
}
@@ -4664,9 +4824,13 @@ Process::ProcessEventData::DoOnRemoval (Event *event_ptr)
void
Process::ProcessEventData::Dump (Stream *s) const
{
- if (m_process_sp)
+ ProcessSP process_sp(m_process_wp.lock());
+
+ if (process_sp)
s->Printf(" process = %p (pid = %" PRIu64 "), ",
- static_cast<void*>(m_process_sp.get()), m_process_sp->GetID());
+ static_cast<void*>(process_sp.get()), process_sp->GetID());
+ else
+ s->PutCString(" process = NULL, ");
s->Printf("state = %s", StateAsCString(GetState()));
}
@@ -4946,6 +5110,7 @@ public:
m_write_file (write_fd, false),
m_pipe ()
{
+ m_pipe.CreateNew(false);
m_read_file.SetDescriptor(GetInputFD(), false);
}
@@ -4955,130 +5120,93 @@ public:
}
- bool
- OpenPipes ()
- {
- if (m_pipe.CanRead() && m_pipe.CanWrite())
- return true;
- Error result = m_pipe.CreateNew(false);
- return result.Success();
- }
-
- void
- ClosePipes()
- {
- m_pipe.Close();
- }
-
// 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.
- virtual void
- Run ()
+ void
+ Run () override
{
- if (m_read_file.IsValid() && m_write_file.IsValid())
+ if (!m_read_file.IsValid() || !m_write_file.IsValid() || !m_pipe.CanRead() || !m_pipe.CanWrite())
{
- SetIsDone(false);
- if (OpenPipes())
- {
- const int read_fd = m_read_file.GetDescriptor();
- const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
- TerminalState terminal_state;
- terminal_state.Save (read_fd, false);
- Terminal terminal(read_fd);
- terminal.SetCanonical(false);
- terminal.SetEcho(false);
+ 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
- while (!GetIsDone())
+ const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
+ while (!GetIsDone())
+ {
+ fd_set read_fdset;
+ FD_ZERO (&read_fdset);
+ FD_SET (read_fd, &read_fdset);
+ FD_SET (pipe_read_fd, &read_fdset);
+ const int nfds = std::max<int>(read_fd, pipe_read_fd) + 1;
+ int num_set_fds = select (nfds, &read_fdset, NULL, NULL, NULL);
+ if (num_set_fds < 0)
+ {
+ const int select_errno = errno;
+
+ if (select_errno != EINTR)
+ SetIsDone(true);
+ }
+ else if (num_set_fds > 0)
+ {
+ char ch = 0;
+ size_t n;
+ if (FD_ISSET (read_fd, &read_fdset))
{
- fd_set read_fdset;
- FD_ZERO (&read_fdset);
- FD_SET (read_fd, &read_fdset);
- FD_SET (pipe_read_fd, &read_fdset);
- const int nfds = std::max<int>(read_fd, pipe_read_fd) + 1;
- int num_set_fds = select (nfds, &read_fdset, NULL, NULL, NULL);
- if (num_set_fds < 0)
+ n = 1;
+ if (m_read_file.Read(&ch, n).Success() && n == 1)
{
- const int select_errno = errno;
-
- if (select_errno != EINTR)
+ if (m_write_file.Write(&ch, n).Fail() || n != 1)
SetIsDone(true);
}
- else if (num_set_fds > 0)
+ else
+ SetIsDone(true);
+ }
+ if (FD_ISSET (pipe_read_fd, &read_fdset))
+ {
+ size_t bytes_read;
+ // Consume the interrupt byte
+ Error error = m_pipe.Read(&ch, 1, bytes_read);
+ if (error.Success())
{
- char ch = 0;
- size_t n;
- if (FD_ISSET (read_fd, &read_fdset))
+ switch (ch)
{
- 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
+ case 'q':
SetIsDone(true);
- }
- if (FD_ISSET (pipe_read_fd, &read_fdset))
- {
- 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->Halt();
- break;
- }
- }
+ break;
+ case 'i':
+ if (StateIsRunningState(m_process->GetState()))
+ m_process->Halt();
+ break;
}
}
}
-#endif
- terminal_state.Restore();
-
}
- else
- SetIsDone(true);
}
- else
- SetIsDone(true);
- }
-
- // Hide any characters that have been displayed so far so async
- // output can be displayed. Refresh() will be called after the
- // output has been displayed.
- virtual void
- Hide ()
- {
-
- }
- // Called when the async output has been received in order to update
- // the input reader (refresh the prompt and redisplay any current
- // line(s) that are being edited
- virtual void
- Refresh ()
- {
-
+#endif
+ terminal_state.Restore();
}
- virtual void
- Cancel ()
+ void
+ Cancel () override
{
char ch = 'q'; // Send 'q' for quit
size_t bytes_written = 0;
m_pipe.Write(&ch, 1, bytes_written);
}
- virtual bool
- Interrupt ()
+ 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
@@ -5111,8 +5239,8 @@ public:
return false;
}
- virtual void
- GotEOF()
+ void
+ GotEOF() override
{
}
@@ -5161,6 +5289,10 @@ Process::PushProcessIOHandler ()
IOHandlerSP io_handler_sp (m_process_input_reader);
if (io_handler_sp)
{
+ Log *log(lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_PROCESS));
+ if (log)
+ log->Printf("Process::%s pushing IO handler", __FUNCTION__);
+
io_handler_sp->SetIsDone(false);
m_target.GetDebugger().PushIOHandler (io_handler_sp);
return true;
@@ -6252,6 +6384,15 @@ 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 ()
{
@@ -6351,13 +6492,29 @@ Process::ModulesDidLoad (ModuleList &module_list)
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
+ // NULL 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);
+ }
}
ThreadCollectionSP
Process::GetHistoryThreads(lldb::addr_t addr)
{
ThreadCollectionSP threads;
-
+
const MemoryHistorySP &memory_history = MemoryHistory::FindPlugin(shared_from_this());
if (! memory_history.get()) {
@@ -6381,3 +6538,12 @@ Process::GetInstrumentationRuntime(lldb::InstrumentationRuntimeType type)
else
return (*pos).second;
}
+
+bool
+Process::GetModuleSpec(const FileSpec& module_file_spec,
+ const ArchSpec& arch,
+ ModuleSpec& module_spec)
+{
+ module_spec.Clear();
+ return false;
+}