[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"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Breakpoint/Breakpoint.h"
|
|
|
|
|
#include "lldb/Breakpoint/BreakpointLocation.h"
|
|
|
|
|
#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"
|
|
|
|
|
#include "lldb/Interpreter/CommandReturnObject.h"
|
2018-04-10 09:03:59 +00:00
|
|
|
#include "lldb/Interpreter/OptionArgParser.h"
|
2012-08-11 01:27:55 +00:00
|
|
|
#include "lldb/Interpreter/Options.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"
|
2018-08-07 11:07:21 +00:00
|
|
|
#include "lldb/Utility/State.h"
|
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) {
|
|
|
|
|
char message[1024];
|
|
|
|
|
if (process->GetState() == eStateAttaching)
|
|
|
|
|
::snprintf(message, sizeof(message),
|
|
|
|
|
"There is a pending attach, abort it and %s?",
|
|
|
|
|
m_new_process_action.c_str());
|
|
|
|
|
else if (process->GetShouldDetach())
|
|
|
|
|
::snprintf(message, sizeof(message),
|
|
|
|
|
"There is a running process, detach from it and %s?",
|
|
|
|
|
m_new_process_action.c_str());
|
|
|
|
|
else
|
|
|
|
|
::snprintf(message, sizeof(message),
|
|
|
|
|
"There is a running process, kill it and %s?",
|
|
|
|
|
m_new_process_action.c_str());
|
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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
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());
|
2013-03-29 00:56:30 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
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",
|
|
|
|
|
"Launch the executable in the debugger.", nullptr,
|
|
|
|
|
eCommandRequiresTarget, "restart"),
|
2016-08-11 23:51:28 +00:00
|
|
|
m_options() {
|
2010-10-04 22:28:36 +00:00
|
|
|
CommandArgumentEntry arg;
|
|
|
|
|
CommandArgumentData run_args_arg;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
// Define the first (and only) variant of this arg.
|
|
|
|
|
run_args_arg.arg_type = eArgTypeRunArgs;
|
|
|
|
|
run_args_arg.arg_repetition = eArgRepeatOptional;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
// There is only one variant this argument could be; put it into the
|
|
|
|
|
// argument entry.
|
|
|
|
|
arg.push_back(run_args_arg);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
|
|
|
m_arguments.push_back(arg);
|
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
|
|
|
|
[lldb][NFC] Remove WordComplete mode, make result array indexed from 0 and remove any undocumented/redundant return values
Summary:
We still have some leftovers of the old completion API in the internals of
LLDB that haven't been replaced by the new CompletionRequest. These leftovers
are:
* The return values (int/size_t) in all completion functions.
* Our result array that starts indexing at 1.
* `WordComplete` mode.
I didn't replace them back then because it's tricky to figure out what exactly they
are used for and the completion code is relatively untested. I finally got around
to writing more tests for the API and understanding the semantics, so I think it's
a good time to get rid of them.
A few words why those things should be removed/replaced:
* The return values are really cryptic, partly redundant and rarely documented.
They are also completely ignored by Xcode, so whatever information they contain will end up
breaking Xcode's completion mechanism. They are also partly impossible to even implement
as we assign negative values special meaning and our completion API sometimes returns size_t.
Completion functions are supposed to return -2 to rewrite the current line. We seem to use this
in some untested code path to expand the history repeat character to the full command, but
I haven't figured out why that doesn't work at the moment.
Completion functions return -1 to 'insert the completion character', but that isn't implemented
(even though we seem to activate this feature in LLDB sometimes).
All positive values have to match the number of results. This is obviously just redundant information
as the user can just look at the result list to get that information (which is what Xcode does).
* The result array that starts indexing at 1 is obviously unexpected. The first element of the array is
reserved for the common prefix of all completions (e.g. "foobar" and "footar" -> "foo"). The idea is
that we calculate this to make the life of the API caller easier, but obviously forcing people to have
1-based indices is not helpful (or even worse, forces them to manually copy the results to make it
0-based like Xcode has to do).
* The `WordComplete` mode indicates that LLDB should enter a space behind the completion. The
idea is that we let the top-level API know that we just provided a full completion. Interestingly we
`WordComplete` is just a single bool that somehow represents all N completions. And we always
provide full completions in LLDB, so in theory it should always be true.
The only use it currently serves is providing redundant information about whether we have a single
definitive completion or not (which we already know from the number of results we get).
This patch essentially removes `WordComplete` mode and makes the result array indexed from 0.
It also removes all return values from all internal completion functions. The only non-redundant information
they contain is about rewriting the current line (which is broken), so that functionality was moved
to the CompletionRequest API. So you can now do `addCompletion("blub", "description", CompletionMode::RewriteLine)`
to do the same.
For the SB API we emulate the old behaviour by making the array indexed from 1 again with the common
prefix at index 0. I didn't keep the special negative return codes as we either never sent them before (e.g. -2) or we
didn't even implement them in the Editline handler (e.g. -1).
I tried to keep this patch minimal and I'm aware we can probably now even further simplify a bunch of related code,
but I would prefer doing this in follow-up NFC commits
Reviewers: JDevlieghere
Reviewed By: JDevlieghere
Subscribers: arphaman, abidh, lldb-commits
Tags: #lldb
Differential Revision: https://reviews.llvm.org/D66536
llvm-svn: 369624
2019-08-22 07:41:23 +00:00
|
|
|
void
|
|
|
|
|
HandleArgumentCompletion(CompletionRequest &request,
|
|
|
|
|
OptionElementVector &opt_element_vector) override {
|
Refactoring for for the internal command line completion API (NFC)
Summary:
This patch refactors the internal completion API. It now takes (as far as possible) a single
CompletionRequest object instead o half a dozen in/out/in-out parameters. The CompletionRequest
contains a common superset of the different parameters as far as it makes sense. This includes
the raw command line string and raw cursor position, which should make the `expr` command
possible to implement (at least without hacks that reconstruct the command line from the args).
This patch is not intended to change the observable behavior of lldb in any way. It's also as
minimal as possible and doesn't attempt to fix all the problems the API has.
Some Q&A:
Q: Why is this not fixing all the problems in the completion API?
A: Because is a blocker for the expr command completion which I want to get in ASAP. This is the
smallest patch that unblocks the expr completion patch and which allows trivial refactoring in the future.
The patch also doesn't really change the internal information flow in the API, so that hopefully
saves us from ever having to revert and resubmit this humongous patch.
Q: Can we merge all the copy-pasted code in the completion methods
(like computing the current incomplete arg) into CompletionRequest class?
A: Yes, but it's out of scope for this patch.
Q: Why the `word_complete = request.GetWordComplete(); ... ` pattern?
A: I don't want to add a getter that returns a reference to the internal integer. So we have
to use a temporary variable and the Getter/Setter instead. We don't throw exceptions
from what I can tell, so the behavior doesn't change.
Q: Why are we not owning the list of matches?
A: Because that's how the previous API works. But that should be fixed too (in another patch).
Q: Can we make the constructor simpler and compute some of the values from the plain command?
A: I think this works, but I rather want to have this in a follow up commit. Especially when making nested
request it's a bit awkward that the parsed arguments behave as both input/output (as we should in theory
propagate the changes on the nested request back to the parent request if we don't want to change the
behavior too much).
Q: Can't we pass one const request object and then just return another result object instead of mixing
them together in one in/out parameter?
A: It's hard to get keep the same behavior with that pattern, but I think we can also get a nice API with just
a single request object. If we make all input parameters read-only, we have a clear separation between what
is actually an input and what an output parameter (and hopefully we get rid of the in-out parameters).
Q: Can we throw out the 'match' variables that are not implemented according to the comment?
A: We currently just forward them as in the old code to the different methods, even though I think
they are really not used. We can easily remove and readd them once every single completion method just
takes a CompletionRequest, but for now I prefer NFC behavior from the perspective of the API user.
Reviewers: davide, jingham, labath
Reviewed By: jingham
Subscribers: mgorny, friss, lldb-commits
Differential Revision: https://reviews.llvm.org/D48796
llvm-svn: 336146
2018-07-02 21:29:56 +00:00
|
|
|
|
2016-08-11 23:51:28 +00:00
|
|
|
CommandCompletions::InvokeCommonCompletionCallbacks(
|
2010-10-04 22:28:36 +00:00
|
|
|
GetCommandInterpreter(), CommandCompletions::eDiskFileCompletion,
|
2018-07-13 18:28:14 +00:00
|
|
|
request, nullptr);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
const char *GetRepeatCommand(Args ¤t_command_args,
|
2015-10-07 16:56:17 +00:00
|
|
|
uint32_t index) override {
|
2010-10-04 22:28:36 +00:00
|
|
|
// No repeat for "process launch"...
|
|
|
|
|
return "";
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
protected:
|
|
|
|
|
bool 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
|
|
|
|
2012-08-10 21:48:41 +00:00
|
|
|
if (exe_module_sp == nullptr) {
|
|
|
|
|
result.AppendError("no file in target, create a debug target using the "
|
2016-08-11 23:51:28 +00:00
|
|
|
"'target create' command");
|
2012-08-10 21:48:41 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
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))
|
2010-06-08 16:52:24 +00:00
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2016-11-17 18:08:12 +00:00
|
|
|
llvm::StringRef target_settings_argv0 = target->GetArg0();
|
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
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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
|
|
|
|
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);
|
2013-12-13 17:20:18 +00:00
|
|
|
m_options.launch_info.SetExecutableFile(
|
2012-06-08 21:56:10 +00:00
|
|
|
exe_module_sp->GetPlatformFileSpec(), false);
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2013-12-13 17:20:18 +00:00
|
|
|
m_options.launch_info.SetExecutableFile(
|
2012-06-08 21:56:10 +00:00
|
|
|
exe_module_sp->GetPlatformFileSpec(), true);
|
|
|
|
|
}
|
|
|
|
|
|
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
|
|
|
|
2016-11-16 21:15:24 +00:00
|
|
|
llvm::StringRef data = stream.GetString();
|
|
|
|
|
if (!data.empty())
|
|
|
|
|
result.AppendMessage(data);
|
2015-05-07 06:26:27 +00:00
|
|
|
const char *archname =
|
|
|
|
|
exe_module_sp->GetArchitecture().GetArchitectureName();
|
2013-12-13 17:20:18 +00:00
|
|
|
result.AppendMessageWithFormat(
|
|
|
|
|
"Process %" PRIu64 " launched: '%s' (%s)\n", process_sp->GetID(),
|
|
|
|
|
exe_module_sp->GetFileSpec().GetPath().c_str(), archname);
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
result.SetDidChangeProcessState(true);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendError(
|
|
|
|
|
"no error returned from Target::Launch, and target has no process");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
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());
|
2011-02-15 21:59:32 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
return result.Succeeded();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-11-03 21:22:33 +00:00
|
|
|
ProcessLaunchCommandOptions m_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:
|
|
|
|
|
class CommandOptions : public Options {
|
2011-04-13 00:18:08 +00:00
|
|
|
public:
|
2016-08-11 23:51:28 +00:00
|
|
|
CommandOptions() : Options() {
|
2015-01-15 20:08:35 +00:00
|
|
|
// Keep default values of all options in one place: OptionParsingStarting
|
2011-11-15 03:53:30 +00:00
|
|
|
// ()
|
2011-10-26 00:56:27 +00:00
|
|
|
OptionParsingStarting(nullptr);
|
2010-06-08 16:52:24 +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;
|
2010-06-08 16:52:24 +00:00
|
|
|
switch (short_option) {
|
2012-05-24 00:43:00 +00:00
|
|
|
case 'c':
|
2016-08-11 23:51:28 +00:00
|
|
|
attach_info.SetContinueOnceAttached(true);
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
case 'p': {
|
2016-11-12 16:56:47 +00:00
|
|
|
lldb::pid_t pid;
|
|
|
|
|
if (option_arg.getAsInteger(0, pid)) {
|
|
|
|
|
error.SetErrorStringWithFormat("invalid process ID '%s'",
|
|
|
|
|
option_arg.str().c_str());
|
2010-06-08 16:52:24 +00:00
|
|
|
} else {
|
2011-11-15 03:53:30 +00:00
|
|
|
attach_info.SetProcessID(pid);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2011-11-15 03:53:30 +00:00
|
|
|
} break;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
case 'P':
|
2011-11-15 03:53:30 +00:00
|
|
|
attach_info.SetProcessPluginName(option_arg);
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
case 'n':
|
2018-11-01 21:05:36 +00:00
|
|
|
attach_info.GetExecutableFile().SetFile(option_arg,
|
2018-06-13 22:08:14 +00:00
|
|
|
FileSpec::Style::native);
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
case 'w':
|
2011-11-15 03:53:30 +00:00
|
|
|
attach_info.SetWaitForLaunch(true);
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
2012-07-20 21:37:13 +00:00
|
|
|
case 'i':
|
|
|
|
|
attach_info.SetIgnoreExisting(false);
|
2016-09-06 20:57:50 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
default:
|
2019-08-22 08:08:05 +00:00
|
|
|
llvm_unreachable("Unimplemented option");
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
return error;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-03-24 21:19:54 +00:00
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
2010-06-08 16:52:24 +00:00
|
|
|
attach_info.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 {
|
2016-09-22 21:06:13 +00:00
|
|
|
return llvm::makeArrayRef(g_process_attach_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
|
|
|
|
2019-08-22 09:14:42 +00:00
|
|
|
void HandleOptionArgumentCompletion(
|
2018-07-13 18:28:14 +00:00
|
|
|
CompletionRequest &request, OptionElementVector &opt_element_vector,
|
|
|
|
|
int opt_element_index, CommandInterpreter &interpreter) override {
|
2010-08-09 23:31:02 +00:00
|
|
|
int opt_arg_pos = opt_element_vector[opt_element_index].opt_arg_pos;
|
|
|
|
|
int opt_defs_index = opt_element_vector[opt_element_index].opt_defs_index;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2020-05-27 14:06:28 +02:00
|
|
|
switch (GetDefinitions()[opt_defs_index].short_option) {
|
|
|
|
|
case 'n': {
|
|
|
|
|
// Look to see if there is a -P argument provided, and if so use that
|
|
|
|
|
// plugin, otherwise use the default plugin.
|
|
|
|
|
|
|
|
|
|
const char *partial_name = nullptr;
|
|
|
|
|
partial_name = request.GetParsedLine().GetArgumentAtIndex(opt_arg_pos);
|
|
|
|
|
|
|
|
|
|
PlatformSP platform_sp(interpreter.GetPlatform(true));
|
|
|
|
|
if (!platform_sp)
|
|
|
|
|
return;
|
|
|
|
|
ProcessInstanceInfoList process_infos;
|
|
|
|
|
ProcessInstanceInfoMatch match_info;
|
|
|
|
|
if (partial_name) {
|
|
|
|
|
match_info.GetProcessInfo().GetExecutableFile().SetFile(
|
|
|
|
|
partial_name, FileSpec::Style::native);
|
|
|
|
|
match_info.SetNameMatchType(NameMatch::StartsWith);
|
|
|
|
|
}
|
|
|
|
|
platform_sp->FindProcesses(match_info, process_infos);
|
|
|
|
|
const size_t num_matches = process_infos.size();
|
|
|
|
|
if (num_matches == 0)
|
|
|
|
|
return;
|
|
|
|
|
for (size_t i = 0; i < num_matches; ++i) {
|
|
|
|
|
request.AddCompletion(process_infos[i].GetNameAsStringRef());
|
|
|
|
|
}
|
|
|
|
|
} break;
|
|
|
|
|
|
|
|
|
|
case 'P':
|
|
|
|
|
CommandCompletions::InvokeCommonCompletionCallbacks(
|
|
|
|
|
interpreter, CommandCompletions::eProcessPluginCompletion, request,
|
|
|
|
|
nullptr);
|
|
|
|
|
break;
|
2019-08-22 13:50:54 +00:00
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2011-11-15 03:53:30 +00:00
|
|
|
// Instance variables to hold the values for command options.
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2013-03-29 00:56:30 +00:00
|
|
|
ProcessAttachInfo attach_info;
|
2010-08-09 23:31:02 +00:00
|
|
|
};
|
|
|
|
|
|
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.",
|
2013-03-29 00:56:30 +00:00
|
|
|
"process attach <cmd-options>", 0, "attach"),
|
2016-02-23 01:43:44 +00:00
|
|
|
m_options() {}
|
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
|
|
|
|
2011-02-04 01:58:07 +00:00
|
|
|
Options *GetOptions() override { return &m_options; }
|
2015-02-03 00:04:35 +00:00
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2015-02-03 00:04:35 +00:00
|
|
|
bool DoExecute(Args &command, CommandReturnObject &result) override {
|
|
|
|
|
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))
|
2016-01-08 00:20:47 +00:00
|
|
|
return false;
|
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"));
|
|
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2019-04-27 06:19:42 +00:00
|
|
|
GetDebugger().GetTargetList().SetSelectedTarget(target);
|
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();
|
|
|
|
|
|
|
|
|
|
if (command.GetArgumentCount()) {
|
|
|
|
|
result.AppendErrorWithFormat("Invalid arguments for '%s'.\nUsage: %s\n",
|
|
|
|
|
m_cmd_name.c_str(), m_cmd_syntax.c_str());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
2013-03-29 00:56:30 +00:00
|
|
|
return false;
|
2015-02-03 00:04:35 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
m_interpreter.UpdateExecutionContext(nullptr);
|
|
|
|
|
StreamString stream;
|
|
|
|
|
const auto error = target->Attach(m_options.attach_info, &stream);
|
|
|
|
|
if (error.Success()) {
|
|
|
|
|
ProcessSP 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");
|
2010-08-09 23:31:02 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!result.Succeeded())
|
|
|
|
|
return false;
|
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:
|
|
|
|
|
char new_path[PATH_MAX];
|
|
|
|
|
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) {
|
|
|
|
|
new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
|
|
|
|
|
result.AppendMessageWithFormat("Executable module set to \"%s\".\n",
|
|
|
|
|
new_path);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2015-02-03 00:04:35 +00:00
|
|
|
} else if (old_exec_module_sp->GetFileSpec() !=
|
|
|
|
|
new_exec_module_sp->GetFileSpec()) {
|
|
|
|
|
char old_path[PATH_MAX];
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-02-03 00:04:35 +00:00
|
|
|
old_exec_module_sp->GetFileSpec().GetPath(old_path, PATH_MAX);
|
|
|
|
|
new_exec_module_sp->GetFileSpec().GetPath(new_path, PATH_MAX);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2015-02-03 00:04:35 +00:00
|
|
|
result.AppendWarningWithFormat(
|
|
|
|
|
"Executable module changed from \"%s\" to \"%s\".\n", old_path,
|
|
|
|
|
new_path);
|
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.
|
2015-02-03 00:04:35 +00:00
|
|
|
if (m_options.attach_info.GetContinueOnceAttached())
|
2016-07-14 22:03:10 +00:00
|
|
|
m_interpreter.HandleCommand("process continue", eLazyBoolNo, result);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
return result.Succeeded();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
CommandOptions m_options;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
// 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 |
|
|
|
|
|
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused),
|
2016-08-11 23:51:28 +00:00
|
|
|
m_options() {}
|
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:
|
2016-02-23 01:43:44 +00:00
|
|
|
CommandOptions() : Options() {
|
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,
|
|
|
|
|
ExecutionContext *execution_context) override {
|
|
|
|
|
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))
|
2010-06-08 16:52:24 +00:00
|
|
|
error.SetErrorStringWithFormat(
|
|
|
|
|
"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;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
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;
|
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 {
|
2016-09-22 21:06:13 +00:00
|
|
|
return llvm::makeArrayRef(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
|
|
|
|
2014-08-12 14:33:19 +00:00
|
|
|
uint32_t m_ignore;
|
2016-09-06 20:57:50 +00:00
|
|
|
};
|
|
|
|
|
|
2014-08-12 14:33:19 +00:00
|
|
|
bool 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-11-29 21:49:15 +00:00
|
|
|
if (command.GetArgumentCount() != 0) {
|
|
|
|
|
result.AppendErrorWithFormat(
|
2014-10-21 01:00:42 +00:00
|
|
|
"The '%s' command does not take any arguments.\n",
|
|
|
|
|
m_cmd_name.c_str());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
2015-02-03 00:04:35 +00:00
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
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) {
|
2010-06-08 16:52:24 +00:00
|
|
|
const size_t num_owners = bp_site_sp->GetNumberOfOwners();
|
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 =
|
2010-06-08 16:52:24 +00:00
|
|
|
bp_site_sp->GetOwnerAtIndex(i)->GetBreakpoint();
|
|
|
|
|
if (!bp_ref.IsInternal()) {
|
|
|
|
|
bp_ref.SetIgnoreCount(m_options.m_ignore);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
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
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
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;
|
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();
|
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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
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));
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
return result.Succeeded();
|
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:
|
2016-08-11 23:51:28 +00:00
|
|
|
CommandOptions() : Options() { 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)
|
|
|
|
|
error.SetErrorStringWithFormat("invalid boolean option: \"%s\"",
|
2016-11-12 16:56:47 +00:00
|
|
|
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 {
|
2016-09-22 21:06:13 +00:00
|
|
|
return llvm::makeArrayRef(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 |
|
|
|
|
|
eCommandProcessMustBeLaunched),
|
2016-08-11 23:51:28 +00:00
|
|
|
m_options() {}
|
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:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
return result.Succeeded();
|
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:
|
2011-10-26 00:56:27 +00:00
|
|
|
CommandOptions() : Options() {
|
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 {
|
2016-09-22 21:06:13 +00:00
|
|
|
return llvm::makeArrayRef(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.",
|
|
|
|
|
"process connect <remote-url>", 0),
|
2016-08-11 23:51:28 +00:00
|
|
|
m_options() {}
|
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:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
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);
|
|
|
|
|
ProcessSP process_sp = platform_sp->ConnectProcess(
|
|
|
|
|
command.GetArgumentAtIndex(0), plugin_name, debugger,
|
|
|
|
|
debugger.GetSelectedTarget().get(), error);
|
|
|
|
|
if (error.Fail() || process_sp == nullptr) {
|
|
|
|
|
result.AppendError(error.AsCString("Error connecting to the process"));
|
2011-02-04 01:58:07 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
2015-12-08 14:08:19 +00:00
|
|
|
return false;
|
2011-02-04 01:58:07 +00:00
|
|
|
}
|
2015-12-08 14:08:19 +00:00
|
|
|
return true;
|
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:
|
2016-08-11 23:51:28 +00:00
|
|
|
CommandOptions() : Options() {
|
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;
|
|
|
|
|
switch (short_option) {
|
|
|
|
|
case 'i':
|
|
|
|
|
do_install = true;
|
2016-11-12 16:56:47 +00:00
|
|
|
if (!option_arg.empty())
|
2018-11-01 21:05:36 +00:00
|
|
|
install_path.SetFile(option_arg, FileSpec::Style::native);
|
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 {
|
2016-09-22 21:06:13 +00:00
|
|
|
return llvm::makeArrayRef(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 |
|
2015-12-08 13:43:59 +00:00
|
|
|
eCommandProcessMustBePaused),
|
|
|
|
|
m_options() {}
|
2010-11-04 01:54:29 +00:00
|
|
|
|
2015-12-08 13:43:59 +00:00
|
|
|
~CommandObjectProcessLoad() override = default;
|
|
|
|
|
|
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:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return result.Succeeded();
|
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 |
|
|
|
|
|
eCommandProcessMustBeLaunched | eCommandProcessMustBePaused) {}
|
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
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
break;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
}
|
|
|
|
|
return result.Succeeded();
|
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) {
|
2010-10-04 22:28:36 +00:00
|
|
|
CommandArgumentEntry arg;
|
|
|
|
|
CommandArgumentData signal_arg;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
// Define the first (and only) variant of this arg.
|
2010-10-18 22:56:57 +00:00
|
|
|
signal_arg.arg_type = eArgTypeUnixSignal;
|
2010-10-04 22:28:36 +00:00
|
|
|
signal_arg.arg_repetition = eArgRepeatPlain;
|
2010-06-08 16:52:24 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
// There is only one variant this argument could be; put it into the
|
|
|
|
|
// argument entry.
|
|
|
|
|
arg.push_back(signal_arg);
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-10-04 22:28:36 +00:00
|
|
|
// Push the data for the first argument into the m_arguments vector.
|
|
|
|
|
m_arguments.push_back(arg);
|
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) {
|
|
|
|
|
request.AddCompletion(signals->GetSignalAsCString(signo), "");
|
|
|
|
|
signo = signals->GetNextSignalNumber(signo);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2012-06-08 21:56:10 +00:00
|
|
|
protected:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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));
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
} 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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
} 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());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
return result.Succeeded();
|
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:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.GetArgumentCount() == 0) {
|
2013-05-10 23:48:10 +00:00
|
|
|
bool clear_thread_plans = true;
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error(process->Halt(clear_thread_plans));
|
2010-06-08 16:52:24 +00:00
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("Failed to halt process: %s\n",
|
|
|
|
|
error.AsCString());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-09-20 21:44:10 +00:00
|
|
|
result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
|
2010-06-08 16:52:24 +00:00
|
|
|
m_cmd_name.c_str(), m_cmd_syntax.c_str());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
return result.Succeeded();
|
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:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (command.GetArgumentCount() == 0) {
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error(process->Destroy(true));
|
2010-06-08 16:52:24 +00:00
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("Failed to kill process: %s\n",
|
|
|
|
|
error.AsCString());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
2011-09-20 21:44:10 +00:00
|
|
|
result.AppendErrorWithFormat("'%s' takes no arguments:\nUsage: %s\n",
|
2010-06-08 16:52:24 +00:00
|
|
|
m_cmd_name.c_str(), m_cmd_syntax.c_str());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
2010-11-04 01:54:29 +00:00
|
|
|
return result.Succeeded();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-06-08 16:52:24 +00:00
|
|
|
};
|
|
|
|
|
|
2014-06-13 00:54:12 +00:00
|
|
|
// CommandObjectProcessSaveCore
|
|
|
|
|
#pragma mark CommandObjectProcessSaveCore
|
|
|
|
|
|
|
|
|
|
class CommandObjectProcessSaveCore : public CommandObjectParsed {
|
|
|
|
|
public:
|
|
|
|
|
CommandObjectProcessSaveCore(CommandInterpreter &interpreter)
|
|
|
|
|
: CommandObjectParsed(interpreter, "process save-core",
|
|
|
|
|
"Save the current process as a core file using an "
|
|
|
|
|
"appropriate file type.",
|
|
|
|
|
"process save-core FILE",
|
2015-05-27 05:04:35 +00:00
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock |
|
|
|
|
|
eCommandProcessMustBeLaunched) {}
|
2016-02-23 01:43:44 +00:00
|
|
|
|
|
|
|
|
~CommandObjectProcessSaveCore() override = default;
|
|
|
|
|
|
2014-06-13 00:54:12 +00:00
|
|
|
protected:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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));
|
2017-05-12 04:51:55 +00:00
|
|
|
Status error = PluginManager::SaveCore(process_sp, output_file);
|
2014-06-13 00:54:12 +00:00
|
|
|
if (error.Success()) {
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishResult);
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat(
|
|
|
|
|
"Failed to save core file for process: %s\n", error.AsCString());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendErrorWithFormat("'%s' takes one arguments:\nUsage: %s\n",
|
|
|
|
|
m_cmd_name.c_str(), m_cmd_syntax.c_str());
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
}
|
|
|
|
|
} else {
|
|
|
|
|
result.AppendError("invalid process");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2016-09-06 20:57:50 +00:00
|
|
|
|
2010-06-08 16:52:24 +00:00
|
|
|
return result.Succeeded();
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
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",
|
[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
|
|
|
eCommandRequiresProcess | eCommandTryTargetAPILock),
|
|
|
|
|
m_options() {}
|
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:
|
|
|
|
|
CommandOptions() : Options(), m_verbose(false) {}
|
|
|
|
|
|
|
|
|
|
~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;
|
|
|
|
|
default:
|
|
|
|
|
llvm_unreachable("Unimplemented option");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return {};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void OptionParsingStarting(ExecutionContext *execution_context) override {
|
|
|
|
|
m_verbose = false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
llvm::ArrayRef<OptionDefinition> GetDefinitions() override {
|
|
|
|
|
return llvm::makeArrayRef(g_process_status_options);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// Instance variables to hold the values for command options.
|
|
|
|
|
bool m_verbose;
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
protected:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool 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
|
|
|
|
|
|
|
|
if (command.GetArgumentCount()) {
|
|
|
|
|
result.AppendError("'process status' takes no arguments");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return result.Succeeded();
|
|
|
|
|
}
|
|
|
|
|
|
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) {
|
|
|
|
|
PlatformSP platform_sp = process->GetTarget().GetPlatform();
|
|
|
|
|
if (!platform_sp) {
|
|
|
|
|
result.AppendError("Couldn'retrieve the target's platform");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return result.Succeeded();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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()));
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return result.Succeeded();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
StructuredData::DictionarySP crash_info_sp = *expected_crash_info;
|
|
|
|
|
|
|
|
|
|
if (crash_info_sp) {
|
|
|
|
|
strm.PutCString("Extended Crash Information:\n");
|
|
|
|
|
crash_info_sp->Dump(strm);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2010-06-18 01:23:09 +00:00
|
|
|
return result.Succeeded();
|
|
|
|
|
}
|
[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:
|
2016-08-11 23:51:28 +00:00
|
|
|
CommandOptions() : Options() { 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) {
|
|
|
|
|
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;
|
|
|
|
|
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();
|
|
|
|
|
}
|
|
|
|
|
|
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 {
|
2016-09-22 21:06:13 +00:00
|
|
|
return llvm::makeArrayRef(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;
|
|
|
|
|
};
|
|
|
|
|
|
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.",
|
2019-08-31 09:41:25 +00:00
|
|
|
nullptr, eCommandRequiresTarget),
|
2016-08-11 23:51:28 +00:00
|
|
|
m_options() {
|
2015-07-14 05:48:36 +00:00
|
|
|
SetHelpLong("\nIf no signals are specified, update them all. If no update "
|
|
|
|
|
"option is specified, list the current values.");
|
2010-10-13 20:44:39 +00:00
|
|
|
CommandArgumentEntry arg;
|
2010-10-18 22:56:57 +00:00
|
|
|
CommandArgumentData signal_arg;
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2010-10-18 22:56:57 +00:00
|
|
|
signal_arg.arg_type = eArgTypeUnixSignal;
|
|
|
|
|
signal_arg.arg_repetition = eArgRepeatStar;
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2010-10-18 22:56:57 +00:00
|
|
|
arg.push_back(signal_arg);
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
m_arguments.push_back(arg);
|
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
|
|
|
bool VerifyCommandOptionValue(const std::string &option, int &real_value) {
|
|
|
|
|
bool okay = true;
|
2015-05-22 08:46:18 +00:00
|
|
|
bool success = false;
|
2018-04-10 09:03:59 +00:00
|
|
|
bool tmp_value = OptionArgParser::ToBoolean(option, false, &success);
|
2010-10-14 21:31:13 +00:00
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
if (success && tmp_value)
|
|
|
|
|
real_value = 1;
|
|
|
|
|
else if (success && !tmp_value)
|
2010-10-14 21:31:13 +00:00
|
|
|
real_value = 0;
|
2016-09-06 20:57:50 +00:00
|
|
|
else {
|
2015-07-14 01:09:28 +00:00
|
|
|
// If the value isn't 'true' or 'false', it had better be 0 or 1.
|
2020-07-01 17:00:12 +02:00
|
|
|
if (!llvm::to_integer(option, real_value))
|
|
|
|
|
real_value = 3;
|
2010-10-14 21:31:13 +00:00
|
|
|
if (real_value != 0 && real_value != 1)
|
|
|
|
|
okay = false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-13 20:44:39 +00:00
|
|
|
return okay;
|
2016-09-06 20:57:50 +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
|
|
|
}
|
|
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
void PrintSignal(Stream &str, int32_t signo, const char *sig_name,
|
|
|
|
|
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
|
|
|
|
2015-05-22 08:46:18 +00:00
|
|
|
str.Printf("%-11s ", 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) {
|
2015-07-14 01:09:28 +00:00
|
|
|
PrintSignal(str, signo, signals_sp->GetSignalAsCString(signo),
|
|
|
|
|
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:
|
2015-10-07 16:56:17 +00:00
|
|
|
bool DoExecute(Args &signal_args, CommandReturnObject &result) override {
|
2019-08-31 09:41:25 +00:00
|
|
|
Target *target_sp = &GetSelectedTarget();
|
2010-10-13 20:44:39 +00:00
|
|
|
|
2010-10-14 21:31:13 +00:00
|
|
|
ProcessSP process_sp = target_sp->GetProcessSP();
|
2010-10-13 20:44:39 +00:00
|
|
|
|
|
|
|
|
if (!process_sp) {
|
|
|
|
|
result.AppendError("No current process; cannot handle signals until you "
|
|
|
|
|
"have a valid process.\n");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int stop_action = -1; // -1 means leave the current setting alone
|
|
|
|
|
int pass_action = -1; // -1 means leave the current setting alone
|
|
|
|
|
int notify_action = -1; // -1 means leave the current setting alone
|
|
|
|
|
|
|
|
|
|
if (!m_options.stop.empty() &&
|
2010-10-14 21:31:13 +00:00
|
|
|
!VerifyCommandOptionValue(m_options.stop, stop_action)) {
|
2010-10-13 20:44:39 +00:00
|
|
|
result.AppendError("Invalid argument for command option --stop; must be "
|
|
|
|
|
"true or false.\n");
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2010-10-14 21:31:13 +00:00
|
|
|
if (!m_options.notify.empty() &&
|
|
|
|
|
!VerifyCommandOptionValue(m_options.notify, notify_action)) {
|
|
|
|
|
result.AppendError("Invalid argument for command option --notify; must "
|
|
|
|
|
"be true or false.\n");
|
2010-10-13 20:44:39 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2010-10-13 20:44:39 +00:00
|
|
|
if (!m_options.pass.empty() &&
|
2010-10-14 21:31:13 +00:00
|
|
|
!VerifyCommandOptionValue(m_options.pass, pass_action)) {
|
|
|
|
|
result.AppendError("Invalid argument for command option --pass; must be "
|
|
|
|
|
"true or false.\n");
|
2015-07-14 01:09:28 +00:00
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
return false;
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
|
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
size_t num_args = signal_args.GetArgumentCount();
|
|
|
|
|
UnixSignalsSP signals_sp = process_sp->GetUnixSignals();
|
|
|
|
|
int num_signals_set = 0;
|
2016-09-06 20:57:50 +00:00
|
|
|
|
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) {
|
|
|
|
|
int32_t signo = signals_sp->GetSignalNumberFromName(arg.c_str());
|
2010-10-14 21:31:13 +00:00
|
|
|
if (signo != LLDB_INVALID_SIGNAL_NUMBER) {
|
2016-08-26 23:28:47 +00:00
|
|
|
// Casting the actions as bools here should be okay, because
|
2018-04-30 16:49:04 +00:00
|
|
|
// VerifyCommandOptionValue guarantees the value is either 0 or 1.
|
2010-10-14 21:31:13 +00:00
|
|
|
if (stop_action != -1)
|
2015-07-14 01:09:28 +00:00
|
|
|
signals_sp->SetShouldStop(signo, stop_action);
|
2010-10-14 21:31:13 +00:00
|
|
|
if (pass_action != -1) {
|
2015-07-14 01:09:28 +00:00
|
|
|
bool suppress = !pass_action;
|
|
|
|
|
signals_sp->SetShouldSuppress(signo, suppress);
|
2016-09-06 20:57:50 +00:00
|
|
|
}
|
2010-10-14 21:31:13 +00:00
|
|
|
if (notify_action != -1)
|
2016-08-26 23:28:47 +00:00
|
|
|
signals_sp->SetShouldNotify(signo, notify_action);
|
2010-10-14 21:31:13 +00:00
|
|
|
++num_signals_set;
|
2016-09-06 20:57:50 +00:00
|
|
|
} else {
|
2010-10-14 21:31:13 +00:00
|
|
|
result.AppendErrorWithFormat("Invalid signal name '%s'\n",
|
2016-11-22 17:10:15 +00:00
|
|
|
arg.c_str());
|
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
|
|
|
|
|
// signals.
|
|
|
|
|
if ((notify_action != -1) || (stop_action != -1) || (pass_action != -1)) {
|
|
|
|
|
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) {
|
|
|
|
|
if (notify_action != -1)
|
2015-07-14 01:09:28 +00:00
|
|
|
signals_sp->SetShouldNotify(signo, notify_action);
|
2010-10-14 21:31:13 +00:00
|
|
|
if (stop_action != -1)
|
2015-07-14 01:09:28 +00:00
|
|
|
signals_sp->SetShouldStop(signo, stop_action);
|
2010-10-14 21:31:13 +00:00
|
|
|
if (pass_action != -1) {
|
2015-07-14 01:09:28 +00:00
|
|
|
bool suppress = !pass_action;
|
|
|
|
|
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
|
|
|
|
2015-07-14 01:09:28 +00:00
|
|
|
PrintSignalInformation(result.GetOutputStream(), signal_args,
|
|
|
|
|
num_signals_set, signals_sp);
|
2010-10-14 21:31:13 +00:00
|
|
|
|
2010-10-13 20:44:39 +00:00
|
|
|
if (num_signals_set > 0)
|
|
|
|
|
result.SetStatus(eReturnStatusSuccessFinishNoResult);
|
|
|
|
|
else
|
|
|
|
|
result.SetStatus(eReturnStatusFailed);
|
|
|
|
|
|
|
|
|
|
return result.Succeeded();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
CommandOptions m_options;
|
|
|
|
|
};
|
|
|
|
|
|
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)));
|
2010-06-08 16:52:24 +00:00
|
|
|
}
|
|
|
|
|
|
2016-02-23 01:43:44 +00:00
|
|
|
CommandObjectMultiwordProcess::~CommandObjectMultiwordProcess() = default;
|