aboutsummaryrefslogtreecommitdiff
path: root/lldb/source/Target/Process.cpp
diff options
context:
space:
mode:
authorDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
committerDimitry Andric <dim@FreeBSD.org>2021-11-19 20:06:13 +0000
commitc0981da47d5696fe36474fcf86b4ce03ae3ff818 (patch)
treef42add1021b9f2ac6a69ac7cf6c4499962739a45 /lldb/source/Target/Process.cpp
parent344a3780b2e33f6ca763666c380202b18aab72a3 (diff)
Diffstat (limited to 'lldb/source/Target/Process.cpp')
-rw-r--r--lldb/source/Target/Process.cpp352
1 files changed, 172 insertions, 180 deletions
diff --git a/lldb/source/Target/Process.cpp b/lldb/source/Target/Process.cpp
index 8ecc66b592ea..84dc2b94a0eb 100644
--- a/lldb/source/Target/Process.cpp
+++ b/lldb/source/Target/Process.cpp
@@ -110,6 +110,19 @@ public:
}
};
+static constexpr OptionEnumValueElement g_follow_fork_mode_values[] = {
+ {
+ eFollowParent,
+ "parent",
+ "Continue tracing the parent process and detach the child.",
+ },
+ {
+ eFollowChild,
+ "child",
+ "Trace the child process and detach the parent.",
+ },
+};
+
#define LLDB_PROPERTIES_process
#include "TargetProperties.inc"
@@ -153,10 +166,10 @@ ProcessProperties::ProcessProperties(lldb_private::Process *process)
m_collection_sp->Initialize(g_process_properties);
m_collection_sp->AppendProperty(
ConstString("thread"), ConstString("Settings specific to threads."),
- true, Thread::GetGlobalProperties()->GetValueProperties());
+ true, Thread::GetGlobalProperties().GetValueProperties());
} else {
m_collection_sp =
- OptionValueProperties::CreateLocalCopy(*Process::GetGlobalProperties());
+ OptionValueProperties::CreateLocalCopy(Process::GetGlobalProperties());
m_collection_sp->SetValueChangedCallback(
ePropertyPythonOSPluginPath,
[this] { m_process->LoadOperatingSystemPlugin(true); });
@@ -334,6 +347,12 @@ void ProcessProperties::SetOSPluginReportsAllThreads(bool does_report) {
nullptr, ePropertyOSPluginReportsAllThreads, does_report);
}
+FollowForkMode ProcessProperties::GetFollowForkMode() const {
+ const uint32_t idx = ePropertyFollowForkMode;
+ return (FollowForkMode)m_collection_sp->GetPropertyAtIndexAsEnumeration(
+ nullptr, idx, g_process_properties[idx].default_uint_value);
+}
+
ProcessSP Process::FindPlugin(lldb::TargetSP target_sp,
llvm::StringRef plugin_name,
ListenerSP listener_sp,
@@ -344,9 +363,8 @@ ProcessSP Process::FindPlugin(lldb::TargetSP target_sp,
ProcessSP process_sp;
ProcessCreateInstance create_callback = nullptr;
if (!plugin_name.empty()) {
- ConstString const_plugin_name(plugin_name);
create_callback =
- PluginManager::GetProcessCreateCallbackForPluginName(const_plugin_name);
+ PluginManager::GetProcessCreateCallbackForPluginName(plugin_name);
if (create_callback) {
process_sp = create_callback(target_sp, listener_sp, crash_file_path,
can_connect);
@@ -481,12 +499,12 @@ Process::~Process() {
m_thread_list.Clear();
}
-const ProcessPropertiesSP &Process::GetGlobalProperties() {
+ProcessProperties &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 =
- new ProcessPropertiesSP(new ProcessProperties(nullptr));
- return *g_settings_sp_ptr;
+ static ProcessProperties *g_settings_ptr =
+ new ProcessProperties(nullptr);
+ return *g_settings_ptr;
}
void Process::Finalize() {
@@ -1278,6 +1296,17 @@ StateType Process::GetState() {
}
void Process::SetPublicState(StateType new_state, bool restarted) {
+ const bool new_state_is_stopped = StateIsStoppedState(new_state, false);
+ if (new_state_is_stopped) {
+ // This will only set the time if the public stop time has no value, so
+ // it is ok to call this multiple times. With a public stop we can't look
+ // at the stop ID because many private stops might have happened, so we
+ // can't check for a stop ID of zero. This allows the "statistics" command
+ // to dump the time it takes to reach somewhere in your code, like a
+ // breakpoint you set.
+ GetTarget().GetStatistics().SetFirstPublicStopTime();
+ }
+
Log *log(lldb_private::GetLogIfAnyCategoriesSet(LIBLLDB_LOG_STATE |
LIBLLDB_LOG_PROCESS));
LLDB_LOGF(log, "Process::SetPublicState (state = %s, restarted = %i)",
@@ -1296,7 +1325,6 @@ void Process::SetPublicState(StateType new_state, bool restarted) {
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) {
LLDB_LOGF(log, "Process::SetPublicState (%s) -- unlocking run lock",
@@ -1427,7 +1455,9 @@ void Process::SetPrivateState(StateType new_state) {
// before we get here.
m_thread_list.DidStop();
- m_mod_id.BumpStopID();
+ if (m_mod_id.BumpStopID() == 0)
+ GetTarget().GetStatistics().SetFirstPrivateStopTime();
+
if (!m_mod_id.IsLastResumeForUserExpression())
m_mod_id.SetStopEventForLastNaturalStopID(event_sp);
m_memory_cache.Clear();
@@ -1953,57 +1983,6 @@ size_t Process::ReadCStringFromMemory(addr_t addr, std::string &out_str,
return out_str.size();
}
-size_t Process::ReadStringFromMemory(addr_t addr, char *dst, size_t max_bytes,
- Status &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;
-}
-
// 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,
@@ -2463,115 +2442,125 @@ Status Process::Launch(ProcessLaunchInfo &launch_info) {
m_process_input_reader.reset();
Module *exe_module = GetTarget().GetExecutableModulePointer();
- if (!exe_module) {
- error.SetErrorString("executable module does not exist");
- return error;
- }
- 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 (FileSystem::Instance().Exists(exe_module->GetFileSpec())) {
+ // The "remote executable path" is hooked up to the local Executable
+ // module. But we should be able to debug a remote process even if the
+ // executable module only exists on the remote. However, there needs to
+ // be a way to express this path, without actually having a module.
+ // The way to do that is to set the ExecutableFile in the LaunchInfo.
+ // Figure that out here:
+
+ FileSpec exe_spec_to_use;
+ if (!exe_module) {
+ if (!launch_info.GetExecutableFile()) {
+ error.SetErrorString("executable module does not exist");
+ return error;
+ }
+ exe_spec_to_use = launch_info.GetExecutableFile();
+ } else
+ exe_spec_to_use = exe_module->GetFileSpec();
+
+ if (exe_module && FileSystem::Instance().Exists(exe_module->GetFileSpec())) {
// 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;
+ }
+ // Listen and queue events that are broadcasted during the process launch.
+ ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack"));
+ HijackProcessEvents(listener_sp);
+ auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); });
- // Listen and queue events that are broadcasted during the process launch.
- ListenerSP listener_sp(Listener::MakeListener("LaunchEventHijack"));
- HijackProcessEvents(listener_sp);
- auto on_exit = llvm::make_scope_exit([this]() { RestoreProcessEvents(); });
+ if (PrivateStateThreadIsValid())
+ PausePrivateStateThread();
- if (PrivateStateThreadIsValid())
- PausePrivateStateThread();
+ error = WillLaunch(exe_module);
+ if (error.Success()) {
+ const bool restarted = false;
+ SetPublicState(eStateLaunching, restarted);
+ m_should_detach = false;
- 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");
+ }
- 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;
- 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;
-
- // Now wait for the process to launch and return control to us, and then
- // call DidLaunch:
- StateType state = WaitForProcessStopPrivate(event_sp, seconds(10));
+ // Now wait for the process to launch and return control to us, and then
+ // call DidLaunch:
+ StateType state = WaitForProcessStopPrivate(event_sp, seconds(10));
- if (state == eStateInvalid || !event_sp) {
- // We were able to launch the process, but we failed to catch the
- // initial stop.
- error.SetErrorString("failed to catch stop after launch");
- SetExitStatus(0, "failed to catch stop after launch");
- Destroy(false);
- } else if (state == eStateStopped || state == eStateCrashed) {
- DidLaunch();
+ if (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();
+ DynamicLoader *dyld = GetDynamicLoader();
+ if (dyld)
+ dyld->DidLaunch();
- GetJITLoaders().DidLaunch();
+ GetJITLoaders().DidLaunch();
- SystemRuntime *system_runtime = GetSystemRuntime();
- if (system_runtime)
- system_runtime->DidLaunch();
+ SystemRuntime *system_runtime = GetSystemRuntime();
+ if (system_runtime)
+ system_runtime->DidLaunch();
- if (!m_os_up)
- LoadOperatingSystemPlugin(false);
+ if (!m_os_up)
+ LoadOperatingSystemPlugin(false);
- // We successfully launched the process and stopped, now it the
- // right time to set up signal filters before resuming.
- UpdateAutomaticSignalFiltering();
+ // We successfully launched the process and stopped, now it the
+ // right time to set up signal filters before resuming.
+ UpdateAutomaticSignalFiltering();
- // 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);
+ // 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.
+ // We are done with the launch hijack listener, and this stop should
+ // go to the public state listener:
+ RestoreProcessEvents();
+ SetPublicState(state, false);
- if (PrivateStateThreadIsValid())
- ResumePrivateStateThread();
- else
- StartPrivateStateThread();
+ if (PrivateStateThreadIsValid())
+ ResumePrivateStateThread();
+ else
+ StartPrivateStateThread();
- // 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.
+ // 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 {
+ std::string local_exec_file_path = exe_spec_to_use.GetPath();
error.SetErrorStringWithFormat("file doesn't exist: '%s'",
- local_exec_file_path);
+ local_exec_file_path.c_str());
}
return error;
@@ -2625,12 +2614,16 @@ Status Process::LoadCore() {
DynamicLoader *Process::GetDynamicLoader() {
if (!m_dyld_up)
- m_dyld_up.reset(DynamicLoader::FindPlugin(this, nullptr));
+ m_dyld_up.reset(DynamicLoader::FindPlugin(this, ""));
return m_dyld_up.get();
}
DataExtractor Process::GetAuxvData() { return DataExtractor(); }
+llvm::Expected<bool> Process::SaveCore(llvm::StringRef outfile) {
+ return false;
+}
+
JITLoaderList &Process::GetJITLoaders() {
if (!m_jit_loaders_up) {
m_jit_loaders_up = std::make_unique<JITLoaderList>();
@@ -2916,13 +2909,11 @@ void Process::CompleteAttach() {
dyld->DidAttach();
if (log) {
ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
- LLDB_LOGF(log,
- "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>"));
+ LLDB_LOG(log,
+ "after DynamicLoader::DidAttach(), target "
+ "executable is {0} (using {1} plugin)",
+ exe_module_sp ? exe_module_sp->GetFileSpec() : FileSpec(),
+ dyld->GetPluginName());
}
}
@@ -2933,13 +2924,11 @@ void Process::CompleteAttach() {
system_runtime->DidAttach();
if (log) {
ModuleSP exe_module_sp = GetTarget().GetExecutableModule();
- LLDB_LOGF(log,
- "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>"));
+ LLDB_LOG(log,
+ "after SystemRuntime::DidAttach(), target "
+ "executable is {0} (using {1} plugin)",
+ exe_module_sp ? exe_module_sp->GetFileSpec() : FileSpec(),
+ system_runtime->GetPluginName());
}
}
@@ -4310,8 +4299,8 @@ public:
: IOHandler(process->GetTarget().GetDebugger(),
IOHandler::Type::ProcessIO),
m_process(process),
- m_read_file(GetInputFD(), File::eOpenOptionRead, false),
- m_write_file(write_fd, File::eOpenOptionWrite, false) {
+ m_read_file(GetInputFD(), File::eOpenOptionReadOnly, false),
+ m_write_file(write_fd, File::eOpenOptionWriteOnly, false) {
m_pipe.CreateNew(false);
}
@@ -4328,11 +4317,11 @@ public:
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);
+ TerminalState terminal_state(terminal, false);
+ // FIXME: error handling?
+ llvm::consumeError(terminal.SetCanonical(false));
+ llvm::consumeError(terminal.SetEcho(false));
// FD_ZERO, FD_SET are not supported on windows
#ifndef _WIN32
const int pipe_read_fd = m_pipe.GetReadFileDescriptor();
@@ -4376,7 +4365,6 @@ public:
}
m_is_running = false;
#endif
- terminal_state.Restore();
}
void Cancel() override {
@@ -4433,7 +4421,7 @@ public:
protected:
Process *m_process;
NativeFile m_read_file; // Read from this file (usually actual STDIN for LLDB
- NativeFile m_write_file; // Write to this file (usually the master pty for
+ NativeFile m_write_file; // Write to this file (usually the primary pty for
// getting io to debuggee)
Pipe m_pipe;
std::atomic<bool> m_is_running{false};
@@ -4494,7 +4482,8 @@ void Process::SettingsInitialize() { Thread::SettingsInitialize(); }
void Process::SettingsTerminate() { Thread::SettingsTerminate(); }
namespace {
-// RestorePlanState is used to record the "is private", "is master" and "okay
+// RestorePlanState is used to record the "is private", "is controlling" 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.
@@ -4505,7 +4494,7 @@ public:
: 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_is_controlling = m_thread_plan_sp->IsControllingPlan();
m_okay_to_discard = m_thread_plan_sp->OkayToDiscard();
}
}
@@ -4516,7 +4505,7 @@ public:
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->SetIsControllingPlan(m_is_controlling);
m_thread_plan_sp->SetOkayToDiscard(m_okay_to_discard);
}
}
@@ -4525,7 +4514,7 @@ private:
lldb::ThreadPlanSP m_thread_plan_sp;
bool m_already_reset;
bool m_private;
- bool m_is_master;
+ bool m_is_controlling;
bool m_okay_to_discard;
};
} // anonymous namespace
@@ -4676,11 +4665,11 @@ Process::RunThreadPlan(ExecutionContext &exe_ctx,
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
+ // The plans run with RunThreadPlan also need to be terminal controlling 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->SetIsControllingPlan(true);
thread_plan_sp->SetOkayToDiscard(false);
// If we are running some utility expression for LLDB, we now have to mark
@@ -5864,6 +5853,13 @@ Process::AdvanceAddressToNextBranchInstruction(Address default_stop_addr,
return retval;
}
+Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr,
+ MemoryRegionInfo &range_info) {
+ if (auto abi = GetABI())
+ load_addr = abi->FixDataAddress(load_addr);
+ return DoGetMemoryRegionInfo(load_addr, range_info);
+}
+
Status
Process::GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list) {
@@ -5963,11 +5959,8 @@ void Process::MapSupportedStructuredDataPlugins(
m_structured_data_plugin_map.insert(
std::make_pair(type_name, plugin_sp));
names_to_remove.push_back(type_name);
- LLDB_LOGF(log,
- "Process::%s(): using plugin %s for type name "
- "%s",
- __FUNCTION__, plugin_sp->GetPluginName().GetCString(),
- type_name.GetCString());
+ LLDB_LOG(log, "using plugin {0} for type name {1}",
+ plugin_sp->GetPluginName(), type_name);
}
}
@@ -6091,8 +6084,7 @@ llvm::Expected<const MemoryTagManager *> Process::GetMemoryTagManager() {
if (!arch || !tag_manager) {
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
- "This architecture does not support memory tagging",
- GetPluginName().GetCString());
+ "This architecture does not support memory tagging");
}
if (!SupportsMemoryTagging()) {