OmarEmaraDev created this revision.
OmarEmaraDev added a reviewer: clayborg.
Herald added a reviewer: teemperor.
OmarEmaraDev requested review of this revision.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.
This patch adds a process launch form. Additionally, a LazyBoolean field
was implemented and numerous utility methods were added to various
fields to get the launch form working.
Repository:
rG LLVM Github Monorepo
https://reviews.llvm.org/D107869
Files:
lldb/source/Core/IOHandlerCursesGUI.cpp
Index: lldb/source/Core/IOHandlerCursesGUI.cpp
===================================================================
--- lldb/source/Core/IOHandlerCursesGUI.cpp
+++ lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -28,6 +28,7 @@
#include "lldb/Core/StreamFile.h"
#include "lldb/Core/ValueObjectUpdater.h"
#include "lldb/Host/File.h"
+#include "lldb/Host/HostInfo.h"
#include "lldb/Utility/Predicate.h"
#include "lldb/Utility/Status.h"
#include "lldb/Utility/StreamString.h"
@@ -1619,6 +1620,33 @@
}
};
+class LazyBooleanFieldDelegate : public ChoicesFieldDelegate {
+public:
+ LazyBooleanFieldDelegate(const char *label, const char *calculate_label)
+ : ChoicesFieldDelegate(label, 3, GetPossibleOptions(calculate_label)) {}
+
+ static constexpr const char *kNo = "No";
+ static constexpr const char *kYes = "Yes";
+
+ std::vector<std::string> GetPossibleOptions(const char *calculate_label) {
+ std::vector<std::string> options;
+ options.push_back(calculate_label);
+ options.push_back(kYes);
+ options.push_back(kNo);
+ return options;
+ }
+
+ LazyBool GetLazyBoolean() {
+ std::string choice = GetChoiceContent();
+ if (choice == kNo)
+ return eLazyBoolNo;
+ else if (choice == kYes)
+ return eLazyBoolYes;
+ else
+ return eLazyBoolCalculate;
+ }
+};
+
template <class T> class ListFieldDelegate : public FieldDelegate {
public:
ListFieldDelegate(const char *label, T default_field)
@@ -1909,6 +1937,21 @@
SelectionType m_selection_type;
};
+class ArgumentsFieldDelegate : public ListFieldDelegate<TextFieldDelegate> {
+public:
+ ArgumentsFieldDelegate()
+ : ListFieldDelegate("Arguments",
+ TextFieldDelegate("Argument", "", false)) {}
+
+ Args GetArguments() {
+ Args arguments;
+ for (int i = 0; i < GetNumberOfFields(); i++) {
+ arguments.AppendArgument(GetField(i).GetText());
+ }
+ return arguments;
+ }
+};
+
template <class KeyFieldDelegateType, class ValueFieldDelegateType>
class MappingFieldDelegate : public FieldDelegate {
public:
@@ -2077,6 +2120,15 @@
EnvironmentVariableListFieldDelegate()
: ListFieldDelegate("Environment Variables",
EnvironmentVariableFieldDelegate()) {}
+
+ Environment GetEnvironment() {
+ Environment environment;
+ for (int i = 0; i < GetNumberOfFields(); i++) {
+ environment.insert(
+ std::make_pair(GetField(i).GetName(), GetField(i).GetValue()));
+ }
+ return environment;
+ }
};
class FormAction {
@@ -2201,6 +2253,14 @@
return delegate;
}
+ LazyBooleanFieldDelegate *AddLazyBooleanField(const char *label,
+ const char *calculate_label) {
+ LazyBooleanFieldDelegate *delegate =
+ new LazyBooleanFieldDelegate(label, calculate_label);
+ m_fields.push_back(FieldDelegateUP(delegate));
+ return delegate;
+ }
+
ChoicesFieldDelegate *AddChoicesField(const char *label, int height,
std::vector<std::string> choices) {
ChoicesFieldDelegate *delegate =
@@ -2230,6 +2290,12 @@
return delegate;
}
+ ArgumentsFieldDelegate *AddArgumentsField() {
+ ArgumentsFieldDelegate *delegate = new ArgumentsFieldDelegate();
+ m_fields.push_back(FieldDelegateUP(delegate));
+ return delegate;
+ }
+
template <class K, class V>
MappingFieldDelegate<K, V> *AddMappingField(K key_field, V value_field) {
MappingFieldDelegate<K, V> *delegate =
@@ -3031,6 +3097,309 @@
ChoicesFieldDelegate *m_load_dependent_files_field;
};
+class ProcessLaunchFormDelegate : public FormDelegate {
+public:
+ ProcessLaunchFormDelegate(Debugger &debugger, WindowSP main_window_sp)
+ : m_debugger(debugger), m_main_window_sp(main_window_sp) {
+
+ m_arguments_field = AddArgumentsField();
+ m_enviroment_field = AddEnvironmentVariableListField();
+
+ m_show_advanced_field = AddBooleanField("Show advanced settings.", false);
+
+ m_stop_at_entry_field = AddBooleanField("Stop at entry point.", false);
+ m_working_directory_field =
+ AddDirectoryField("Working Directory", "", /*need_to_exist=*/true,
+ /*required=*/false);
+ m_disable_aslr_field =
+ AddLazyBooleanField("Disable ASLR", "Use target setting");
+ m_plugin_field = AddProcessPluginField();
+ m_arch_field = AddArchField("Architecture", "", /*required=*/false);
+ m_shell_field = AddFileField("Shell", "", /*need_to_exist=*/true,
+ /*required=*/false);
+ m_expand_shell_arguments_field =
+ AddBooleanField("Expand shell arguments.", false);
+ m_standard_output_field =
+ AddFileField("Standard Output", "", /*need_to_exist=*/false,
+ /*required=*/false);
+ m_standard_error_field =
+ AddFileField("Standard Error", "", /*need_to_exist=*/false,
+ /*required=*/false);
+ m_standard_input_field =
+ AddFileField("Standard Input", "", /*need_to_exist=*/false,
+ /*required=*/false);
+
+ AddAction("Launch", [this](Window &window) { Launch(window); });
+ }
+
+ std::string GetName() override { return "Launch Process"; }
+
+ void UpdateFieldsVisibility() override {
+ if (m_show_advanced_field->GetBoolean()) {
+ m_stop_at_entry_field->FieldDelegateShow();
+ m_working_directory_field->FieldDelegateShow();
+ m_disable_aslr_field->FieldDelegateShow();
+ m_plugin_field->FieldDelegateShow();
+ m_arch_field->FieldDelegateShow();
+ m_shell_field->FieldDelegateShow();
+ m_expand_shell_arguments_field->FieldDelegateShow();
+ m_standard_input_field->FieldDelegateShow();
+ m_standard_output_field->FieldDelegateShow();
+ m_standard_error_field->FieldDelegateShow();
+ } else {
+ m_stop_at_entry_field->FieldDelegateHide();
+ m_working_directory_field->FieldDelegateHide();
+ m_disable_aslr_field->FieldDelegateHide();
+ m_plugin_field->FieldDelegateHide();
+ m_arch_field->FieldDelegateHide();
+ m_shell_field->FieldDelegateHide();
+ m_expand_shell_arguments_field->FieldDelegateHide();
+ m_standard_input_field->FieldDelegateHide();
+ m_standard_output_field->FieldDelegateHide();
+ m_standard_error_field->FieldDelegateHide();
+ }
+ }
+
+ void SetArguments(ProcessLaunchInfo &launch_info) {
+ TargetSP target = m_debugger.GetSelectedTarget();
+ Args arguments = m_arguments_field->GetArguments();
+ if (arguments.GetArgumentCount() != 0)
+ launch_info.GetArguments().AppendArguments(arguments);
+
+ launch_info.GetArguments().AppendArguments(
+ target->GetProcessLaunchInfo().GetArguments());
+ }
+
+ void SetEnvironment(ProcessLaunchInfo &launch_info) {
+ Environment environment = m_enviroment_field->GetEnvironment();
+ launch_info.GetEnvironment().insert(environment.begin(), environment.end());
+
+ TargetSP target = m_debugger.GetSelectedTarget();
+ Environment target_environment = target->GetEnvironment();
+ launch_info.GetEnvironment().insert(target_environment.begin(),
+ target_environment.end());
+ }
+
+ void SetStopAtEntry(ProcessLaunchInfo &launch_info) {
+ if (m_stop_at_entry_field->GetBoolean())
+ launch_info.GetFlags().Set(eLaunchFlagStopAtEntry);
+ }
+
+ void SetWorkingDirectory(ProcessLaunchInfo &launch_info) {
+ if (m_working_directory_field->IsSpecified())
+ launch_info.SetWorkingDirectory(
+ m_working_directory_field->GetResolvedFileSpec());
+ }
+
+ void SetDisableASLR(ProcessLaunchInfo &launch_info) {
+ bool disable_aslr;
+ LazyBool lazy_boolean = m_disable_aslr_field->GetLazyBoolean();
+ if (lazy_boolean == eLazyBoolCalculate)
+ disable_aslr = m_debugger.GetSelectedTarget()->GetDisableASLR();
+ else
+ disable_aslr = lazy_boolean == eLazyBoolYes;
+
+ if (disable_aslr)
+ launch_info.GetFlags().Set(eLaunchFlagDisableASLR);
+ else
+ launch_info.GetFlags().Clear(eLaunchFlagDisableASLR);
+ }
+
+ void SetPlugin(ProcessLaunchInfo &launch_info) {
+ launch_info.SetProcessPluginName(m_plugin_field->GetPluginName());
+ }
+
+ void SetArch(ProcessLaunchInfo &launch_info) {
+ TargetSP target_sp = m_debugger.GetSelectedTarget();
+ PlatformSP platform_sp =
+ target_sp ? target_sp->GetPlatform() : PlatformSP();
+ launch_info.GetArchitecture() = Platform::GetAugmentedArchSpec(
+ platform_sp.get(), m_arch_field->GetArchString());
+ }
+
+ void SetShell(ProcessLaunchInfo &launch_info) {
+ if (m_shell_field->IsSpecified())
+ launch_info.SetShell(m_shell_field->GetResolvedFileSpec());
+ else
+ launch_info.SetShell(HostInfo::GetDefaultShell());
+ launch_info.SetShellExpandArguments(
+ m_expand_shell_arguments_field->GetBoolean());
+ }
+
+ void AddFileActions(ProcessLaunchInfo &launch_info) {
+ FileAction action;
+ const FileSpec dev_null(FileSystem::DEV_NULL);
+
+ if (m_standard_input_field->IsSpecified()) {
+ action.Open(STDIN_FILENO, m_standard_input_field->GetFileSpec(), true,
+ false);
+ launch_info.AppendFileAction(action);
+ } else {
+ action.Open(STDIN_FILENO, dev_null, true, false);
+ launch_info.AppendFileAction(action);
+ }
+
+ if (m_standard_output_field->IsSpecified()) {
+ action.Open(STDOUT_FILENO, m_standard_output_field->GetFileSpec(), false,
+ true);
+ launch_info.AppendFileAction(action);
+ } else {
+ action.Open(STDOUT_FILENO, dev_null, false, true);
+ launch_info.AppendFileAction(action);
+ }
+
+ if (m_standard_error_field->IsSpecified()) {
+ action.Open(STDERR_FILENO, m_standard_error_field->GetFileSpec(), false,
+ true);
+ launch_info.AppendFileAction(action);
+ } else {
+ action.Open(STDERR_FILENO, dev_null, false, true);
+ launch_info.AppendFileAction(action);
+ }
+ }
+
+ void SetTargetSettings(ProcessLaunchInfo &launch_info) {
+ TargetSP target = m_debugger.GetSelectedTarget();
+
+ if (target->GetInheritTCC())
+ launch_info.GetFlags().Set(eLaunchFlagInheritTCCFromParent);
+
+ if (target->GetDetachOnError())
+ launch_info.GetFlags().Set(eLaunchFlagDetachOnError);
+
+ if (target->GetDisableSTDIO())
+ launch_info.GetFlags().Set(eLaunchFlagDisableSTDIO);
+ }
+
+ void SetExecutable(ProcessLaunchInfo &launch_info) {
+ TargetSP target = m_debugger.GetSelectedTarget();
+ ModuleSP executable_module = target->GetExecutableModule();
+ llvm::StringRef target_settings_argv0 = target->GetArg0();
+
+ if (!target_settings_argv0.empty()) {
+ launch_info.GetArguments().AppendArgument(target_settings_argv0);
+ launch_info.SetExecutableFile(executable_module->GetPlatformFileSpec(),
+ false);
+ return;
+ }
+
+ launch_info.SetExecutableFile(executable_module->GetPlatformFileSpec(),
+ true);
+ }
+
+ ProcessLaunchInfo GetLaunchInfo() {
+ ProcessLaunchInfo launch_info;
+
+ SetArguments(launch_info);
+ SetEnvironment(launch_info);
+ SetStopAtEntry(launch_info);
+ SetWorkingDirectory(launch_info);
+ SetDisableASLR(launch_info);
+ SetPlugin(launch_info);
+ SetArch(launch_info);
+ SetShell(launch_info);
+ AddFileActions(launch_info);
+ SetTargetSettings(launch_info);
+ SetExecutable(launch_info);
+
+ return launch_info;
+ }
+
+ bool StopRunningProcess() {
+ ExecutionContext exe_ctx =
+ m_debugger.GetCommandInterpreter().GetExecutionContext();
+
+ if (!exe_ctx.HasProcessScope())
+ return false;
+
+ Process *process = exe_ctx.GetProcessPtr();
+ if (!(process && process->IsAlive()))
+ return false;
+
+ FormDelegateSP form_delegate_sp =
+ FormDelegateSP(new DetachOrKillProcessFormDelegate(process));
+ Rect bounds = m_main_window_sp->GetCenteredRect(85, 8);
+ WindowSP form_window_sp = m_main_window_sp->CreateSubWindow(
+ form_delegate_sp->GetName().c_str(), bounds, true);
+ WindowDelegateSP window_delegate_sp =
+ WindowDelegateSP(new FormWindowDelegate(form_delegate_sp));
+ form_window_sp->SetDelegate(window_delegate_sp);
+
+ return true;
+ }
+
+ Target *GetTarget() {
+ Target *target = m_debugger.GetSelectedTarget().get();
+
+ if (target == nullptr) {
+ SetError("No target exists!");
+ return nullptr;
+ }
+
+ ModuleSP exe_module_sp = target->GetExecutableModule();
+
+ if (exe_module_sp == nullptr) {
+ SetError("No executable in target!");
+ return nullptr;
+ }
+
+ return target;
+ }
+
+ void Launch(Window &window) {
+ ClearError();
+
+ bool all_fields_are_valid = CheckFieldsValidity();
+ if (!all_fields_are_valid)
+ return;
+
+ bool process_is_running = StopRunningProcess();
+ if (process_is_running)
+ return;
+
+ Target *target = GetTarget();
+ if (HasError())
+ return;
+
+ StreamString stream;
+ ProcessLaunchInfo launch_info = GetLaunchInfo();
+ Status status = target->Launch(launch_info, &stream);
+
+ if (status.Fail()) {
+ SetError(status.AsCString());
+ return;
+ }
+
+ ProcessSP process_sp(target->GetProcessSP());
+ if (!process_sp) {
+ SetError("Launched successfully but target has no process!");
+ return;
+ }
+
+ window.GetParent()->RemoveSubWindow(&window);
+ }
+
+protected:
+ Debugger &m_debugger;
+ WindowSP m_main_window_sp;
+
+ ArgumentsFieldDelegate *m_arguments_field;
+ EnvironmentVariableListFieldDelegate *m_enviroment_field;
+
+ BooleanFieldDelegate *m_show_advanced_field;
+
+ BooleanFieldDelegate *m_stop_at_entry_field;
+ DirectoryFieldDelegate *m_working_directory_field;
+ LazyBooleanFieldDelegate *m_disable_aslr_field;
+ ProcessPluginFieldDelegate *m_plugin_field;
+ ArchFieldDelegate *m_arch_field;
+ FileFieldDelegate *m_shell_field;
+ BooleanFieldDelegate *m_expand_shell_arguments_field;
+ FileFieldDelegate *m_standard_input_field;
+ FileFieldDelegate *m_standard_output_field;
+ FileFieldDelegate *m_standard_error_field;
+};
+
class MenuDelegate {
public:
virtual ~MenuDelegate() = default;
@@ -5348,6 +5717,18 @@
form_window_sp->SetDelegate(window_delegate_sp);
return MenuActionResult::Handled;
}
+ case eMenuID_ProcessLaunch: {
+ WindowSP main_window_sp = m_app.GetMainWindow();
+ FormDelegateSP form_delegate_sp = FormDelegateSP(
+ new ProcessLaunchFormDelegate(m_debugger, main_window_sp));
+ Rect bounds = main_window_sp->GetCenteredRect(80, 22);
+ WindowSP form_window_sp = main_window_sp->CreateSubWindow(
+ form_delegate_sp->GetName().c_str(), bounds, true);
+ WindowDelegateSP window_delegate_sp =
+ WindowDelegateSP(new FormWindowDelegate(form_delegate_sp));
+ form_window_sp->SetDelegate(window_delegate_sp);
+ return MenuActionResult::Handled;
+ }
case eMenuID_ProcessContinue: {
ExecutionContext exe_ctx =
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits