[lldb][NFC] Fix all formatting errors in .cpp file headers
Summary:
A *.cpp file header in LLDB (and in LLDB) should like this:
```
//===-- TestUtilities.cpp -------------------------------------------------===//
```
However in LLDB most of our source files have arbitrary changes to this format and
these changes are spreading through LLDB as folks usually just use the existing
source files as templates for their new files (most notably the unnecessary
editor language indicator `-*- C++ -*-` is spreading and in every review
someone is pointing out that this is wrong, resulting in people pointing out that this
is done in the same way in other files).
This patch removes most of these inconsistencies including the editor language indicators,
all the different missing/additional '-' characters, files that center the file name, missing
trailing `===//` (mostly caused by clang-format breaking the line).
Reviewers: aprantl, espindola, jfb, shafik, JDevlieghere
Reviewed By: JDevlieghere
Subscribers: dexonsmith, wuzish, emaste, sdardis, nemanjai, kbarton, MaskRay, atanasyan, arphaman, jfb, abidh, jsji, JDevlieghere, usaxena95, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D73258
2020-01-24 08:23:27 +01:00
|
|
|
//===-- CommandObjectProcess.cpp ------------------------------------------===//
|
2010-06-08 16:52:24 +00:00
|
|
|
//
|
2019-01-19 08:50:56 +00:00
|
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
|
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
|
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
2010-06-08 16:52:24 +00:00
|
|
|
//
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
#include "CommandObjectProcess.h"
|
2022-06-07 18:03:23 -07:00
|
|
|
#include "CommandObjectBreakpoint.h"
|
2022-07-13 20:11:37 -07:00
|
|
|
#include "CommandObjectTrace.h"
|
2023-03-03 15:27:07 -08:00
|
|
|
#include "CommandOptionsProcessAttach.h"
|
2021-01-20 18:33:00 +01:00
|
|
|
#include "CommandOptionsProcessLaunch.h"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Breakpoint/Breakpoint.h"
|
2022-06-07 18:03:23 -07:00
|
|
|
#include "lldb/Breakpoint/BreakpointIDList.h"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
2022-06-07 18:03:23 -07:00
|
|
|
#include "lldb/Breakpoint/BreakpointName.h"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Breakpoint/BreakpointSite.h"
|
<rdar://problem/11757916>
Make breakpoint setting by file and line much more efficient by only looking for inlined breakpoint locations if we are setting a breakpoint in anything but a source implementation file. Implementing this complex for a many reasons. Turns out that parsing compile units lazily had some issues with respect to how we need to do things with DWARF in .o files. So the fixes in the checkin for this makes these changes:
- Add a new setting called "target.inline-breakpoint-strategy" which can be set to "never", "always", or "headers". "never" will never try and set any inlined breakpoints (fastest). "always" always looks for inlined breakpoint locations (slowest, but most accurate). "headers", which is the default setting, will only look for inlined breakpoint locations if the breakpoint is set in what are consudered to be header files, which is realy defined as "not in an implementation source file".
- modify the breakpoint setting by file and line to check the current "target.inline-breakpoint-strategy" setting and act accordingly
- Modify compile units to be able to get their language and other info lazily. This allows us to create compile units from the debug map and not have to fill all of the details in, and then lazily discover this information as we go on debuggging. This is needed to avoid parsing all .o files when setting breakpoints in implementation only files (no inlines). Otherwise we would need to parse the .o file, the object file (mach-o in our case) and the symbol file (DWARF in the object file) just to see what the compile unit was.
- modify the "SymbolFileDWARFDebugMap" to subclass lldb_private::Module so that the virtual "GetObjectFile()" and "GetSymbolVendor()" functions can be intercepted when the .o file contenst are later lazilly needed. Prior to this fix, when we first instantiated the "SymbolFileDWARFDebugMap" class, we would also make modules, object files and symbol files for every .o file in the debug map because we needed to fix up the sections in the .o files with information that is in the executable debug map. Now we lazily do this in the DebugMapModule::GetObjectFile()
Cleaned up header includes a bit as well.
llvm-svn: 162860
2012-08-29 21:13:06 +00:00
|
|
|
#include "lldb/Core/Module.h"
|
2014-06-13 00:54:12 +00:00
|
|
|
#include "lldb/Core/PluginManager.h"
|
2017-03-22 23:33:16 +00:00
|
|
|
#include "lldb/Host/OptionParser.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#include "lldb/Interpreter/CommandInterpreter.h"
|
2022-07-13 20:11:37 -07:00
|
|
|
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
2018-04-10 09:03:59 +00:00
|
|
|
#include "lldb/Interpreter/OptionArgParser.h"
|
2021-03-23 16:22:07 +00:00
|
|
|
#include "lldb/Interpreter/OptionGroupPythonClassWithDict.h"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Interpreter/Options.h"
|
2024-09-11 10:33:19 -07:00
|
|
|
#include "lldb/Symbol/SaveCoreOptions.h"
|
2011-03-08 22:40:15 +00:00
|
|
|
#include "lldb/Target/Platform.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#include "lldb/Target/Process.h"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Target/StopInfo.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
#include "lldb/Target/Target.h"
|
|
|
|
|
#include "lldb/Target/Thread.h"
|
2015-03-03 21:51:25 +00:00
|
|
|
#include "lldb/Target/UnixSignals.h"
|
2018-04-17 18:53:35 +00:00
|
|
|
#include "lldb/Utility/Args.h"
|
2023-03-06 11:53:09 -08:00
|
|
|
#include "lldb/Utility/ScriptedMetadata.h"
|
2018-08-07 11:07:21 +00:00
|
|
|
#include "lldb/Utility/State.h"
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
#include "llvm/ADT/ScopeExit.h"
|
|
|
|
|
|
2021-07-22 01:02:54 -07:00
|
|
|
#include <bitset>
|
2023-01-07 13:43:00 -08:00
|
|
|
#include <optional>
|
2021-07-22 01:02:54 -07:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
using namespace lldb;
|
|
|
|
|
using namespace lldb_private;
|
|
|
|
|
|
2013-03-29 00:56:30 +00:00
|
|
|
class CommandObjectProcessLaunchOrAttach : public CommandObjectParsed {
|
|
|
|
|
public:
|
|
|
|
|
CommandObjectProcessLaunchOrAttach(CommandInterpreter &interpreter,
|
|
|
|
|
const char *name, const char *help,
|
|
|
|
|
const char *syntax, uint32_t flags,
|
|
|
|
|
const char *new_process_action)
|
|
|
|
|
: CommandObjectParsed(interpreter, name, help, syntax, flags),
|
|
|
|
|
m_new_process_action(new_process_action) {}
|
2016-02-23 01:43:44 +00:00
|
|
|
|
|
|
|
|
~CommandObjectProcessLaunchOrAttach() override = default;
|
|
|
|
|
|
2013-03-29 00:56:30 +00:00
|
|
|
protected:
|
2013-12-13 17:20:18 +00:00
|
|
|
bool StopProcessIfNecessary(Process *process, StateType &state,
|
|
|
|
|
CommandReturnObject &result) {
|
2013-03-29 00:56:30 +00:00
|
|
|
state = eStateInvalid;
|
|
|
|
|
if (process) {
|
|
|
|
|
state = process->GetState();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2013-03-29 00:56:30 +00:00
|
|
|
if (process->IsAlive() && state != eStateConnected) {
|
2020-07-27 14:05:23 +02:00
|
|
|
std::string message;
|
2013-03-29 00:56:30 +00:00
|
|
|
if (process->GetState() == eStateAttaching)
|
2020-07-27 14:05:23 +02:00
|
|
|
message =
|
|
|
|
|
llvm::formatv("There is a pending attach, abort it and {0}?",
|
|
|
|
|
m_new_process_action);
|
2013-03-29 00:56:30 +00:00
|
|
|
else if (process->GetShouldDetach())
|
2020-07-27 14:05:23 +02:00
|
|
|
message = llvm::formatv(
|
|
|
|
|
"There is a running process, detach from it and {0}?",
|
|
|
|
|
m_new_process_action);
|
2013-03-29 00:56:30 +00:00
|
|
|
else
|
2020-07-27 14:05:23 +02:00
|
|
|
message =
|
|
|
|
|
llvm::formatv("There is a running process, kill it and {0}?",
|
|
|
|
|
m_new_process_action);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2013-03-29 00:56:30 +00:00
|
|
|
if (!m_interpreter.Confirm(message, true)) {
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
} else {
|
2015-04-17 05:01:58 +00:00
|
|
|
if (process->GetShouldDetach()) {
|
|
|
|
|
bool keep_stopped = false;
|
2017-05-12 04:51:55 +00:00
|
|
|
Status detach_error(process->Detach(keep_stopped));
|
2013-03-29 00:56:30 +00:00
|
|
|
if (detach_error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2016-02-23 01:43:44 +00:00
|
|
|
process = nullptr;
|
2013-03-29 00:56:30 +00:00
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"Failed to detach from process: %s\n",
|
|
|
|
|
detach_error.AsCString());
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status destroy_error(process->Destroy(false));
|
2013-03-29 00:56:30 +00:00
|
|
|
if (destroy_error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2016-02-23 01:43:44 +00:00
|
|
|
process = nullptr;
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.AppendErrorWithFormat("Failed to kill process: %s\n",
|
2013-12-13 17:20:18 +00:00
|
|
|
destroy_error.AsCString());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2013-03-29 00:56:30 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2013-03-29 00:56:30 +00:00
|
|
|
}
|
|
|
|
|
return result.Succeeded();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2016-02-23 01:43:44 +00:00
|
|
|
|
2013-03-29 00:56:30 +00:00
|
|
|
std::string m_new_process_action;
|
|
|
|
|
};
|
2016-02-23 01:43:44 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
// CommandObjectProcessLaunch
|
2012-02-16 06:50:00 +00:00
|
|
|
#pragma mark CommandObjectProcessLaunch
|
2013-03-29 00:56:30 +00:00
|
|
|
class CommandObjectProcessLaunch : public CommandObjectProcessLaunchOrAttach {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2010-09-18 01:14:36 +00:00
|
|
|
CommandObjectProcessLaunch(CommandInterpreter &interpreter)
|
2016-02-23 01:43:44 +00:00
|
|
|
: CommandObjectProcessLaunchOrAttach(
|
|
|
|
|
interpreter, "process launch",
|
2025-02-22 11:11:40 -06:00
|
|
|
"Launch the executable in the debugger. If no run-args are "
|
|
|
|
|
"specified, the arguments from target.run-args are used.",
|
|
|
|
|
nullptr, eCommandRequiresTarget, "restart"),
|
2022-01-23 11:07:14 -08:00
|
|
|
|
|
|
|
|
m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
|
2021-03-23 16:22:07 +00:00
|
|
|
m_all_options.Append(&m_options);
|
|
|
|
|
m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
|
|
|
|
|
LLDB_OPT_SET_ALL);
|
|
|
|
|
m_all_options.Finalize();
|
|
|
|
|
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypeRunArgs, eArgRepeatOptional);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
~CommandObjectProcessLaunch() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2021-03-23 16:22:07 +00:00
|
|
|
Options *GetOptions() override { return &m_all_options; }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2023-01-07 14:18:35 -08:00
|
|
|
std::optional<std::string> GetRepeatCommand(Args ¤t_command_args,
|
|
|
|
|
uint32_t index) override {
|
2010-10-04 22:28:36 +00:00
|
|
|
// No repeat for "process launch"...
|
2022-02-04 15:16:31 -08:00
|
|
|
return std::string("");
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &launch_args, CommandReturnObject &result) override {
|
2019-04-27 06:19:42 +00:00
|
|
|
Debugger &debugger = GetDebugger();
|
2011-11-08 02:43:13 +00:00
|
|
|
Target *target = debugger.GetSelectedTarget().get();
|
2012-08-10 21:48:41 +00:00
|
|
|
// If our listener is nullptr, users aren't allows to launch
|
|
|
|
|
ModuleSP exe_module_sp = target->GetExecutableModule();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2021-11-17 14:49:55 -08:00
|
|
|
// If the target already has an executable module, then use that. If it
|
|
|
|
|
// doesn't then someone must be trying to launch using a path that will
|
|
|
|
|
// make sense to the remote stub, but doesn't exist on the local host.
|
|
|
|
|
// In that case use the ExecutableFile that was set in the target's
|
|
|
|
|
// ProcessLaunchInfo.
|
|
|
|
|
if (exe_module_sp == nullptr && !target->GetProcessLaunchInfo().GetExecutableFile()) {
|
2012-08-10 21:48:41 +00:00
|
|
|
result.AppendError("no file in target, create a debug target using the "
|
2016-08-11 23:51:28 +00:00
|
|
|
"'target create' command");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2012-08-10 21:48:41 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
StateType state = eStateInvalid;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
if (!StopProcessIfNecessary(m_exe_ctx.GetProcessPtr(), state, result))
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-08-19 17:40:43 +00:00
|
|
|
// Determine whether we will disable ASLR or leave it in the default state
|
2018-04-30 16:49:04 +00:00
|
|
|
// (i.e. enabled if the platform supports it). First check if the process
|
|
|
|
|
// launch options explicitly turn on/off
|
2014-08-19 17:40:43 +00:00
|
|
|
// disabling ASLR. If so, use that setting;
|
|
|
|
|
// otherwise, use the 'settings target.disable-aslr' setting.
|
|
|
|
|
bool disable_aslr = false;
|
|
|
|
|
if (m_options.disable_aslr != eLazyBoolCalculate) {
|
2018-04-30 16:49:04 +00:00
|
|
|
// The user specified an explicit setting on the process launch line.
|
|
|
|
|
// Use it.
|
2010-06-08 16:52:24 +00:00
|
|
|
disable_aslr = (m_options.disable_aslr == eLazyBoolYes);
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2018-04-30 16:49:04 +00:00
|
|
|
// The user did not explicitly specify whether to disable ASLR. Fall
|
|
|
|
|
// back to the target.disable-aslr setting.
|
2014-08-19 17:40:43 +00:00
|
|
|
disable_aslr = target->GetDisableASLR();
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2021-03-23 16:22:07 +00:00
|
|
|
if (!m_class_options.GetName().empty()) {
|
|
|
|
|
m_options.launch_info.SetProcessPluginName("ScriptedProcess");
|
2023-03-03 15:17:59 -08:00
|
|
|
ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
|
|
|
|
|
m_class_options.GetName(), m_class_options.GetStructuredData());
|
|
|
|
|
m_options.launch_info.SetScriptedMetadata(metadata_sp);
|
2021-03-23 16:22:07 +00:00
|
|
|
target->SetProcessLaunchInfo(m_options.launch_info);
|
|
|
|
|
}
|
|
|
|
|
|
2014-08-19 17:40:43 +00:00
|
|
|
if (disable_aslr)
|
2013-12-13 17:20:18 +00:00
|
|
|
m_options.launch_info.GetFlags().Set(eLaunchFlagDisableASLR);
|
2016-09-06 20:57:50 +00:00
|
|
|
else
|
2015-10-07 16:56:17 +00:00
|
|
|
m_options.launch_info.GetFlags().Clear(eLaunchFlagDisableASLR);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2020-08-05 10:02:51 -07:00
|
|
|
if (target->GetInheritTCC())
|
|
|
|
|
m_options.launch_info.GetFlags().Set(eLaunchFlagInheritTCCFromParent);
|
|
|
|
|
|
2014-06-25 02:32:56 +00:00
|
|
|
if (target->GetDetachOnError())
|
|
|
|
|
m_options.launch_info.GetFlags().Set(eLaunchFlagDetachOnError);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2013-12-13 17:20:18 +00:00
|
|
|
if (target->GetDisableSTDIO())
|
2015-10-07 16:56:17 +00:00
|
|
|
m_options.launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2024-11-05 13:26:59 -05:00
|
|
|
if (!m_options.launch_info.GetWorkingDirectory()) {
|
|
|
|
|
if (llvm::StringRef wd = target->GetLaunchWorkingDirectory();
|
|
|
|
|
!wd.empty()) {
|
|
|
|
|
m_options.launch_info.SetWorkingDirectory(FileSpec(wd));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2019-05-13 19:17:48 +00:00
|
|
|
// Merge the launch info environment with the target environment.
|
|
|
|
|
Environment target_env = target->GetEnvironment();
|
|
|
|
|
m_options.launch_info.GetEnvironment().insert(target_env.begin(),
|
|
|
|
|
target_env.end());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2021-08-11 16:56:36 +01:00
|
|
|
llvm::StringRef target_settings_argv0 = target->GetArg0();
|
|
|
|
|
|
2016-11-17 18:08:12 +00:00
|
|
|
if (!target_settings_argv0.empty()) {
|
2012-06-08 21:56:10 +00:00
|
|
|
m_options.launch_info.GetArguments().AppendArgument(
|
2016-11-17 18:08:12 +00:00
|
|
|
target_settings_argv0);
|
2021-11-17 14:49:55 -08:00
|
|
|
if (exe_module_sp)
|
|
|
|
|
m_options.launch_info.SetExecutableFile(
|
|
|
|
|
exe_module_sp->GetPlatformFileSpec(), false);
|
|
|
|
|
else
|
|
|
|
|
m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), false);
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2021-11-17 14:49:55 -08:00
|
|
|
if (exe_module_sp)
|
|
|
|
|
m_options.launch_info.SetExecutableFile(
|
|
|
|
|
exe_module_sp->GetPlatformFileSpec(), true);
|
|
|
|
|
else
|
|
|
|
|
m_options.launch_info.SetExecutableFile(target->GetProcessLaunchInfo().GetExecutableFile(), true);
|
2012-06-08 21:56:10 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
if (launch_args.GetArgumentCount() == 0) {
|
2011-05-03 22:09:39 +00:00
|
|
|
m_options.launch_info.GetArguments().AppendArguments(
|
2012-10-17 22:57:12 +00:00
|
|
|
target->GetProcessLaunchInfo().GetArguments());
|
2014-08-19 17:40:43 +00:00
|
|
|
} else {
|
|
|
|
|
m_options.launch_info.GetArguments().AppendArguments(launch_args);
|
2012-10-17 22:57:12 +00:00
|
|
|
// Save the arguments for subsequent runs in the current target.
|
|
|
|
|
target->SetRunArguments(launch_args);
|
2011-11-03 21:22:33 +00:00
|
|
|
}
|
2014-10-21 01:00:42 +00:00
|
|
|
|
|
|
|
|
StreamString stream;
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error = target->Launch(m_options.launch_info, &stream);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-09-18 01:14:36 +00:00
|
|
|
if (error.Success()) {
|
2013-12-13 17:20:18 +00:00
|
|
|
ProcessSP process_sp(target->GetProcessSP());
|
|
|
|
|
if (process_sp) {
|
2015-05-07 06:26:27 +00:00
|
|
|
// There is a race condition where this thread will return up the call
|
2018-04-30 16:49:04 +00:00
|
|
|
// stack to the main command handler and show an (lldb) prompt before
|
|
|
|
|
// HandlePrivateEvent (from PrivateStateThread) has a chance to call
|
|
|
|
|
// PushProcessIOHandler().
|
2018-05-09 14:29:30 +00:00
|
|
|
process_sp->SyncIOHandler(0, std::chrono::seconds(2));
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2021-11-17 14:49:55 -08:00
|
|
|
// If we didn't have a local executable, then we wouldn't have had an
|
|
|
|
|
// executable module before launch.
|
|
|
|
|
if (!exe_module_sp)
|
|
|
|
|
exe_module_sp = target->GetExecutableModule();
|
|
|
|
|
if (!exe_module_sp) {
|
|
|
|
|
result.AppendWarning("Could not get executable module after launch.");
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
|
|
const char *archname =
|
|
|
|
|
exe_module_sp->GetArchitecture().GetArchitectureName();
|
|
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(),
|
|
|
|
|
exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
|
|
|
|
|
}
|
2013-12-13 17:20:18 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2023-11-24 12:48:16 -03:00
|
|
|
// This message will refer to an event that happened after the process
|
|
|
|
|
// launched.
|
|
|
|
|
llvm::StringRef data = stream.GetString();
|
|
|
|
|
if (!data.empty())
|
|
|
|
|
result.AppendMessage(data);
|
2013-12-13 17:20:18 +00:00
|
|
|
result.SetDidChangeProcessState(true);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendError(
|
|
|
|
|
"no error returned from Target::Launch, and target has no process");
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2011-02-15 21:59:32 +00:00
|
|
|
} else {
|
2013-12-13 17:20:18 +00:00
|
|
|
result.AppendError(error.AsCString());
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2021-01-20 18:33:00 +01:00
|
|
|
CommandOptionsProcessLaunch m_options;
|
2021-03-23 16:22:07 +00:00
|
|
|
OptionGroupPythonClassWithDict m_class_options;
|
|
|
|
|
OptionGroupOptions m_all_options;
|
2010-06-08 16:52:24 +00:00
|
|
|
};
|
|
|
|
|
|
2019-07-23 12:54:33 +00:00
|
|
|
#define LLDB_OPTIONS_process_attach
|
|
|
|
|
#include "CommandOptions.inc"
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessAttach
|
2013-03-29 00:56:30 +00:00
|
|
|
class CommandObjectProcessAttach : public CommandObjectProcessLaunchOrAttach {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2016-02-23 01:43:44 +00:00
|
|
|
CommandObjectProcessAttach(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectProcessLaunchOrAttach(
|
2016-07-14 22:03:10 +00:00
|
|
|
interpreter, "process attach", "Attach to a process.",
|
2023-03-03 15:27:07 -08:00
|
|
|
"process attach <cmd-options>", 0, "attach"),
|
|
|
|
|
m_class_options("scripted process", true, 'C', 'k', 'v', 0) {
|
|
|
|
|
m_all_options.Append(&m_options);
|
|
|
|
|
m_all_options.Append(&m_class_options, LLDB_OPT_SET_1 | LLDB_OPT_SET_2,
|
|
|
|
|
LLDB_OPT_SET_ALL);
|
|
|
|
|
m_all_options.Finalize();
|
|
|
|
|
}
|
2010-08-09 23:31:02 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
~CommandObjectProcessAttach() override = default;
|
2012-06-08 21:56:10 +00:00
|
|
|
|
2023-03-03 15:27:07 -08:00
|
|
|
Options *GetOptions() override { return &m_all_options; }
|
2015-02-03 00:04:35 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
2015-02-03 00:04:35 +00:00
|
|
|
PlatformSP platform_sp(
|
2019-04-27 06:19:42 +00:00
|
|
|
GetDebugger().GetPlatformList().GetSelectedPlatform());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2019-04-27 06:19:42 +00:00
|
|
|
Target *target = GetDebugger().GetSelectedTarget().get();
|
2015-02-10 22:49:57 +00:00
|
|
|
// N.B. The attach should be synchronous. It doesn't help much to get the
|
2018-04-30 16:49:04 +00:00
|
|
|
// prompt back between initiating the attach and the target actually
|
|
|
|
|
// stopping. So even if the interpreter is set to be asynchronous, we wait
|
|
|
|
|
// for the stop ourselves here.
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-02-10 22:49:57 +00:00
|
|
|
StateType state = eStateInvalid;
|
|
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-02-10 22:49:57 +00:00
|
|
|
if (!StopProcessIfNecessary(process, state, result))
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-01-08 00:20:47 +00:00
|
|
|
if (target == nullptr) {
|
2015-02-10 22:49:57 +00:00
|
|
|
// If there isn't a current target create one.
|
|
|
|
|
TargetSP new_target_sp;
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2019-04-27 06:19:42 +00:00
|
|
|
error = GetDebugger().GetTargetList().CreateTarget(
|
|
|
|
|
GetDebugger(), "", "", eLoadDependentsNo,
|
2015-02-03 00:04:35 +00:00
|
|
|
nullptr, // No platform options
|
2016-02-23 01:43:44 +00:00
|
|
|
new_target_sp);
|
2015-02-03 00:04:35 +00:00
|
|
|
target = new_target_sp.get();
|
|
|
|
|
if (target == nullptr || error.Fail()) {
|
|
|
|
|
result.AppendError(error.AsCString("Error creating target"));
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-02-03 00:04:35 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-03 15:27:07 -08:00
|
|
|
if (!m_class_options.GetName().empty()) {
|
|
|
|
|
m_options.attach_info.SetProcessPluginName("ScriptedProcess");
|
2023-03-03 15:17:59 -08:00
|
|
|
ScriptedMetadataSP metadata_sp = std::make_shared<ScriptedMetadata>(
|
|
|
|
|
m_class_options.GetName(), m_class_options.GetStructuredData());
|
|
|
|
|
m_options.attach_info.SetScriptedMetadata(metadata_sp);
|
2023-03-03 15:27:07 -08:00
|
|
|
}
|
|
|
|
|
|
2015-02-03 00:04:35 +00:00
|
|
|
// Record the old executable module, we want to issue a warning if the
|
2018-04-30 16:49:04 +00:00
|
|
|
// process of attaching changed the current executable (like somebody said
|
|
|
|
|
// "file foo" then attached to a PID whose executable was bar.)
|
2012-05-24 00:43:00 +00:00
|
|
|
|
2015-02-03 00:04:35 +00:00
|
|
|
ModuleSP old_exec_module_sp = target->GetExecutableModule();
|
|
|
|
|
ArchSpec old_arch_spec = target->GetArchitecture();
|
|
|
|
|
|
|
|
|
|
StreamString stream;
|
2021-09-29 19:38:09 -07:00
|
|
|
ProcessSP process_sp;
|
2015-02-03 00:04:35 +00:00
|
|
|
const auto error = target->Attach(m_options.attach_info, &stream);
|
|
|
|
|
if (error.Success()) {
|
2021-09-29 19:38:09 -07:00
|
|
|
process_sp = target->GetProcessSP();
|
2015-02-10 22:49:57 +00:00
|
|
|
if (process_sp) {
|
2016-11-16 21:15:24 +00:00
|
|
|
result.AppendMessage(stream.GetString());
|
2015-02-03 00:04:35 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
|
|
|
result.SetDidChangeProcessState(true);
|
|
|
|
|
} else {
|
2011-09-20 21:44:10 +00:00
|
|
|
result.AppendError(
|
2015-02-03 00:04:35 +00:00
|
|
|
"no error returned from Target::Attach, and target has no process");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-02-03 00:04:35 +00:00
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("attach failed: %s\n", error.AsCString());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!result.Succeeded())
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-02-03 00:04:35 +00:00
|
|
|
// Okay, we're done. Last step is to warn if the executable module has
|
|
|
|
|
// changed:
|
|
|
|
|
ModuleSP new_exec_module_sp(target->GetExecutableModule());
|
|
|
|
|
if (!old_exec_module_sp) {
|
|
|
|
|
// We might not have a module if we attached to a raw pid...
|
|
|
|
|
if (new_exec_module_sp) {
|
2024-07-23 17:50:40 -07:00
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Executable binary set to \"%s\".\n",
|
|
|
|
|
new_exec_module_sp->GetFileSpec().GetPath().c_str());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2024-07-23 17:50:40 -07:00
|
|
|
} else if (!new_exec_module_sp) {
|
|
|
|
|
result.AppendWarningWithFormat("No executable binary.");
|
2015-02-03 00:04:35 +00:00
|
|
|
} else if (old_exec_module_sp->GetFileSpec() !=
|
|
|
|
|
new_exec_module_sp->GetFileSpec()) {
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-02-03 00:04:35 +00:00
|
|
|
result.AppendWarningWithFormat(
|
2024-07-23 17:50:40 -07:00
|
|
|
"Executable binary changed from \"%s\" to \"%s\".\n",
|
|
|
|
|
old_exec_module_sp->GetFileSpec().GetPath().c_str(),
|
|
|
|
|
new_exec_module_sp->GetFileSpec().GetPath().c_str());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-02-03 00:04:35 +00:00
|
|
|
|
2010-08-09 23:31:02 +00:00
|
|
|
if (!old_arch_spec.IsValid()) {
|
|
|
|
|
result.AppendMessageWithFormat(
|
2015-02-03 00:04:35 +00:00
|
|
|
"Architecture set to: %s.\n",
|
2010-08-09 23:31:02 +00:00
|
|
|
target->GetArchitecture().GetTriple().getTriple().c_str());
|
2015-02-03 00:04:35 +00:00
|
|
|
} else if (!old_arch_spec.IsExactMatch(target->GetArchitecture())) {
|
2010-08-09 23:31:02 +00:00
|
|
|
result.AppendWarningWithFormat(
|
|
|
|
|
"Architecture changed from %s to %s.\n",
|
2015-02-03 00:04:35 +00:00
|
|
|
old_arch_spec.GetTriple().getTriple().c_str(),
|
|
|
|
|
target->GetArchitecture().GetTriple().getTriple().c_str());
|
2010-08-09 23:31:02 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2018-04-30 16:49:04 +00:00
|
|
|
// This supports the use-case scenario of immediately continuing the
|
|
|
|
|
// process once attached.
|
2021-09-29 19:38:09 -07:00
|
|
|
if (m_options.attach_info.GetContinueOnceAttached()) {
|
|
|
|
|
// We have made a process but haven't told the interpreter about it yet,
|
|
|
|
|
// so CheckRequirements will fail for "process continue". Set the override
|
|
|
|
|
// here:
|
|
|
|
|
ExecutionContext exe_ctx(process_sp);
|
|
|
|
|
m_interpreter.HandleCommand("process continue", eLazyBoolNo, exe_ctx, result);
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-03-03 15:27:07 -08:00
|
|
|
CommandOptionsProcessAttach m_options;
|
|
|
|
|
OptionGroupPythonClassWithDict m_class_options;
|
|
|
|
|
OptionGroupOptions m_all_options;
|
2010-06-08 16:52:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CommandObjectProcessContinue
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2019-07-23 12:54:33 +00:00
|
|
|
#define LLDB_OPTIONS_process_continue
|
|
|
|
|
#include "CommandOptions.inc"
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessContinue
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessContinue : public CommandObjectParsed {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2010-09-18 01:14:36 +00:00
|
|
|
CommandObjectProcessContinue(CommandInterpreter &interpreter)
|
2012-06-08 21:56:10 +00:00
|
|
|
: CommandObjectParsed(
|
|
|
|
|
interpreter, "process continue",
|
|
|
|
|
"Continue execution of all threads in the current process.",
|
|
|
|
|
"process continue",
|
2015-05-27 05:04:35 +00:00
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
2022-01-23 11:07:14 -08:00
|
|
|
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessContinue() override = default;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2012-08-11 01:27:55 +00:00
|
|
|
class CommandOptions : public Options {
|
|
|
|
|
public:
|
2022-01-23 11:07:14 -08:00
|
|
|
CommandOptions() {
|
2012-08-11 01:27:55 +00:00
|
|
|
// Keep default values of all options in one place: OptionParsingStarting
|
2016-08-11 23:51:28 +00:00
|
|
|
// ()
|
|
|
|
|
OptionParsingStarting(nullptr);
|
2012-08-11 01:27:55 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
~CommandOptions() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
2022-06-07 18:03:23 -07:00
|
|
|
ExecutionContext *exe_ctx) override {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2010-09-18 01:14:36 +00:00
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
2010-06-08 16:52:24 +00:00
|
|
|
switch (short_option) {
|
|
|
|
|
case 'i':
|
2016-11-12 16:56:47 +00:00
|
|
|
if (option_arg.getAsInteger(0, m_ignore))
|
2024-08-27 10:59:31 -07:00
|
|
|
error = Status::FromErrorStringWithFormat(
|
2010-06-08 16:52:24 +00:00
|
|
|
"invalid value for ignore option: \"%s\", should be a number.",
|
2016-11-12 16:56:47 +00:00
|
|
|
option_arg.str().c_str());
|
2010-06-08 16:52:24 +00:00
|
|
|
break;
|
2022-06-07 18:03:23 -07:00
|
|
|
case 'b':
|
|
|
|
|
m_run_to_bkpt_args.AppendArgument(option_arg);
|
|
|
|
|
m_any_bkpts_specified = true;
|
2025-04-24 11:16:30 +12:00
|
|
|
break;
|
|
|
|
|
case 'F':
|
|
|
|
|
m_base_direction = lldb::RunDirection::eRunForward;
|
|
|
|
|
break;
|
|
|
|
|
case 'R':
|
|
|
|
|
m_base_direction = lldb::RunDirection::eRunReverse;
|
|
|
|
|
break;
|
2010-06-08 16:52:24 +00:00
|
|
|
default:
|
2019-08-22 08:08:05 +00:00
|
|
|
llvm_unreachable("Unimplemented option");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2012-08-11 01:27:55 +00:00
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
|
|
|
|
m_ignore = 0;
|
2022-06-07 18:03:23 -07:00
|
|
|
m_run_to_bkpt_args.Clear();
|
|
|
|
|
m_any_bkpts_specified = false;
|
2025-04-24 11:16:30 +12:00
|
|
|
m_base_direction = std::nullopt;
|
2012-09-10 20:50:15 +00:00
|
|
|
}
|
2014-08-12 14:33:19 +00:00
|
|
|
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_continue_options);
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
uint32_t m_ignore = 0;
|
|
|
|
|
Args m_run_to_bkpt_args;
|
|
|
|
|
bool m_any_bkpts_specified = false;
|
2025-04-24 11:16:30 +12:00
|
|
|
std::optional<lldb::RunDirection> m_base_direction;
|
2016-09-06 20:57:50 +00:00
|
|
|
};
|
|
|
|
|
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
2012-11-29 21:49:15 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
|
|
|
|
bool synchronous_execution = m_interpreter.GetSynchronous();
|
|
|
|
|
StateType state = process->GetState();
|
2010-06-08 16:52:24 +00:00
|
|
|
if (state == eStateStopped) {
|
2012-08-11 01:27:55 +00:00
|
|
|
if (m_options.m_ignore > 0) {
|
2014-10-21 01:00:42 +00:00
|
|
|
ThreadSP sel_thread_sp(GetDefaultThread()->shared_from_this());
|
2012-08-11 01:27:55 +00:00
|
|
|
if (sel_thread_sp) {
|
|
|
|
|
StopInfoSP stop_info_sp = sel_thread_sp->GetStopInfo();
|
2014-10-21 01:00:42 +00:00
|
|
|
if (stop_info_sp &&
|
|
|
|
|
stop_info_sp->GetStopReason() == eStopReasonBreakpoint) {
|
2013-01-25 18:06:21 +00:00
|
|
|
lldb::break_id_t bp_site_id =
|
2010-06-08 16:52:24 +00:00
|
|
|
(lldb::break_id_t)stop_info_sp->GetValue();
|
|
|
|
|
BreakpointSiteSP bp_site_sp(
|
|
|
|
|
process->GetBreakpointSiteList().FindByID(bp_site_id));
|
2012-08-11 01:27:55 +00:00
|
|
|
if (bp_site_sp) {
|
[lldb] [mostly NFC] Large WP foundation: WatchpointResources (#68845)
This patch is rearranging code a bit to add WatchpointResources to
Process. A WatchpointResource is meant to represent a hardware
watchpoint register in the inferior process. It has an address, a size,
a type, and a list of Watchpoints that are using this
WatchpointResource.
This current patch doesn't add any of the features of
WatchpointResources that make them interesting -- a user asking to watch
a 24 byte object could watch this with three 8 byte WatchpointResources.
Or a Watchpoint on 1 byte at 0x1002 and a second watchpoint on 1 byte at
0x1003, these must both be served by a single WatchpointResource on that
doubleword at 0x1000 on a 64-bit target, if two hardware watchpoint
registers were used to track these separately, one of them may not be
hit. Or if you have one Watchpoint on a variable with a condition set,
and another Watchpoint on that same variable with a command defined or
different condition, or ignorecount, both of those Watchpoints need to
evaluate their criteria/commands when their WatchpointResource has been
hit.
There's a bit of code movement to rearrange things in the direction I'll
need for implementing this feature, so I want to start with reviewing &
landing this mostly NFC patch and we can focus on the algorithmic
choices about how WatchpointResources are shared and handled as they're
triggeed, separately.
This patch also stops printing "Watchpoint <n> hit: old value: <x>, new
vlaue: <y>" for Read watchpoints. I could make an argument for print
"Watchpoint <n> hit: current value <x>" but the current output doesn't
make any sense, and the user can print the value if they are
particularly interested. Read watchpoints are used primarily to
understand what code is reading a variable.
This patch adds more fallbacks for how to print the objects being
watched if we have types, instead of assuming they are all integral
values, so a struct will print its elements. As large watchpoints are
added, we'll be doing a lot more of those.
To track the WatchpointSP in the WatchpointResources, I changed the
internal API which took a WatchpointSP and devolved it to a Watchpoint*,
which meant touching several different Process files. I removed the
watchpoint code in ProcessKDP which only reported that watchpoints
aren't supported, the base class does that already.
I haven't yet changed how we receive a watchpoint to identify the
WatchpointResource responsible for the trigger, and identify all
Watchpoints that are using this Resource to evaluate their conditions
etc. This is the same work that a BreakpointSite needs to do when it has
been tiggered, where multiple Breakpoints may be at the same address.
There is not yet any printing of the Resources that a Watchpoint is
implemented in terms of ("watchpoint list", or
SBWatchpoint::GetDescription).
"watchpoint set var" and "watchpoint set expression" take a size
argument which was previously 1, 2, 4, or 8 (an enum). I've changed this
to an unsigned int. Most hardware implementations can only watch 1, 2,
4, 8 byte ranges, but with Resources we'll allow a user to ask for
different sized watchpoints and set them in hardware-expressble terms
soon.
I've annotated areas where I know there is work still needed with
LWP_TODO that I'll be working on once this is landed.
I've tested this on aarch64 macOS, aarch64 Linux, and Intel macOS.
https://discourse.llvm.org/t/rfc-large-watchpoint-support-in-lldb/72116
(cherry picked from commit fc6b72523f3d73b921690a713e97a433c96066c6)
2023-11-27 13:28:59 -08:00
|
|
|
const size_t num_owners = bp_site_sp->GetNumberOfConstituents();
|
2013-01-25 18:06:21 +00:00
|
|
|
for (size_t i = 0; i < num_owners; i++) {
|
2012-08-11 01:27:55 +00:00
|
|
|
Breakpoint &bp_ref =
|
[lldb] [mostly NFC] Large WP foundation: WatchpointResources (#68845)
This patch is rearranging code a bit to add WatchpointResources to
Process. A WatchpointResource is meant to represent a hardware
watchpoint register in the inferior process. It has an address, a size,
a type, and a list of Watchpoints that are using this
WatchpointResource.
This current patch doesn't add any of the features of
WatchpointResources that make them interesting -- a user asking to watch
a 24 byte object could watch this with three 8 byte WatchpointResources.
Or a Watchpoint on 1 byte at 0x1002 and a second watchpoint on 1 byte at
0x1003, these must both be served by a single WatchpointResource on that
doubleword at 0x1000 on a 64-bit target, if two hardware watchpoint
registers were used to track these separately, one of them may not be
hit. Or if you have one Watchpoint on a variable with a condition set,
and another Watchpoint on that same variable with a command defined or
different condition, or ignorecount, both of those Watchpoints need to
evaluate their criteria/commands when their WatchpointResource has been
hit.
There's a bit of code movement to rearrange things in the direction I'll
need for implementing this feature, so I want to start with reviewing &
landing this mostly NFC patch and we can focus on the algorithmic
choices about how WatchpointResources are shared and handled as they're
triggeed, separately.
This patch also stops printing "Watchpoint <n> hit: old value: <x>, new
vlaue: <y>" for Read watchpoints. I could make an argument for print
"Watchpoint <n> hit: current value <x>" but the current output doesn't
make any sense, and the user can print the value if they are
particularly interested. Read watchpoints are used primarily to
understand what code is reading a variable.
This patch adds more fallbacks for how to print the objects being
watched if we have types, instead of assuming they are all integral
values, so a struct will print its elements. As large watchpoints are
added, we'll be doing a lot more of those.
To track the WatchpointSP in the WatchpointResources, I changed the
internal API which took a WatchpointSP and devolved it to a Watchpoint*,
which meant touching several different Process files. I removed the
watchpoint code in ProcessKDP which only reported that watchpoints
aren't supported, the base class does that already.
I haven't yet changed how we receive a watchpoint to identify the
WatchpointResource responsible for the trigger, and identify all
Watchpoints that are using this Resource to evaluate their conditions
etc. This is the same work that a BreakpointSite needs to do when it has
been tiggered, where multiple Breakpoints may be at the same address.
There is not yet any printing of the Resources that a Watchpoint is
implemented in terms of ("watchpoint list", or
SBWatchpoint::GetDescription).
"watchpoint set var" and "watchpoint set expression" take a size
argument which was previously 1, 2, 4, or 8 (an enum). I've changed this
to an unsigned int. Most hardware implementations can only watch 1, 2,
4, 8 byte ranges, but with Resources we'll allow a user to ask for
different sized watchpoints and set them in hardware-expressble terms
soon.
I've annotated areas where I know there is work still needed with
LWP_TODO that I'll be working on once this is landed.
I've tested this on aarch64 macOS, aarch64 Linux, and Intel macOS.
https://discourse.llvm.org/t/rfc-large-watchpoint-support-in-lldb/72116
(cherry picked from commit fc6b72523f3d73b921690a713e97a433c96066c6)
2023-11-27 13:28:59 -08:00
|
|
|
bp_site_sp->GetConstituentAtIndex(i)->GetBreakpoint();
|
2010-06-08 16:52:24 +00:00
|
|
|
if (!bp_ref.IsInternal()) {
|
|
|
|
|
bp_ref.SetIgnoreCount(m_options.m_ignore);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2024-08-02 09:51:47 -07:00
|
|
|
Target &target = GetTarget();
|
2022-06-07 18:03:23 -07:00
|
|
|
BreakpointIDList run_to_bkpt_ids;
|
2022-06-22 12:16:24 -07:00
|
|
|
// Don't pass an empty run_to_breakpoint list, as Verify will look for the
|
|
|
|
|
// default breakpoint.
|
|
|
|
|
if (m_options.m_run_to_bkpt_args.GetArgumentCount() > 0)
|
|
|
|
|
CommandObjectMultiwordBreakpoint::VerifyBreakpointOrLocationIDs(
|
2022-07-06 16:05:25 -07:00
|
|
|
m_options.m_run_to_bkpt_args, target, result, &run_to_bkpt_ids,
|
2022-06-22 12:16:24 -07:00
|
|
|
BreakpointName::Permissions::disablePerm);
|
2022-06-07 18:03:23 -07:00
|
|
|
if (!result.Succeeded()) {
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-06-07 18:03:23 -07:00
|
|
|
}
|
|
|
|
|
result.Clear();
|
|
|
|
|
if (m_options.m_any_bkpts_specified && run_to_bkpt_ids.GetSize() == 0) {
|
|
|
|
|
result.AppendError("continue-to breakpoints did not specify any actual "
|
|
|
|
|
"breakpoints or locations");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-06-07 18:03:23 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// First figure out which breakpoints & locations were specified by the
|
|
|
|
|
// user:
|
|
|
|
|
size_t num_run_to_bkpt_ids = run_to_bkpt_ids.GetSize();
|
|
|
|
|
std::vector<break_id_t> bkpts_disabled;
|
|
|
|
|
std::vector<BreakpointID> locs_disabled;
|
|
|
|
|
if (num_run_to_bkpt_ids != 0) {
|
2022-07-06 16:05:25 -07:00
|
|
|
// Go through the ID's specified, and separate the breakpoints from are
|
2022-06-07 18:03:23 -07:00
|
|
|
// the breakpoint.location specifications since the latter require
|
|
|
|
|
// special handling. We also figure out whether there's at least one
|
|
|
|
|
// specifier in the set that is enabled.
|
2024-08-02 09:51:47 -07:00
|
|
|
BreakpointList &bkpt_list = target.GetBreakpointList();
|
2022-06-07 18:03:23 -07:00
|
|
|
std::unordered_set<break_id_t> bkpts_seen;
|
|
|
|
|
std::unordered_set<break_id_t> bkpts_with_locs_seen;
|
|
|
|
|
BreakpointIDList with_locs;
|
|
|
|
|
bool any_enabled = false;
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
for (size_t idx = 0; idx < num_run_to_bkpt_ids; idx++) {
|
|
|
|
|
BreakpointID bkpt_id = run_to_bkpt_ids.GetBreakpointIDAtIndex(idx);
|
|
|
|
|
break_id_t bp_id = bkpt_id.GetBreakpointID();
|
|
|
|
|
break_id_t loc_id = bkpt_id.GetLocationID();
|
2022-07-06 16:05:25 -07:00
|
|
|
BreakpointSP bp_sp
|
2022-06-07 18:03:23 -07:00
|
|
|
= bkpt_list.FindBreakpointByID(bp_id);
|
2022-07-06 16:05:25 -07:00
|
|
|
// Note, VerifyBreakpointOrLocationIDs checks for existence, so we
|
2022-06-07 18:03:23 -07:00
|
|
|
// don't need to do it again here.
|
|
|
|
|
if (bp_sp->IsEnabled()) {
|
|
|
|
|
if (loc_id == LLDB_INVALID_BREAK_ID) {
|
2022-07-06 16:05:25 -07:00
|
|
|
// A breakpoint (without location) was specified. Make sure that
|
2022-06-07 18:03:23 -07:00
|
|
|
// at least one of the locations is enabled.
|
|
|
|
|
size_t num_locations = bp_sp->GetNumLocations();
|
|
|
|
|
for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) {
|
2022-07-06 16:05:25 -07:00
|
|
|
BreakpointLocationSP loc_sp
|
2022-06-07 18:03:23 -07:00
|
|
|
= bp_sp->GetLocationAtIndex(loc_idx);
|
|
|
|
|
if (loc_sp->IsEnabled()) {
|
|
|
|
|
any_enabled = true;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
// A location was specified, check if it was enabled:
|
|
|
|
|
BreakpointLocationSP loc_sp = bp_sp->FindLocationByID(loc_id);
|
|
|
|
|
if (loc_sp->IsEnabled())
|
|
|
|
|
any_enabled = true;
|
|
|
|
|
}
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
// Then sort the bp & bp.loc entries for later use:
|
|
|
|
|
if (bkpt_id.GetLocationID() == LLDB_INVALID_BREAK_ID)
|
|
|
|
|
bkpts_seen.insert(bkpt_id.GetBreakpointID());
|
|
|
|
|
else {
|
|
|
|
|
bkpts_with_locs_seen.insert(bkpt_id.GetBreakpointID());
|
|
|
|
|
with_locs.AddBreakpointID(bkpt_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
// Do all the error checking here so once we start disabling we don't
|
|
|
|
|
// have to back out half-way through.
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
// Make sure at least one of the specified breakpoints is enabled.
|
|
|
|
|
if (!any_enabled) {
|
|
|
|
|
result.AppendError("at least one of the continue-to breakpoints must "
|
|
|
|
|
"be enabled.");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-06-07 18:03:23 -07:00
|
|
|
}
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
// Also, if you specify BOTH a breakpoint and one of it's locations,
|
|
|
|
|
// we flag that as an error, since it won't do what you expect, the
|
|
|
|
|
// breakpoint directive will mean "run to all locations", which is not
|
|
|
|
|
// what the location directive means...
|
|
|
|
|
for (break_id_t bp_id : bkpts_with_locs_seen) {
|
|
|
|
|
if (bkpts_seen.count(bp_id)) {
|
|
|
|
|
result.AppendErrorWithFormatv("can't specify both a breakpoint and "
|
|
|
|
|
"one of its locations: {0}", bp_id);
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
// Now go through the breakpoints in the target, disabling all the ones
|
|
|
|
|
// that the user didn't mention:
|
|
|
|
|
for (BreakpointSP bp_sp : bkpt_list.Breakpoints()) {
|
|
|
|
|
break_id_t bp_id = bp_sp->GetID();
|
|
|
|
|
// Handle the case where no locations were specified. Note we don't
|
|
|
|
|
// have to worry about the case where a breakpoint and one of its
|
|
|
|
|
// locations are both in the lists, we've already disallowed that.
|
|
|
|
|
if (!bkpts_with_locs_seen.count(bp_id)) {
|
|
|
|
|
if (!bkpts_seen.count(bp_id) && bp_sp->IsEnabled()) {
|
|
|
|
|
bkpts_disabled.push_back(bp_id);
|
|
|
|
|
bp_sp->SetEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
continue;
|
|
|
|
|
}
|
|
|
|
|
// Next, handle the case where a location was specified:
|
|
|
|
|
// Run through all the locations of this breakpoint and disable
|
|
|
|
|
// the ones that aren't on our "with locations" BreakpointID list:
|
|
|
|
|
size_t num_locations = bp_sp->GetNumLocations();
|
|
|
|
|
BreakpointID tmp_id(bp_id, LLDB_INVALID_BREAK_ID);
|
|
|
|
|
for (size_t loc_idx = 0; loc_idx < num_locations; loc_idx++) {
|
|
|
|
|
BreakpointLocationSP loc_sp = bp_sp->GetLocationAtIndex(loc_idx);
|
|
|
|
|
tmp_id.SetBreakpointLocationID(loc_idx);
|
2024-01-26 10:19:03 -08:00
|
|
|
if (!with_locs.Contains(tmp_id) && loc_sp->IsEnabled()) {
|
2022-06-07 18:03:23 -07:00
|
|
|
locs_disabled.push_back(tmp_id);
|
|
|
|
|
loc_sp->SetEnabled(false);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-09-10 20:50:15 +00:00
|
|
|
{ // Scope for thread list mutex:
|
2016-05-19 05:13:57 +00:00
|
|
|
std::lock_guard<std::recursive_mutex> guard(
|
|
|
|
|
process->GetThreadList().GetMutex());
|
2012-09-10 20:50:15 +00:00
|
|
|
const uint32_t num_threads = process->GetThreadList().GetSize();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-09-10 20:50:15 +00:00
|
|
|
// Set the actions that the threads should each take when resuming
|
|
|
|
|
for (uint32_t idx = 0; idx < num_threads; ++idx) {
|
2014-04-03 01:26:14 +00:00
|
|
|
const bool override_suspend = false;
|
|
|
|
|
process->GetThreadList().GetThreadAtIndex(idx)->SetResumeState(
|
|
|
|
|
eStateRunning, override_suspend);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-04-24 11:16:30 +12:00
|
|
|
if (m_options.m_base_direction.has_value())
|
|
|
|
|
process->SetBaseDirection(*m_options.m_base_direction);
|
|
|
|
|
|
2015-05-27 12:40:32 +00:00
|
|
|
const uint32_t iohandler_id = process->GetIOHandlerID();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-10-21 01:00:42 +00:00
|
|
|
StreamString stream;
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2022-06-07 18:03:23 -07:00
|
|
|
// For now we can only do -b with synchronous:
|
|
|
|
|
bool old_sync = GetDebugger().GetAsyncExecution();
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
if (run_to_bkpt_ids.GetSize() != 0) {
|
|
|
|
|
GetDebugger().SetAsyncExecution(false);
|
|
|
|
|
synchronous_execution = true;
|
2022-07-06 16:05:25 -07:00
|
|
|
}
|
2014-10-21 01:00:42 +00:00
|
|
|
if (synchronous_execution)
|
|
|
|
|
error = process->ResumeSynchronous(&stream);
|
2010-06-08 16:52:24 +00:00
|
|
|
else
|
2014-10-21 01:00:42 +00:00
|
|
|
error = process->Resume();
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
if (run_to_bkpt_ids.GetSize() != 0) {
|
|
|
|
|
GetDebugger().SetAsyncExecution(old_sync);
|
2022-07-06 16:05:25 -07:00
|
|
|
}
|
|
|
|
|
|
2022-06-07 18:03:23 -07:00
|
|
|
// Now re-enable the breakpoints we disabled:
|
2024-08-02 09:51:47 -07:00
|
|
|
BreakpointList &bkpt_list = target.GetBreakpointList();
|
2022-06-07 18:03:23 -07:00
|
|
|
for (break_id_t bp_id : bkpts_disabled) {
|
|
|
|
|
BreakpointSP bp_sp = bkpt_list.FindBreakpointByID(bp_id);
|
|
|
|
|
if (bp_sp)
|
|
|
|
|
bp_sp->SetEnabled(true);
|
|
|
|
|
}
|
|
|
|
|
for (const BreakpointID &bkpt_id : locs_disabled) {
|
2022-07-06 16:05:25 -07:00
|
|
|
BreakpointSP bp_sp
|
2022-06-07 18:03:23 -07:00
|
|
|
= bkpt_list.FindBreakpointByID(bkpt_id.GetBreakpointID());
|
|
|
|
|
if (bp_sp) {
|
2022-07-06 16:05:25 -07:00
|
|
|
BreakpointLocationSP loc_sp
|
2022-06-07 18:03:23 -07:00
|
|
|
= bp_sp->FindLocationByID(bkpt_id.GetLocationID());
|
|
|
|
|
if (loc_sp)
|
|
|
|
|
loc_sp->SetEnabled(true);
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
if (error.Success()) {
|
2014-08-12 14:33:19 +00:00
|
|
|
// There is a race condition where this thread will return up the call
|
2018-04-30 16:49:04 +00:00
|
|
|
// stack to the main command handler and show an (lldb) prompt before
|
|
|
|
|
// HandlePrivateEvent (from PrivateStateThread) has a chance to call
|
|
|
|
|
// PushProcessIOHandler().
|
2018-05-09 14:29:30 +00:00
|
|
|
process->SyncIOHandler(iohandler_id, std::chrono::seconds(2));
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-12-08 14:08:19 +00:00
|
|
|
result.AppendMessageWithFormat("Process %" PRIu64 " resuming\n",
|
|
|
|
|
process->GetID());
|
2014-10-21 01:00:42 +00:00
|
|
|
if (synchronous_execution) {
|
|
|
|
|
// If any state changed events had anything to say, add that to the
|
2016-09-06 20:57:50 +00:00
|
|
|
// result
|
2016-11-16 21:15:24 +00:00
|
|
|
result.AppendMessage(stream.GetString());
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2014-04-03 01:26:14 +00:00
|
|
|
result.SetDidChangeProcessState(true);
|
2015-02-03 00:04:35 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessContinuingNoResult);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.AppendErrorWithFormat("Failed to resume process: %s.\n",
|
|
|
|
|
error.AsCString());
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"Process cannot be continued from its current state (%s).\n",
|
|
|
|
|
StateAsCString(state));
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2012-08-11 01:27:55 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-08-11 01:27:55 +00:00
|
|
|
CommandOptions m_options;
|
|
|
|
|
};
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
// CommandObjectProcessDetach
|
2019-07-23 12:54:33 +00:00
|
|
|
#define LLDB_OPTIONS_process_detach
|
|
|
|
|
#include "CommandOptions.inc"
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessDetach
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessDetach : public CommandObjectParsed {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2013-05-02 00:27:30 +00:00
|
|
|
class CommandOptions : public Options {
|
|
|
|
|
public:
|
2022-01-23 11:07:14 -08:00
|
|
|
CommandOptions() { OptionParsingStarting(nullptr); }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandOptions() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
Status error;
|
2013-05-02 00:27:30 +00:00
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2013-05-02 00:27:30 +00:00
|
|
|
switch (short_option) {
|
|
|
|
|
case 's':
|
|
|
|
|
bool tmp_result;
|
|
|
|
|
bool success;
|
2018-04-10 09:03:59 +00:00
|
|
|
tmp_result = OptionArgParser::ToBoolean(option_arg, false, &success);
|
2013-05-02 00:27:30 +00:00
|
|
|
if (!success)
|
2024-08-27 10:59:31 -07:00
|
|
|
error = Status::FromErrorStringWithFormat(
|
|
|
|
|
"invalid boolean option: \"%s\"", option_arg.str().c_str());
|
2013-05-02 00:27:30 +00:00
|
|
|
else {
|
|
|
|
|
if (tmp_result)
|
|
|
|
|
m_keep_stopped = eLazyBoolYes;
|
|
|
|
|
else
|
|
|
|
|
m_keep_stopped = eLazyBoolNo;
|
|
|
|
|
}
|
|
|
|
|
break;
|
|
|
|
|
default:
|
2019-08-22 08:08:05 +00:00
|
|
|
llvm_unreachable("Unimplemented option");
|
2013-05-02 00:27:30 +00:00
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 23:51:28 +00:00
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
2013-05-02 00:27:30 +00:00
|
|
|
m_keep_stopped = eLazyBoolCalculate;
|
|
|
|
|
}
|
|
|
|
|
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_detach_options);
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
}
|
2013-05-02 00:27:30 +00:00
|
|
|
|
|
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
|
LazyBool m_keep_stopped;
|
|
|
|
|
};
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessDetach(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process detach",
|
|
|
|
|
"Detach from the current target process.",
|
|
|
|
|
"process detach",
|
|
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
2022-01-23 11:07:14 -08:00
|
|
|
eCommandProcessMustBeLaunched) {}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessDetach() override = default;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2013-05-02 00:27:30 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2013-05-02 00:27:30 +00:00
|
|
|
// FIXME: This will be a Command Option:
|
|
|
|
|
bool keep_stopped;
|
|
|
|
|
if (m_options.m_keep_stopped == eLazyBoolCalculate) {
|
|
|
|
|
// Check the process default:
|
2016-02-23 01:43:44 +00:00
|
|
|
keep_stopped = process->GetDetachKeepsStopped();
|
2013-05-02 00:27:30 +00:00
|
|
|
} else if (m_options.m_keep_stopped == eLazyBoolYes)
|
|
|
|
|
keep_stopped = true;
|
|
|
|
|
else
|
|
|
|
|
keep_stopped = false;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error(process->Detach(keep_stopped));
|
2010-06-08 16:52:24 +00:00
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("Detach failed: %s\n", error.AsCString());
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2013-05-02 00:27:30 +00:00
|
|
|
|
|
|
|
|
CommandOptions m_options;
|
|
|
|
|
};
|
|
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
// CommandObjectProcessConnect
|
2019-07-23 12:54:33 +00:00
|
|
|
#define LLDB_OPTIONS_process_connect
|
|
|
|
|
#include "CommandOptions.inc"
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
#pragma mark CommandObjectProcessConnect
|
|
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessConnect : public CommandObjectParsed {
|
2011-02-04 01:58:07 +00:00
|
|
|
public:
|
|
|
|
|
class CommandOptions : public Options {
|
2011-04-13 00:18:08 +00:00
|
|
|
public:
|
2022-01-23 11:07:14 -08:00
|
|
|
CommandOptions() {
|
2016-08-11 23:51:28 +00:00
|
|
|
// Keep default values of all options in one place: OptionParsingStarting
|
2011-02-04 01:58:07 +00:00
|
|
|
// ()
|
2011-03-24 21:19:54 +00:00
|
|
|
OptionParsingStarting(nullptr);
|
2011-02-04 01:58:07 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandOptions() override = default;
|
|
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
Status error;
|
2015-10-07 16:56:17 +00:00
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
switch (short_option) {
|
2011-02-04 01:58:07 +00:00
|
|
|
case 'p':
|
2020-01-28 20:23:46 +01:00
|
|
|
plugin_name.assign(std::string(option_arg));
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2019-08-22 08:08:05 +00:00
|
|
|
llvm_unreachable("Unimplemented option");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2011-02-04 01:58:07 +00:00
|
|
|
return error;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
2012-06-08 21:56:10 +00:00
|
|
|
plugin_name.clear();
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_connect_options);
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
// Instance variables to hold the values for command options.
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
std::string plugin_name;
|
2016-09-06 20:57:50 +00:00
|
|
|
};
|
|
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
CommandObjectProcessConnect(CommandInterpreter &interpreter)
|
2016-07-14 22:03:10 +00:00
|
|
|
: CommandObjectParsed(interpreter, "process connect",
|
2012-06-08 21:56:10 +00:00
|
|
|
"Connect to a remote debug service.",
|
2022-06-23 09:33:40 -07:00
|
|
|
"process connect <remote-url>", 0) {
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypeConnectURL);
|
2022-06-23 09:33:40 -07:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessConnect() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-08-26 23:28:47 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
2015-12-08 14:08:19 +00:00
|
|
|
if (command.GetArgumentCount() != 1) {
|
|
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"'%s' takes exactly one argument:\nUsage: %s\n", m_cmd_name.c_str(),
|
|
|
|
|
m_cmd_syntax.c_str());
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2011-02-04 01:58:07 +00:00
|
|
|
}
|
2015-12-08 14:08:19 +00:00
|
|
|
|
|
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
|
|
|
|
if (process && process->IsAlive()) {
|
|
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"Process %" PRIu64
|
|
|
|
|
" is currently being debugged, kill the process before connecting.\n",
|
|
|
|
|
process->GetID());
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2011-02-04 01:58:07 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-08 14:08:19 +00:00
|
|
|
const char *plugin_name = nullptr;
|
|
|
|
|
if (!m_options.plugin_name.empty())
|
|
|
|
|
plugin_name = m_options.plugin_name.c_str();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2019-04-27 06:19:42 +00:00
|
|
|
Debugger &debugger = GetDebugger();
|
2015-12-08 14:08:19 +00:00
|
|
|
PlatformSP platform_sp = m_interpreter.GetPlatform(true);
|
2020-07-14 08:44:40 -07:00
|
|
|
ProcessSP process_sp =
|
|
|
|
|
debugger.GetAsyncExecution()
|
|
|
|
|
? platform_sp->ConnectProcess(
|
|
|
|
|
command.GetArgumentAtIndex(0), plugin_name, debugger,
|
|
|
|
|
debugger.GetSelectedTarget().get(), error)
|
|
|
|
|
: platform_sp->ConnectProcessSynchronous(
|
|
|
|
|
command.GetArgumentAtIndex(0), plugin_name, debugger,
|
|
|
|
|
result.GetOutputStream(), debugger.GetSelectedTarget().get(),
|
|
|
|
|
error);
|
2015-12-08 14:08:19 +00:00
|
|
|
if (error.Fail() || process_sp == nullptr) {
|
|
|
|
|
result.AppendError(error.AsCString("Error connecting to the process"));
|
2011-02-04 01:58:07 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-12-08 14:08:19 +00:00
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
CommandOptions m_options;
|
|
|
|
|
};
|
|
|
|
|
|
2012-10-13 02:07:45 +00:00
|
|
|
// CommandObjectProcessPlugin
|
|
|
|
|
#pragma mark CommandObjectProcessPlugin
|
|
|
|
|
|
|
|
|
|
class CommandObjectProcessPlugin : public CommandObjectProxy {
|
|
|
|
|
public:
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessPlugin(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectProxy(
|
|
|
|
|
interpreter, "process plugin",
|
|
|
|
|
"Send a custom command to the current target process plug-in.",
|
|
|
|
|
"process plugin <args>", 0) {}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessPlugin() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
CommandObject *GetProxyCommandObject() override {
|
2013-01-09 22:58:18 +00:00
|
|
|
Process *process = m_interpreter.GetExecutionContext().GetProcessPtr();
|
2012-10-13 02:07:45 +00:00
|
|
|
if (process)
|
|
|
|
|
return process->GetPluginCommandObject();
|
2016-02-23 01:43:44 +00:00
|
|
|
return nullptr;
|
2012-10-13 02:07:45 +00:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2010-11-04 01:54:29 +00:00
|
|
|
// CommandObjectProcessLoad
|
2019-07-23 12:54:33 +00:00
|
|
|
#define LLDB_OPTIONS_process_load
|
|
|
|
|
#include "CommandOptions.inc"
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessLoad
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessLoad : public CommandObjectParsed {
|
2010-11-04 01:54:29 +00:00
|
|
|
public:
|
2015-12-08 13:43:59 +00:00
|
|
|
class CommandOptions : public Options {
|
|
|
|
|
public:
|
2022-01-23 11:07:14 -08:00
|
|
|
CommandOptions() {
|
2015-12-08 13:43:59 +00:00
|
|
|
// Keep default values of all options in one place: OptionParsingStarting
|
|
|
|
|
// ()
|
2016-08-11 23:51:28 +00:00
|
|
|
OptionParsingStarting(nullptr);
|
2015-12-08 13:43:59 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandOptions() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
Status error;
|
2015-12-08 13:43:59 +00:00
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
2024-07-16 15:21:06 +02:00
|
|
|
ArchSpec arch =
|
|
|
|
|
execution_context->GetProcessPtr()->GetSystemArchitecture();
|
2015-12-08 13:43:59 +00:00
|
|
|
switch (short_option) {
|
|
|
|
|
case 'i':
|
|
|
|
|
do_install = true;
|
2016-11-12 16:56:47 +00:00
|
|
|
if (!option_arg.empty())
|
2024-07-16 15:21:06 +02:00
|
|
|
install_path.SetFile(option_arg, arch.GetTriple());
|
2015-12-08 13:43:59 +00:00
|
|
|
break;
|
|
|
|
|
default:
|
2019-08-22 08:08:05 +00:00
|
|
|
llvm_unreachable("Unimplemented option");
|
2015-12-08 13:43:59 +00:00
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 23:51:28 +00:00
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
2015-12-08 13:43:59 +00:00
|
|
|
do_install = false;
|
|
|
|
|
install_path.Clear();
|
|
|
|
|
}
|
|
|
|
|
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_load_options);
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
|
bool do_install;
|
|
|
|
|
FileSpec install_path;
|
2016-09-06 20:57:50 +00:00
|
|
|
};
|
2015-12-08 13:43:59 +00:00
|
|
|
|
|
|
|
|
CommandObjectProcessLoad(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process load",
|
|
|
|
|
"Load a shared library into the current process.",
|
2012-06-08 21:56:10 +00:00
|
|
|
"process load <filename> [<filename> ...]",
|
2015-12-08 13:43:59 +00:00
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
2015-05-27 05:04:35 +00:00
|
|
|
eCommandProcessMustBeLaunched |
|
2022-06-23 09:33:40 -07:00
|
|
|
eCommandProcessMustBePaused) {
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypePath, eArgRepeatPlus);
|
2022-06-23 09:33:40 -07:00
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2015-12-08 13:43:59 +00:00
|
|
|
~CommandObjectProcessLoad() override = default;
|
|
|
|
|
|
2020-08-21 09:57:18 +02:00
|
|
|
void
|
|
|
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
|
|
|
OptionElementVector &opt_element_vector) override {
|
|
|
|
|
if (!m_exe_ctx.HasProcessScope())
|
|
|
|
|
return;
|
2024-02-20 14:18:03 -08:00
|
|
|
CommandObject::HandleArgumentCompletion(request, opt_element_vector);
|
2020-08-21 09:57:18 +02:00
|
|
|
}
|
|
|
|
|
|
2016-08-26 23:28:47 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-10-05 23:40:23 +00:00
|
|
|
for (auto &entry : command.entries()) {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error;
|
2015-12-02 11:58:51 +00:00
|
|
|
PlatformSP platform = process->GetTarget().GetPlatform();
|
2019-09-13 11:26:48 +00:00
|
|
|
llvm::StringRef image_path = entry.ref();
|
2015-12-08 13:43:59 +00:00
|
|
|
uint32_t image_token = LLDB_INVALID_IMAGE_TOKEN;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-12-08 13:43:59 +00:00
|
|
|
if (!m_options.do_install) {
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec image_spec(image_path);
|
2015-12-08 13:43:59 +00:00
|
|
|
platform->ResolveRemotePath(image_spec, image_spec);
|
|
|
|
|
image_token =
|
|
|
|
|
platform->LoadImage(process, FileSpec(), image_spec, error);
|
|
|
|
|
} else if (m_options.install_path) {
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec image_spec(image_path);
|
|
|
|
|
FileSystem::Instance().Resolve(image_spec);
|
2015-12-08 13:43:59 +00:00
|
|
|
platform->ResolveRemotePath(m_options.install_path,
|
|
|
|
|
m_options.install_path);
|
|
|
|
|
image_token = platform->LoadImage(process, image_spec,
|
|
|
|
|
m_options.install_path, error);
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec image_spec(image_path);
|
|
|
|
|
FileSystem::Instance().Resolve(image_spec);
|
2015-12-08 13:43:59 +00:00
|
|
|
image_token =
|
|
|
|
|
platform->LoadImage(process, image_spec, FileSpec(), error);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2010-11-04 01:54:29 +00:00
|
|
|
if (image_token != LLDB_INVALID_IMAGE_TOKEN) {
|
2015-12-08 13:43:59 +00:00
|
|
|
result.AppendMessageWithFormat(
|
2016-10-05 23:40:23 +00:00
|
|
|
"Loading \"%s\"...ok\nImage %u loaded.\n", image_path.str().c_str(),
|
|
|
|
|
image_token);
|
2010-11-04 01:54:29 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
2016-10-05 23:40:23 +00:00
|
|
|
result.AppendErrorWithFormat("failed to load '%s': %s",
|
|
|
|
|
image_path.str().c_str(),
|
2010-11-04 01:54:29 +00:00
|
|
|
error.AsCString());
|
|
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-12-08 13:43:59 +00:00
|
|
|
CommandOptions m_options;
|
2010-11-04 01:54:29 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CommandObjectProcessUnload
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessUnload
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessUnload : public CommandObjectParsed {
|
2010-11-04 01:54:29 +00:00
|
|
|
public:
|
|
|
|
|
CommandObjectProcessUnload(CommandInterpreter &interpreter)
|
2016-07-14 22:03:10 +00:00
|
|
|
: CommandObjectParsed(
|
|
|
|
|
interpreter, "process unload",
|
2012-06-08 21:56:10 +00:00
|
|
|
"Unload a shared library from the current process using the index "
|
|
|
|
|
"returned by a previous call to \"process load\".",
|
|
|
|
|
"process unload <index>",
|
2016-07-14 22:03:10 +00:00
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
2022-06-23 09:33:40 -07:00
|
|
|
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypeUnsignedInteger);
|
2022-06-23 09:33:40 -07:00
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessUnload() override = default;
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2020-08-21 09:57:18 +02:00
|
|
|
void
|
|
|
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
|
|
|
OptionElementVector &opt_element_vector) override {
|
|
|
|
|
|
|
|
|
|
if (request.GetCursorIndex() || !m_exe_ctx.HasProcessScope())
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
|
|
|
|
|
|
|
|
|
const std::vector<lldb::addr_t> &tokens = process->GetImageTokens();
|
|
|
|
|
const size_t token_num = tokens.size();
|
|
|
|
|
for (size_t i = 0; i < token_num; ++i) {
|
|
|
|
|
if (tokens[i] == LLDB_INVALID_IMAGE_TOKEN)
|
|
|
|
|
continue;
|
|
|
|
|
request.TryCompleteCurrentArg(std::to_string(i));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-10-05 23:40:23 +00:00
|
|
|
for (auto &entry : command.entries()) {
|
|
|
|
|
uint32_t image_token;
|
2019-09-13 11:26:48 +00:00
|
|
|
if (entry.ref().getAsInteger(0, image_token)) {
|
2010-11-04 01:54:29 +00:00
|
|
|
result.AppendErrorWithFormat("invalid image index argument '%s'",
|
2019-09-13 11:26:48 +00:00
|
|
|
entry.ref().str().c_str());
|
2010-11-04 01:54:29 +00:00
|
|
|
break;
|
|
|
|
|
} else {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error(process->GetTarget().GetPlatform()->UnloadImage(
|
2015-12-02 11:58:51 +00:00
|
|
|
process, image_token));
|
2010-11-04 01:54:29 +00:00
|
|
|
if (error.Success()) {
|
|
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Unloading shared library with index %u...ok\n", image_token);
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("failed to unload image: %s",
|
|
|
|
|
error.AsCString());
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
};
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
// CommandObjectProcessSignal
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessSignal
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessSignal : public CommandObjectParsed {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessSignal(CommandInterpreter &interpreter)
|
2019-10-30 15:26:19 -07:00
|
|
|
: CommandObjectParsed(
|
|
|
|
|
interpreter, "process signal",
|
|
|
|
|
"Send a UNIX signal to the current target process.", nullptr,
|
|
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock) {
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypeUnixSignal);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessSignal() override = default;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2020-03-06 15:49:23 -08:00
|
|
|
void
|
|
|
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
|
|
|
OptionElementVector &opt_element_vector) override {
|
|
|
|
|
if (!m_exe_ctx.HasProcessScope() || request.GetCursorIndex() != 0)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
UnixSignalsSP signals = m_exe_ctx.GetProcessPtr()->GetUnixSignals();
|
|
|
|
|
int signo = signals->GetFirstSignalNumber();
|
|
|
|
|
while (signo != LLDB_INVALID_SIGNAL_NUMBER) {
|
2023-08-17 10:57:05 -07:00
|
|
|
request.TryCompleteCurrentArg(signals->GetSignalAsStringRef(signo));
|
2020-03-06 15:49:23 -08:00
|
|
|
signo = signals->GetNextSignalNumber(signo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
if (command.GetArgumentCount() == 1) {
|
2010-10-09 01:40:57 +00:00
|
|
|
int signo = LLDB_INVALID_SIGNAL_NUMBER;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-09 01:40:57 +00:00
|
|
|
const char *signal_name = command.GetArgumentAtIndex(0);
|
2020-07-01 17:00:12 +02:00
|
|
|
if (::isxdigit(signal_name[0])) {
|
|
|
|
|
if (!llvm::to_integer(signal_name, signo))
|
|
|
|
|
signo = LLDB_INVALID_SIGNAL_NUMBER;
|
|
|
|
|
} else
|
2015-07-14 01:09:28 +00:00
|
|
|
signo = process->GetUnixSignals()->GetSignalNumberFromName(signal_name);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-09 01:40:57 +00:00
|
|
|
if (signo == LLDB_INVALID_SIGNAL_NUMBER) {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.AppendErrorWithFormat("Invalid signal argument '%s'.\n",
|
|
|
|
|
command.GetArgumentAtIndex(0));
|
|
|
|
|
} else {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error(process->Signal(signo));
|
2010-06-08 16:52:24 +00:00
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("Failed to send signal %i: %s\n", signo,
|
|
|
|
|
error.AsCString());
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-09-20 21:44:10 +00:00
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"'%s' takes exactly one signal number argument:\nUsage: %s\n",
|
2010-06-08 16:52:24 +00:00
|
|
|
m_cmd_name.c_str(), m_cmd_syntax.c_str());
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CommandObjectProcessInterrupt
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessInterrupt
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessInterrupt : public CommandObjectParsed {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessInterrupt(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process interrupt",
|
|
|
|
|
"Interrupt the current target process.",
|
|
|
|
|
"process interrupt",
|
|
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
|
|
|
|
eCommandProcessMustBeLaunched) {}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessInterrupt() override = default;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2016-02-23 01:43:44 +00:00
|
|
|
if (process == nullptr) {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.AppendError("no process to halt");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2022-06-23 09:33:40 -07:00
|
|
|
bool clear_thread_plans = true;
|
|
|
|
|
Status error(process->Halt(clear_thread_plans));
|
|
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2010-06-08 16:52:24 +00:00
|
|
|
} else {
|
2022-06-23 09:33:40 -07:00
|
|
|
result.AppendErrorWithFormat("Failed to halt process: %s\n",
|
|
|
|
|
error.AsCString());
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CommandObjectProcessKill
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessKill
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessKill : public CommandObjectParsed {
|
2010-06-08 16:52:24 +00:00
|
|
|
public:
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessKill(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process kill",
|
|
|
|
|
"Terminate the current target process.",
|
|
|
|
|
"process kill",
|
|
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
|
|
|
|
eCommandProcessMustBeLaunched) {}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessKill() override = default;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
2016-02-23 01:43:44 +00:00
|
|
|
if (process == nullptr) {
|
2010-06-08 16:52:24 +00:00
|
|
|
result.AppendError("no process to kill");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2022-06-23 09:33:40 -07:00
|
|
|
Status error(process->Destroy(true));
|
|
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2010-06-08 16:52:24 +00:00
|
|
|
} else {
|
2022-06-23 09:33:40 -07:00
|
|
|
result.AppendErrorWithFormat("Failed to kill process: %s\n",
|
|
|
|
|
error.AsCString());
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
};
|
|
|
|
|
|
2021-06-20 12:19:50 -07:00
|
|
|
#define LLDB_OPTIONS_process_save_core
|
|
|
|
|
#include "CommandOptions.inc"
|
|
|
|
|
|
2014-06-13 00:54:12 +00:00
|
|
|
class CommandObjectProcessSaveCore : public CommandObjectParsed {
|
|
|
|
|
public:
|
|
|
|
|
CommandObjectProcessSaveCore(CommandInterpreter &interpreter)
|
2021-09-01 15:13:56 +02:00
|
|
|
: CommandObjectParsed(
|
|
|
|
|
interpreter, "process save-core",
|
|
|
|
|
"Save the current process as a core file using an "
|
|
|
|
|
"appropriate file type.",
|
|
|
|
|
"process save-core [-s corefile-style -p plugin-name] FILE",
|
|
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
2022-06-23 09:33:40 -07:00
|
|
|
eCommandProcessMustBeLaunched) {
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypePath);
|
2022-06-23 09:33:40 -07:00
|
|
|
}
|
2016-02-23 01:43:44 +00:00
|
|
|
|
|
|
|
|
~CommandObjectProcessSaveCore() override = default;
|
|
|
|
|
|
2021-06-20 12:19:50 -07:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
|
|
|
|
|
|
|
|
|
class CommandOptions : public Options {
|
|
|
|
|
public:
|
2022-03-31 13:20:46 -07:00
|
|
|
CommandOptions() = default;
|
2021-06-20 12:19:50 -07:00
|
|
|
|
|
|
|
|
~CommandOptions() override = default;
|
|
|
|
|
|
|
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_save_core_options);
|
2021-06-20 12:19:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
|
|
|
|
Status error;
|
|
|
|
|
|
|
|
|
|
switch (short_option) {
|
2021-09-01 15:13:56 +02:00
|
|
|
case 'p':
|
2024-07-18 17:10:15 -07:00
|
|
|
error = m_core_dump_options.SetPluginName(option_arg.data());
|
2021-09-01 15:13:56 +02:00
|
|
|
break;
|
2021-06-20 12:19:50 -07:00
|
|
|
case 's':
|
2024-07-18 17:10:15 -07:00
|
|
|
m_core_dump_options.SetStyle(
|
2021-06-20 12:19:50 -07:00
|
|
|
(lldb::SaveCoreStyle)OptionArgParser::ToOptionEnum(
|
|
|
|
|
option_arg, GetDefinitions()[option_idx].enum_values,
|
2024-07-18 17:10:15 -07:00
|
|
|
eSaveCoreUnspecified, error));
|
2021-06-20 12:19:50 -07:00
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unimplemented option");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
2024-07-18 17:10:15 -07:00
|
|
|
m_core_dump_options.Clear();
|
2021-06-20 12:19:50 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Instance variables to hold the values for command options.
|
2024-07-18 17:10:15 -07:00
|
|
|
SaveCoreOptions m_core_dump_options;
|
2021-06-20 12:19:50 -07:00
|
|
|
};
|
|
|
|
|
|
2014-06-13 00:54:12 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
2014-06-13 00:54:12 +00:00
|
|
|
ProcessSP process_sp = m_exe_ctx.GetProcessSP();
|
|
|
|
|
if (process_sp) {
|
|
|
|
|
if (command.GetArgumentCount() == 1) {
|
2018-11-01 21:05:36 +00:00
|
|
|
FileSpec output_file(command.GetArgumentAtIndex(0));
|
2023-06-13 11:21:08 -07:00
|
|
|
FileSystem::Instance().Resolve(output_file);
|
2024-07-18 17:10:15 -07:00
|
|
|
auto &core_dump_options = m_options.m_core_dump_options;
|
|
|
|
|
core_dump_options.SetOutputFile(output_file);
|
|
|
|
|
Status error = PluginManager::SaveCore(process_sp, core_dump_options);
|
2014-06-13 00:54:12 +00:00
|
|
|
if (error.Success()) {
|
2024-07-18 17:10:15 -07:00
|
|
|
if (core_dump_options.GetStyle() ==
|
|
|
|
|
SaveCoreStyle::eSaveCoreDirtyOnly ||
|
|
|
|
|
core_dump_options.GetStyle() ==
|
|
|
|
|
SaveCoreStyle::eSaveCoreStackOnly) {
|
2021-06-20 12:19:50 -07:00
|
|
|
result.AppendMessageWithFormat(
|
2021-08-11 13:37:31 -07:00
|
|
|
"\nModified-memory or stack-memory only corefile "
|
|
|
|
|
"created. This corefile may \n"
|
|
|
|
|
"not show library/framework/app binaries "
|
2021-06-20 12:19:50 -07:00
|
|
|
"on a different system, or when \n"
|
|
|
|
|
"those binaries have "
|
|
|
|
|
"been updated/modified. Copies are not included\n"
|
|
|
|
|
"in this corefile. Use --style full to include all "
|
|
|
|
|
"process memory.\n");
|
|
|
|
|
}
|
2014-06-13 00:54:12 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"Failed to save core file for process: %s\n", error.AsCString());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("'%s' takes one arguments:\nUsage: %s\n",
|
|
|
|
|
m_cmd_name.c_str(), m_cmd_syntax.c_str());
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendError("invalid process");
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2021-06-20 12:19:50 -07:00
|
|
|
|
|
|
|
|
CommandOptions m_options;
|
2014-06-13 00:54:12 +00:00
|
|
|
};
|
|
|
|
|
|
2010-06-18 01:23:09 +00:00
|
|
|
// CommandObjectProcessStatus
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessStatus
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
#define LLDB_OPTIONS_process_status
|
|
|
|
|
#include "CommandOptions.inc"
|
2010-12-09 18:58:16 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessStatus : public CommandObjectParsed {
|
2010-06-18 01:23:09 +00:00
|
|
|
public:
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessStatus(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(
|
|
|
|
|
interpreter, "process status",
|
|
|
|
|
"Show status and stop location for the current target process.",
|
|
|
|
|
"process status",
|
2022-01-23 11:07:14 -08:00
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock) {}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandObjectProcessStatus() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
|
|
|
|
|
|
|
|
|
class CommandOptions : public Options {
|
|
|
|
|
public:
|
2022-03-31 13:20:46 -07:00
|
|
|
CommandOptions() = default;
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
|
|
|
|
|
~CommandOptions() override = default;
|
|
|
|
|
|
|
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
|
|
|
|
|
|
|
|
|
switch (short_option) {
|
|
|
|
|
case 'v':
|
|
|
|
|
m_verbose = true;
|
|
|
|
|
break;
|
2025-05-02 12:54:03 +00:00
|
|
|
case 'd':
|
|
|
|
|
m_dump = true;
|
|
|
|
|
break;
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unimplemented option");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
|
|
|
|
m_verbose = false;
|
2025-05-02 12:54:03 +00:00
|
|
|
m_dump = false;
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_status_options);
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
|
bool m_verbose = false;
|
2025-05-02 12:54:03 +00:00
|
|
|
bool m_dump = false;
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
Centralized a lot of the status information for processes,
threads, and stack frame down in the lldb_private::Process,
lldb_private::Thread, lldb_private::StackFrameList and the
lldb_private::StackFrame classes. We had some command line
commands that had duplicate versions of the process status
output ("thread list" and "process status" for example).
Removed the "file" command and placed it where it should
have been: "target create". Made an alias for "file" to
"target create" so we stay compatible with GDB commands.
We can now have multple usable targets in lldb at the
same time. This is nice for comparing two runs of a program
or debugging more than one binary at the same time. The
new command is "target select <target-idx>" and also to see
a list of the current targets you can use the new "target list"
command. The flow in a debug session can be:
(lldb) target create /path/to/exe/a.out
(lldb) breakpoint set --name main
(lldb) run
... hit breakpoint
(lldb) target create /bin/ls
(lldb) run /tmp
Process 36001 exited with status = 0 (0x00000000)
(lldb) target list
Current targets:
target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
* target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) target select 0
Current targets:
* target #0: /tmp/args/a.out ( arch=x86_64-apple-darwin, platform=localhost, pid=35999, state=stopped )
target #1: /bin/ls ( arch=x86_64-apple-darwin, platform=localhost, pid=36001, state=exited )
(lldb) bt
* thread #1: tid = 0x2d03, 0x0000000100000b9a a.out`main + 42 at main.c:16, stop reason = breakpoint 1.1
frame #0: 0x0000000100000b9a a.out`main + 42 at main.c:16
frame #1: 0x0000000100000b64 a.out`start + 52
Above we created a target for "a.out" and ran and hit a
breakpoint at "main". Then we created a new target for /bin/ls
and ran it. Then we listed the targest and selected our original
"a.out" program, so we showed two concurent debug sessions
going on at the same time.
llvm-svn: 129695
2011-04-18 08:33:37 +00:00
|
|
|
Stream &strm = result.GetOutputStream();
|
2010-06-18 01:23:09 +00:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
|
2015-05-27 05:04:35 +00:00
|
|
|
// No need to check "process" for validity as eCommandRequiresProcess
|
|
|
|
|
// ensures it is valid
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
Process *process = m_exe_ctx.GetProcessPtr();
|
|
|
|
|
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;
|
2019-10-30 15:26:19 -07:00
|
|
|
const bool stop_format = true;
|
Expanded the flags that can be set for a command object in lldb_private::CommandObject. This list of available flags are:
enum
{
//----------------------------------------------------------------------
// eFlagRequiresTarget
//
// Ensures a valid target is contained in m_exe_ctx prior to executing
// the command. If a target doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidTargetDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidTargetDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresTarget = (1u << 0),
//----------------------------------------------------------------------
// eFlagRequiresProcess
//
// Ensures a valid process is contained in m_exe_ctx prior to executing
// the command. If a process doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidProcessDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidProcessDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresProcess = (1u << 1),
//----------------------------------------------------------------------
// eFlagRequiresThread
//
// Ensures a valid thread is contained in m_exe_ctx prior to executing
// the command. If a thread doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidThreadDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidThreadDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresThread = (1u << 2),
//----------------------------------------------------------------------
// eFlagRequiresFrame
//
// Ensures a valid frame is contained in m_exe_ctx prior to executing
// the command. If a frame doesn't exist or is invalid, the command
// will fail and CommandObject::GetInvalidFrameDescription() will be
// returned as the error. CommandObject subclasses can override the
// virtual function for GetInvalidFrameDescription() to provide custom
// strings when needed.
//----------------------------------------------------------------------
eFlagRequiresFrame = (1u << 3),
//----------------------------------------------------------------------
// eFlagRequiresRegContext
//
// Ensures a valid register context (from the selected frame if there
// is a frame in m_exe_ctx, or from the selected thread from m_exe_ctx)
// is availble from m_exe_ctx prior to executing the command. If a
// target doesn't exist or is invalid, the command will fail and
// CommandObject::GetInvalidRegContextDescription() will be returned as
// the error. CommandObject subclasses can override the virtual function
// for GetInvalidRegContextDescription() to provide custom strings when
// needed.
//----------------------------------------------------------------------
eFlagRequiresRegContext = (1u << 4),
//----------------------------------------------------------------------
// eFlagTryTargetAPILock
//
// Attempts to acquire the target lock if a target is selected in the
// command interpreter. If the command object fails to acquire the API
// lock, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagTryTargetAPILock = (1u << 5),
//----------------------------------------------------------------------
// eFlagProcessMustBeLaunched
//
// Verifies that there is a launched process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBeLaunched = (1u << 6),
//----------------------------------------------------------------------
// eFlagProcessMustBePaused
//
// Verifies that there is a paused process in m_exe_ctx, if there
// isn't, the command will fail with an appropriate error message.
//----------------------------------------------------------------------
eFlagProcessMustBePaused = (1u << 7)
};
Now each command object contains a "ExecutionContext m_exe_ctx;" member variable that gets initialized prior to running the command. The validity of the target objects in m_exe_ctx are checked to ensure that any target/process/thread/frame/reg context that are required are valid prior to executing the command. Each command object also contains a Mutex::Locker m_api_locker which gets used if eFlagTryTargetAPILock is set. This centralizes a lot of checking code that was previously and inconsistently implemented across many commands.
llvm-svn: 171990
2013-01-09 19:44:40 +00:00
|
|
|
process->GetStatus(strm);
|
|
|
|
|
process->GetThreadStatus(strm, only_threads_with_stop_reason, start_frame,
|
2016-11-08 20:36:40 +00:00
|
|
|
num_frames, num_frames_with_source, stop_format);
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
|
|
|
|
|
if (m_options.m_verbose) {
|
2021-07-22 01:02:54 -07:00
|
|
|
addr_t code_mask = process->GetCodeAddressMask();
|
|
|
|
|
addr_t data_mask = process->GetDataAddressMask();
|
[lldb] Address mask sbprocess apis and new mask invalid const (#83663)
[lldb] Add SBProcess methods for get/set/use address masks (#83095)
I'm reviving a patch from phabracator, https://reviews.llvm.org/D155905
which was approved but I wasn't thrilled with all the API I was adding
to SBProcess for all of the address mask types / memory regions. In this
update, I added enums to control type address mask type (code, data,
any) and address space specifiers (low, high, all) with defaulted
arguments for the most common case. I originally landed this via
https://github.com/llvm/llvm-project/pull/83095 but it failed on CIs
outside of arm64 Darwin so I had to debug it on more environments
and update the patch.
This patch is also fixing a bug in the "addressable bits to address
mask" calculation I added in AddressableBits::SetProcessMasks. If lldb
were told that 64 bits are valid for addressing, this method would
overflow the calculation and set an invalid mask. Added tests to check
this specific bug while I was adding these APIs.
This patch changes the value of "no mask set" from 0 to
LLDB_INVALID_ADDRESS_MASK, which is UINT64_MAX. A mask of all 1's
means "no bits are used for addressing" which is an impossible mask,
whereas a mask of 0 means "all bits are used for addressing" which
is possible.
I added a base class implementation of ABI::FixCodeAddress and
ABI::FixDataAddress that will apply the Process mask values if they
are set to a value other than LLDB_INVALID_ADDRESS_MASK.
I updated all the callers/users of the Mask methods which were
handling a value of 0 to mean invalid mask to use
LLDB_INVALID_ADDRESS_MASK.
I added code to the all AArch64 ABI Fix* methods to apply the
Highmem masks if they have been set. These will not be set on a
Linux environment, but in TestAddressMasks.py I test the highmem
masks feature for any AArch64 target, so all AArch64 ABI plugins
must handle it.
rdar://123530562
2024-03-06 10:06:56 -08:00
|
|
|
if (code_mask != LLDB_INVALID_ADDRESS_MASK) {
|
2021-07-22 01:02:54 -07:00
|
|
|
int bits = std::bitset<64>(~code_mask).count();
|
|
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Addressable code address mask: 0x%" PRIx64 "\n", code_mask);
|
|
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Addressable data address mask: 0x%" PRIx64 "\n", data_mask);
|
|
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Number of bits used in addressing (code): %d\n", bits);
|
|
|
|
|
}
|
|
|
|
|
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
PlatformSP platform_sp = process->GetTarget().GetPlatform();
|
|
|
|
|
if (!platform_sp) {
|
2024-09-24 19:48:27 -04:00
|
|
|
result.AppendError("Couldn't retrieve the target's platform");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
auto expected_crash_info =
|
2020-02-24 10:04:16 -05:00
|
|
|
platform_sp->FetchExtendedCrashInformation(*process);
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
|
|
|
|
|
if (!expected_crash_info) {
|
|
|
|
|
result.AppendError(llvm::toString(expected_crash_info.takeError()));
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::DictionarySP crash_info_sp = *expected_crash_info;
|
|
|
|
|
|
|
|
|
|
if (crash_info_sp) {
|
2022-11-03 11:25:40 -07:00
|
|
|
strm.EOL();
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
strm.PutCString("Extended Crash Information:\n");
|
2022-11-03 11:25:40 -07:00
|
|
|
crash_info_sp->GetDescription(strm);
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
}
|
|
|
|
|
}
|
2025-05-02 12:54:03 +00:00
|
|
|
|
|
|
|
|
if (m_options.m_dump) {
|
|
|
|
|
StateType state = process->GetState();
|
|
|
|
|
if (state == eStateStopped) {
|
|
|
|
|
ProcessModID process_mod_id = process->GetModID();
|
|
|
|
|
process_mod_id.Dump(result.GetOutputStream());
|
|
|
|
|
}
|
|
|
|
|
}
|
2010-06-18 01:23:09 +00:00
|
|
|
}
|
[lldb/Plugins] Add ability to fetch crash information on crashed processes
Currently, in macOS, when a process crashes, lldb halts inside the
implementation disassembly without yielding any useful information.
The only way to get more information is to detach from the process, then wait
for ReportCrash to generate a report, find the report, then see what error
message was included in it. Instead of waiting for this to happen, lldb could
locate the error_string and make it available to the user.
This patch addresses this issue by enabling the user to fetch extended
crash information for crashed processes using `process status --verbose`.
Depending on the platform, this will try to gather different crash information
into an structured data dictionnary. This dictionnary is generic and extensible,
as it contains an array for each different type of crash information.
On Darwin Platforms, lldb will iterate over each of the target's images,
extract their `__crash_info` section and generated a StructuredData::Array
containing, in each entry, the module spec, its UUID, the crash messages
and the abort cause. The array will be inserted into the platform's
`m_extended_crash_info` dictionnary and `FetchExtendedCrashInformation` will
return its JSON representation like this:
```
{
"crash-info annotations": [
{
"abort-cause": 0,
"image": "/usr/lib/system/libsystem_malloc.dylib",
"message": "main(76483,0x1000cedc0) malloc: *** error for object 0x1003040a0: pointer being freed was not allocated",
"message2": "",
"uuid": "5747D0C9-900D-3306-8D70-1E2EA4B7E821"
},
...
],
...
}
```
This crash information can also be fetched using the SB API or lldb-rpc protocol
using SBTarget::GetExtendedCrashInformation().
rdar://37736535
Differential Revision: https://reviews.llvm.org/D74657
Signed-off-by: Med Ismail Bennani <medismail.bennani@gmail.com>
2020-02-21 22:43:25 +01:00
|
|
|
|
|
|
|
|
private:
|
|
|
|
|
CommandOptions m_options;
|
2010-06-18 01:23:09 +00:00
|
|
|
};
|
|
|
|
|
|
2010-10-13 20:44:39 +00:00
|
|
|
// CommandObjectProcessHandle
|
2019-07-23 12:54:33 +00:00
|
|
|
#define LLDB_OPTIONS_process_handle
|
|
|
|
|
#include "CommandOptions.inc"
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
|
2010-12-09 18:58:16 +00:00
|
|
|
#pragma mark CommandObjectProcessHandle
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
class CommandObjectProcessHandle : public CommandObjectParsed {
|
2010-10-13 20:44:39 +00:00
|
|
|
public:
|
|
|
|
|
class CommandOptions : public Options {
|
|
|
|
|
public:
|
2022-01-23 11:07:14 -08:00
|
|
|
CommandOptions() { OptionParsingStarting(nullptr); }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
~CommandOptions() override = default;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2017-05-12 04:51:55 +00:00
|
|
|
Status SetOptionValue(uint32_t option_idx, llvm::StringRef option_arg,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
Status error;
|
2012-12-04 00:32:51 +00:00
|
|
|
const int short_option = m_getopt_table[option_idx].val;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-13 20:44:39 +00:00
|
|
|
switch (short_option) {
|
2022-05-18 14:39:03 -07:00
|
|
|
case 'c':
|
|
|
|
|
do_clear = true;
|
|
|
|
|
break;
|
|
|
|
|
case 'd':
|
|
|
|
|
dummy = true;
|
|
|
|
|
break;
|
2010-10-13 20:44:39 +00:00
|
|
|
case 's':
|
2020-01-28 20:23:46 +01:00
|
|
|
stop = std::string(option_arg);
|
2010-10-13 20:44:39 +00:00
|
|
|
break;
|
|
|
|
|
case 'n':
|
2020-01-28 20:23:46 +01:00
|
|
|
notify = std::string(option_arg);
|
2010-10-13 20:44:39 +00:00
|
|
|
break;
|
|
|
|
|
case 'p':
|
2020-01-28 20:23:46 +01:00
|
|
|
pass = std::string(option_arg);
|
2010-10-13 20:44:39 +00:00
|
|
|
break;
|
2022-05-18 14:39:03 -07:00
|
|
|
case 't':
|
|
|
|
|
only_target_values = true;
|
|
|
|
|
break;
|
2010-10-13 20:44:39 +00:00
|
|
|
default:
|
2019-08-22 08:08:05 +00:00
|
|
|
llvm_unreachable("Unimplemented option");
|
2010-10-13 20:44:39 +00:00
|
|
|
}
|
|
|
|
|
return error;
|
|
|
|
|
}
|
|
|
|
|
|
2016-08-11 23:51:28 +00:00
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
2010-10-13 20:44:39 +00:00
|
|
|
stop.clear();
|
|
|
|
|
notify.clear();
|
|
|
|
|
pass.clear();
|
2022-05-18 14:39:03 -07:00
|
|
|
only_target_values = false;
|
|
|
|
|
do_clear = false;
|
|
|
|
|
dummy = false;
|
2010-10-13 20:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
2023-01-09 18:11:07 +01:00
|
|
|
return llvm::ArrayRef(g_process_handle_options);
|
Convert option tables to ArrayRefs.
This change is very mechanical. All it does is change the
signature of `Options::GetDefinitions()` and `OptionGroup::
GetDefinitions()` to return an `ArrayRef<OptionDefinition>`
instead of a `const OptionDefinition *`. In the case of the
former, it deletes the sentinel entry from every table, and
in the case of the latter, it removes the `GetNumDefinitions()`
method from the interface. These are no longer necessary as
`ArrayRef` carries its own length.
In the former case, iteration was done by using a sentinel
entry, so there was no knowledge of length. Because of this
the individual option tables were allowed to be defined below
the corresponding class (after all, only a pointer was needed).
Now, however, the length must be known at compile time to
construct the `ArrayRef`, and as a result it is necessary to
move every option table before its corresponding class. This
results in this CL looking very big, but in terms of substance
there is not much here.
Differential revision: https://reviews.llvm.org/D24834
llvm-svn: 282188
2016-09-22 20:22:55 +00:00
|
|
|
}
|
2010-10-13 20:44:39 +00:00
|
|
|
|
|
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
|
|
|
|
|
|
std::string stop;
|
|
|
|
|
std::string notify;
|
|
|
|
|
std::string pass;
|
2022-05-18 14:39:03 -07:00
|
|
|
bool only_target_values = false;
|
|
|
|
|
bool do_clear = false;
|
|
|
|
|
bool dummy = false;
|
2010-10-13 20:44:39 +00:00
|
|
|
};
|
|
|
|
|
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectProcessHandle(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process handle",
|
|
|
|
|
"Manage LLDB handling of OS signals for the "
|
|
|
|
|
"current target process. Defaults to showing "
|
|
|
|
|
"current policy.",
|
2022-05-18 14:39:03 -07:00
|
|
|
nullptr) {
|
|
|
|
|
SetHelpLong("\nIf no signals are specified but one or more actions are, "
|
|
|
|
|
"and there is a live process, update them all. If no action "
|
|
|
|
|
"is specified, list the current values.\n"
|
|
|
|
|
"If you specify actions with no target (e.g. in an init file) "
|
|
|
|
|
"or in a target with no process "
|
|
|
|
|
"the values will get copied into subsequent targets, but "
|
|
|
|
|
"lldb won't be able to spell-check the options since it can't "
|
|
|
|
|
"know which signal set will later be in force."
|
|
|
|
|
"\nYou can see the signal modifications held by the target"
|
|
|
|
|
"by passing the -t option."
|
|
|
|
|
"\nYou can also clear the target modification for a signal"
|
|
|
|
|
"by passing the -c option");
|
2024-02-27 10:34:01 -08:00
|
|
|
AddSimpleArgumentList(eArgTypeUnixSignal, eArgRepeatStar);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2015-10-07 16:56:17 +00:00
|
|
|
~CommandObjectProcessHandle() override = default;
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2010-10-14 21:31:13 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2010-10-14 21:31:13 +00:00
|
|
|
void PrintSignalHeader(Stream &str) {
|
2015-07-14 01:09:28 +00:00
|
|
|
str.Printf("NAME PASS STOP NOTIFY\n");
|
2015-05-22 08:46:18 +00:00
|
|
|
str.Printf("=========== ===== ===== ======\n");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2023-08-17 10:57:05 -07:00
|
|
|
void PrintSignal(Stream &str, int32_t signo, llvm::StringRef sig_name,
|
2015-07-14 01:09:28 +00:00
|
|
|
const UnixSignalsSP &signals_sp) {
|
2010-10-14 21:31:13 +00:00
|
|
|
bool stop;
|
|
|
|
|
bool suppress;
|
|
|
|
|
bool notify;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2023-08-17 10:57:05 -07:00
|
|
|
str.Format("{0, -11} ", sig_name);
|
2015-07-14 01:09:28 +00:00
|
|
|
if (signals_sp->GetSignalInfo(signo, suppress, stop, notify)) {
|
2010-10-14 21:31:13 +00:00
|
|
|
bool pass = !suppress;
|
|
|
|
|
str.Printf("%s %s %s", (pass ? "true " : "false"),
|
|
|
|
|
(stop ? "true " : "false"), (notify ? "true " : "false"));
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-14 21:31:13 +00:00
|
|
|
str.Printf("\n");
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
void PrintSignalInformation(Stream &str, Args &signal_args,
|
|
|
|
|
int num_valid_signals,
|
|
|
|
|
const UnixSignalsSP &signals_sp) {
|
2010-10-14 21:31:13 +00:00
|
|
|
PrintSignalHeader(str);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-14 21:31:13 +00:00
|
|
|
if (num_valid_signals > 0) {
|
|
|
|
|
size_t num_args = signal_args.GetArgumentCount();
|
|
|
|
|
for (size_t i = 0; i < num_args; ++i) {
|
2015-07-14 01:09:28 +00:00
|
|
|
int32_t signo = signals_sp->GetSignalNumberFromName(
|
|
|
|
|
signal_args.GetArgumentAtIndex(i));
|
2010-10-14 21:31:13 +00:00
|
|
|
if (signo != LLDB_INVALID_SIGNAL_NUMBER)
|
2015-07-14 01:09:28 +00:00
|
|
|
PrintSignal(str, signo, signal_args.GetArgumentAtIndex(i),
|
|
|
|
|
signals_sp);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-14 21:31:13 +00:00
|
|
|
} else // Print info for ALL signals
|
|
|
|
|
{
|
2015-07-14 01:09:28 +00:00
|
|
|
int32_t signo = signals_sp->GetFirstSignalNumber();
|
2010-10-14 21:31:13 +00:00
|
|
|
while (signo != LLDB_INVALID_SIGNAL_NUMBER) {
|
2023-08-17 10:57:05 -07:00
|
|
|
PrintSignal(str, signo, signals_sp->GetSignalAsStringRef(signo),
|
2015-07-14 01:09:28 +00:00
|
|
|
signals_sp);
|
|
|
|
|
signo = signals_sp->GetNextSignalNumber(signo);
|
2010-10-14 21:31:13 +00:00
|
|
|
}
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-14 21:31:13 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &signal_args, CommandReturnObject &result) override {
|
[lldb] Unify the way we get the Target in CommandObject (#101208)
Currently, CommandObjects are obtaining a target in a variety of ways.
Often the command incorrectly operates on the selected target. As an
example, when a breakpoint command is running, the current target is
passed into the command but the target that hit the breakpoint is not
the selected target. In other places we use the CommandObject's
execution context, which is frozen during the execution of the command,
and comes with its own limitations. Finally, we often want to fall back
to the dummy target if no real target is available.
Instead of having to guess how to get the target, this patch introduces
one helper function in CommandObject to get the most relevant target. In
order of priority, that's the target from the command object's execution
context, from the interpreter's execution context, the selected target
or the dummy target.
rdar://110846511
2024-07-31 09:57:10 -07:00
|
|
|
Target &target = GetTarget();
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2022-07-06 16:05:25 -07:00
|
|
|
// Any signals that are being set should be added to the Target's
|
2022-05-18 14:39:03 -07:00
|
|
|
// DummySignals so they will get applied on rerun, etc.
|
|
|
|
|
// If we have a process, however, we can do a more accurate job of vetting
|
|
|
|
|
// the user's options.
|
|
|
|
|
ProcessSP process_sp = target.GetProcessSP();
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2024-02-14 10:20:58 -08:00
|
|
|
std::optional<bool> stop_action = {};
|
|
|
|
|
std::optional<bool> pass_action = {};
|
|
|
|
|
std::optional<bool> notify_action = {};
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2024-02-14 10:20:58 -08:00
|
|
|
if (!m_options.stop.empty()) {
|
|
|
|
|
bool success = false;
|
|
|
|
|
bool value = OptionArgParser::ToBoolean(m_options.stop, false, &success);
|
|
|
|
|
if (!success) {
|
|
|
|
|
result.AppendError(
|
|
|
|
|
"Invalid argument for command option --stop; must be "
|
|
|
|
|
"true or false.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
stop_action = value;
|
2010-10-13 20:44:39 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-14 10:20:58 -08:00
|
|
|
if (!m_options.pass.empty()) {
|
|
|
|
|
bool success = false;
|
|
|
|
|
bool value = OptionArgParser::ToBoolean(m_options.pass, false, &success);
|
|
|
|
|
if (!success) {
|
|
|
|
|
result.AppendError(
|
|
|
|
|
"Invalid argument for command option --pass; must be "
|
|
|
|
|
"true or false.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
pass_action = value;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2024-02-14 10:20:58 -08:00
|
|
|
if (!m_options.notify.empty()) {
|
|
|
|
|
bool success = false;
|
|
|
|
|
bool value =
|
|
|
|
|
OptionArgParser::ToBoolean(m_options.notify, false, &success);
|
|
|
|
|
if (!success) {
|
|
|
|
|
result.AppendError("Invalid argument for command option --notify; must "
|
|
|
|
|
"be true or false.\n");
|
|
|
|
|
return;
|
|
|
|
|
}
|
|
|
|
|
notify_action = value;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!m_options.notify.empty() && !notify_action.has_value()) {
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2022-07-06 16:05:25 -07:00
|
|
|
|
2024-02-14 10:20:58 -08:00
|
|
|
bool no_actions = (!stop_action.has_value() && !pass_action.has_value() &&
|
|
|
|
|
!notify_action.has_value());
|
2022-05-18 14:39:03 -07:00
|
|
|
if (m_options.only_target_values && !no_actions) {
|
|
|
|
|
result.AppendError("-t is for reporting, not setting, target values.");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-05-18 14:39:03 -07:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
size_t num_args = signal_args.GetArgumentCount();
|
2022-05-18 14:39:03 -07:00
|
|
|
UnixSignalsSP signals_sp;
|
|
|
|
|
if (process_sp)
|
|
|
|
|
signals_sp = process_sp->GetUnixSignals();
|
|
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
int num_signals_set = 0;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2022-05-18 14:39:03 -07:00
|
|
|
// If we were just asked to print the target values, do that here and
|
|
|
|
|
// return:
|
|
|
|
|
if (m_options.only_target_values) {
|
|
|
|
|
target.PrintDummySignals(result.GetOutputStream(), signal_args);
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-05-18 14:39:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This handles clearing values:
|
|
|
|
|
if (m_options.do_clear) {
|
|
|
|
|
target.ClearDummySignals(signal_args);
|
|
|
|
|
if (m_options.dummy)
|
|
|
|
|
GetDummyTarget().ClearDummySignals(signal_args);
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-05-18 14:39:03 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// This rest handles setting values:
|
2010-10-14 21:31:13 +00:00
|
|
|
if (num_args > 0) {
|
2016-11-22 17:10:15 +00:00
|
|
|
for (const auto &arg : signal_args) {
|
2022-05-18 14:39:03 -07:00
|
|
|
// Do the process first. If we have a process we can catch
|
|
|
|
|
// invalid signal names, which we do here.
|
|
|
|
|
if (signals_sp) {
|
|
|
|
|
int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str());
|
|
|
|
|
if (signo != LLDB_INVALID_SIGNAL_NUMBER) {
|
2024-02-14 10:20:58 -08:00
|
|
|
if (stop_action.has_value())
|
|
|
|
|
signals_sp->SetShouldStop(signo, *stop_action);
|
|
|
|
|
if (pass_action.has_value()) {
|
|
|
|
|
bool suppress = !*pass_action;
|
2022-05-18 14:39:03 -07:00
|
|
|
signals_sp->SetShouldSuppress(signo, suppress);
|
|
|
|
|
}
|
2024-02-14 10:20:58 -08:00
|
|
|
if (notify_action.has_value())
|
|
|
|
|
signals_sp->SetShouldNotify(signo, *notify_action);
|
2022-05-18 14:39:03 -07:00
|
|
|
++num_signals_set;
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("Invalid signal name '%s'\n",
|
|
|
|
|
arg.c_str());
|
|
|
|
|
continue;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
} else {
|
2022-05-18 14:39:03 -07:00
|
|
|
// If there's no process we can't check, so we just set them all.
|
|
|
|
|
// But since the map signal name -> signal number across all platforms
|
|
|
|
|
// is not 1-1, we can't sensibly set signal actions by number before
|
|
|
|
|
// we have a process. Check that here:
|
|
|
|
|
int32_t signo;
|
|
|
|
|
if (llvm::to_integer(arg.c_str(), signo)) {
|
|
|
|
|
result.AppendErrorWithFormat("Can't set signal handling by signal "
|
|
|
|
|
"number with no process");
|
2023-10-30 10:21:00 -10:00
|
|
|
return;
|
2022-05-18 14:39:03 -07:00
|
|
|
}
|
|
|
|
|
num_signals_set = num_args;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2024-02-14 10:20:58 -08:00
|
|
|
auto set_lazy_bool = [](std::optional<bool> action) -> LazyBool {
|
|
|
|
|
if (!action.has_value())
|
|
|
|
|
return eLazyBoolCalculate;
|
|
|
|
|
return (*action) ? eLazyBoolYes : eLazyBoolNo;
|
2022-05-18 14:39:03 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// If there were no actions, we're just listing, don't add the dummy:
|
|
|
|
|
if (!no_actions)
|
2024-02-14 10:20:58 -08:00
|
|
|
target.AddDummySignal(arg.ref(), set_lazy_bool(pass_action),
|
2022-05-18 14:39:03 -07:00
|
|
|
set_lazy_bool(notify_action),
|
|
|
|
|
set_lazy_bool(stop_action));
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-14 21:31:13 +00:00
|
|
|
} else {
|
|
|
|
|
// No signal specified, if any command options were specified, update ALL
|
2022-05-18 14:39:03 -07:00
|
|
|
// signals. But we can't do this without a process since we don't know
|
|
|
|
|
// all the possible signals that might be valid for this target.
|
2024-02-14 10:20:58 -08:00
|
|
|
if ((notify_action.has_value() || stop_action.has_value() ||
|
|
|
|
|
pass_action.has_value()) &&
|
|
|
|
|
process_sp) {
|
2010-10-14 21:31:13 +00:00
|
|
|
if (m_interpreter.Confirm(
|
|
|
|
|
"Do you really want to update all the signals?", false)) {
|
2015-07-14 01:09:28 +00:00
|
|
|
int32_t signo = signals_sp->GetFirstSignalNumber();
|
2010-10-14 21:31:13 +00:00
|
|
|
while (signo != LLDB_INVALID_SIGNAL_NUMBER) {
|
2024-02-14 10:20:58 -08:00
|
|
|
if (notify_action.has_value())
|
|
|
|
|
signals_sp->SetShouldNotify(signo, *notify_action);
|
|
|
|
|
if (stop_action.has_value())
|
|
|
|
|
signals_sp->SetShouldStop(signo, *stop_action);
|
|
|
|
|
if (pass_action.has_value()) {
|
|
|
|
|
bool suppress = !*pass_action;
|
2015-07-14 01:09:28 +00:00
|
|
|
signals_sp->SetShouldSuppress(signo, suppress);
|
2010-10-13 20:44:39 +00:00
|
|
|
}
|
2015-07-14 01:09:28 +00:00
|
|
|
signo = signals_sp->GetNextSignalNumber(signo);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-13 20:44:39 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
}
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2022-05-18 14:39:03 -07:00
|
|
|
if (signals_sp)
|
|
|
|
|
PrintSignalInformation(result.GetOutputStream(), signal_args,
|
|
|
|
|
num_signals_set, signals_sp);
|
|
|
|
|
else
|
2022-07-06 16:05:25 -07:00
|
|
|
target.PrintDummySignals(result.GetOutputStream(),
|
2022-05-18 14:39:03 -07:00
|
|
|
signal_args);
|
2010-10-14 21:31:13 +00:00
|
|
|
|
2010-10-13 20:44:39 +00:00
|
|
|
if (num_signals_set > 0)
|
2022-05-18 14:39:03 -07:00
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
2010-10-13 20:44:39 +00:00
|
|
|
else
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CommandOptions m_options;
|
|
|
|
|
};
|
|
|
|
|
|
2020-11-09 13:36:26 -08:00
|
|
|
// Next are the subcommands of CommandObjectMultiwordProcessTrace
|
|
|
|
|
|
|
|
|
|
// CommandObjectProcessTraceStart
|
|
|
|
|
class CommandObjectProcessTraceStart : public CommandObjectTraceProxy {
|
|
|
|
|
public:
|
|
|
|
|
CommandObjectProcessTraceStart(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectTraceProxy(
|
|
|
|
|
/*live_debug_session_only*/ true, interpreter,
|
|
|
|
|
"process trace start",
|
|
|
|
|
"Start tracing this process with the corresponding trace "
|
|
|
|
|
"plug-in.",
|
|
|
|
|
"process trace start [<trace-options>]") {}
|
|
|
|
|
|
|
|
|
|
protected:
|
|
|
|
|
lldb::CommandObjectSP GetDelegateCommand(Trace &trace) override {
|
|
|
|
|
return trace.GetProcessTraceStartCommand(m_interpreter);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CommandObjectProcessTraceStop
|
|
|
|
|
class CommandObjectProcessTraceStop : public CommandObjectParsed {
|
|
|
|
|
public:
|
|
|
|
|
CommandObjectProcessTraceStop(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process trace stop",
|
|
|
|
|
"Stop tracing this process. This does not affect "
|
|
|
|
|
"traces started with the "
|
|
|
|
|
"\"thread trace start\" command.",
|
|
|
|
|
"process trace stop",
|
|
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
|
|
|
|
eCommandProcessMustBeLaunched |
|
|
|
|
|
eCommandProcessMustBePaused |
|
|
|
|
|
eCommandProcessMustBeTraced) {}
|
|
|
|
|
|
|
|
|
|
~CommandObjectProcessTraceStop() override = default;
|
|
|
|
|
|
2023-10-30 10:21:00 -10:00
|
|
|
void DoExecute(Args &command, CommandReturnObject &result) override {
|
2020-11-09 13:36:26 -08:00
|
|
|
ProcessSP process_sp = m_exe_ctx.GetProcessSP();
|
|
|
|
|
|
|
|
|
|
TraceSP trace_sp = process_sp->GetTarget().GetTrace();
|
|
|
|
|
|
2021-06-01 15:34:06 -07:00
|
|
|
if (llvm::Error err = trace_sp->Stop())
|
2021-06-22 16:12:56 +00:00
|
|
|
result.AppendError(toString(std::move(err)));
|
2020-11-09 13:36:26 -08:00
|
|
|
else
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// CommandObjectMultiwordProcessTrace
|
|
|
|
|
class CommandObjectMultiwordProcessTrace : public CommandObjectMultiword {
|
|
|
|
|
public:
|
|
|
|
|
CommandObjectMultiwordProcessTrace(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectMultiword(
|
|
|
|
|
interpreter, "trace", "Commands for tracing the current process.",
|
|
|
|
|
"process trace <subcommand> [<subcommand objects>]") {
|
|
|
|
|
LoadSubCommand("start", CommandObjectSP(new CommandObjectProcessTraceStart(
|
|
|
|
|
interpreter)));
|
|
|
|
|
LoadSubCommand("stop", CommandObjectSP(
|
|
|
|
|
new CommandObjectProcessTraceStop(interpreter)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
~CommandObjectMultiwordProcessTrace() override = default;
|
|
|
|
|
};
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
// CommandObjectMultiwordProcess
|
|
|
|
|
|
2016-07-14 22:03:10 +00:00
|
|
|
CommandObjectMultiwordProcess::CommandObjectMultiwordProcess(
|
|
|
|
|
CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectMultiword(
|
|
|
|
|
interpreter, "process",
|
|
|
|
|
"Commands for interacting with processes on the current platform.",
|
|
|
|
|
"process <subcommand> [<subcommand-options>]") {
|
2011-07-02 21:07:54 +00:00
|
|
|
LoadSubCommand("attach",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessAttach(interpreter)));
|
|
|
|
|
LoadSubCommand("launch",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessLaunch(interpreter)));
|
|
|
|
|
LoadSubCommand("continue", CommandObjectSP(new CommandObjectProcessContinue(
|
|
|
|
|
interpreter)));
|
|
|
|
|
LoadSubCommand("connect",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessConnect(interpreter)));
|
|
|
|
|
LoadSubCommand("detach",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessDetach(interpreter)));
|
|
|
|
|
LoadSubCommand("load",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessLoad(interpreter)));
|
|
|
|
|
LoadSubCommand("unload",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessUnload(interpreter)));
|
|
|
|
|
LoadSubCommand("signal",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessSignal(interpreter)));
|
|
|
|
|
LoadSubCommand("handle",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessHandle(interpreter)));
|
|
|
|
|
LoadSubCommand("status",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessStatus(interpreter)));
|
2010-09-18 01:14:36 +00:00
|
|
|
LoadSubCommand("interrupt", CommandObjectSP(new CommandObjectProcessInterrupt(
|
|
|
|
|
interpreter)));
|
2011-07-02 21:07:54 +00:00
|
|
|
LoadSubCommand("kill",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessKill(interpreter)));
|
2012-10-13 02:07:45 +00:00
|
|
|
LoadSubCommand("plugin",
|
|
|
|
|
CommandObjectSP(new CommandObjectProcessPlugin(interpreter)));
|
2014-06-13 00:54:12 +00:00
|
|
|
LoadSubCommand("save-core", CommandObjectSP(new CommandObjectProcessSaveCore(
|
|
|
|
|
interpreter)));
|
2020-11-09 13:36:26 -08:00
|
|
|
LoadSubCommand(
|
|
|
|
|
"trace",
|
|
|
|
|
CommandObjectSP(new CommandObjectMultiwordProcessTrace(interpreter)));
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess() = default;
|