OmarEmaraDev updated this revision to Diff 358268.
OmarEmaraDev added a comment.
- Add kill/detach form.
- Fix forms with no fields.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D105655/new/
https://reviews.llvm.org/D105655
Files:
lldb/source/Core/IOHandlerCursesGUI.cpp
Index: lldb/source/Core/IOHandlerCursesGUI.cpp
===================================================================
--- lldb/source/Core/IOHandlerCursesGUI.cpp
+++ lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -40,6 +40,7 @@
#if LLDB_ENABLE_CURSES
#include "lldb/Breakpoint/BreakpointLocation.h"
#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Core/ValueObjectRegister.h"
#include "lldb/Symbol/Block.h"
@@ -608,9 +609,19 @@
m_delete = del;
}
}
- //
+
// Get the rectangle in our parent window
Rect GetBounds() const { return Rect(GetParentOrigin(), GetSize()); }
+
+ Rect GetCenteredRect(int width, int height) {
+ Size size = GetSize();
+ width = std::min(size.width, width);
+ height = std::min(size.height, height);
+ int x = (size.width - width) / 2;
+ int y = (size.height - height) / 2;
+ return Rect(Point(x, y), Size(width, height));
+ }
+
int GetChar() { return ::wgetch(m_window); }
Point GetParentOrigin() const { return Point(GetParentX(), GetParentY()); }
int GetParentX() const { return getparx(m_window); }
@@ -1050,9 +1061,18 @@
// Select the last element in the field if multiple elements exists.
virtual void FieldDelegateSelectLastElement() { return; }
+
+ bool FieldDelegateIsVisible() { return m_is_visible; }
+
+ void FieldDelegateHide() { m_is_visible = false; }
+
+ void FieldDelegateShow() { m_is_visible = true; }
+
+protected:
+ bool m_is_visible = true;
};
-typedef std::shared_ptr<FieldDelegate> FieldDelegateSP;
+typedef std::unique_ptr<FieldDelegate> FieldDelegateUP;
class TextFieldDelegate : public FieldDelegate {
public:
@@ -1227,7 +1247,6 @@
void SetError(const char *error) { m_error = error; }
- // Returns the text content of the field.
const std::string &GetText() { return m_content; }
protected:
@@ -1634,7 +1653,7 @@
m_selection_type = SelectionType::NewButton;
}
- HandleCharResult SelecteNext(int key) {
+ HandleCharResult SelectNext(int key) {
if (m_selection_type == SelectionType::NewButton)
return eKeyNotHandled;
@@ -1707,7 +1726,7 @@
}
break;
case '\t':
- SelecteNext(key);
+ SelectNext(key);
return eKeyHandled;
case KEY_SHIFT_TAB:
SelectPrevious(key);
@@ -1812,7 +1831,11 @@
virtual ~FormDelegate() = default;
- FieldDelegateSP &GetField(int field_index) { return m_fields[field_index]; }
+ virtual std::string GetName() = 0;
+
+ virtual void UpdateFieldsVisibility() { return; }
+
+ FieldDelegateUP &GetField(int field_index) { return m_fields[field_index]; }
FormAction &GetAction(int action_index) { return m_actions[action_index]; }
@@ -1832,8 +1855,7 @@
TextFieldDelegate *AddTextField(const char *label, const char *content) {
TextFieldDelegate *delegate = new TextFieldDelegate(label, content);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
@@ -1841,8 +1863,7 @@
bool need_to_exist = true) {
FileFieldDelegate *delegate =
new FileFieldDelegate(label, content, need_to_exist);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
@@ -1851,22 +1872,19 @@
bool need_to_exist = true) {
DirectoryFieldDelegate *delegate =
new DirectoryFieldDelegate(label, content, need_to_exist);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
IntegerFieldDelegate *AddIntegerField(const char *label, int content) {
IntegerFieldDelegate *delegate = new IntegerFieldDelegate(label, content);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
BooleanFieldDelegate *AddBooleanField(const char *label, bool content) {
BooleanFieldDelegate *delegate = new BooleanFieldDelegate(label, content);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
@@ -1874,8 +1892,7 @@
std::vector<std::string> choices) {
ChoicesFieldDelegate *delegate =
new ChoicesFieldDelegate(label, height, choices);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
@@ -1883,8 +1900,7 @@
ListFieldDelegate<T> *AddListField(const char *label, T default_field) {
ListFieldDelegate<T> *delegate =
new ListFieldDelegate<T>(label, default_field);
- FieldDelegateSP delegate_sp = FieldDelegateSP(delegate);
- m_fields.push_back(delegate_sp);
+ m_fields.push_back(FieldDelegateUP(delegate));
return delegate;
}
@@ -1895,7 +1911,7 @@
}
protected:
- std::vector<FieldDelegateSP> m_fields;
+ std::vector<FieldDelegateUP> m_fields;
std::vector<FormAction> m_actions;
// Optional error message. If empty, form is considered to have no error.
std::string m_error;
@@ -1907,7 +1923,13 @@
public:
FormWindowDelegate(FormDelegateSP &delegate_sp)
: m_delegate_sp(delegate_sp), m_selection_index(0),
- m_selection_type(SelectionType::Field), m_first_visible_line(0) {}
+ m_first_visible_line(0) {
+ assert(m_delegate_sp->GetNumberOfActions() > 0);
+ if (m_delegate_sp->GetNumberOfFields() > 0)
+ m_selection_type = SelectionType::Field;
+ else
+ m_selection_type = SelectionType::Action;
+ }
// Signify which element is selected. If a field or an action is selected,
// then m_selection_index signifies the particular field or action that is
@@ -1948,6 +1970,8 @@
int height = 0;
height += GetErrorHeight();
for (int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
+ if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
+ continue;
height += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
}
height += GetActionsHeight();
@@ -1958,11 +1982,13 @@
if (m_selection_type == SelectionType::Action)
return ScrollContext(GetContentHeight() - 1);
- FieldDelegateSP &field = m_delegate_sp->GetField(m_selection_index);
+ FieldDelegateUP &field = m_delegate_sp->GetField(m_selection_index);
ScrollContext context = field->FieldDelegateGetScrollContext();
int offset = GetErrorHeight();
for (int i = 0; i < m_selection_index; i++) {
+ if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
+ continue;
offset += m_delegate_sp->GetField(i)->FieldDelegateGetHeight();
}
context.Offset(offset);
@@ -2018,8 +2044,10 @@
int width = surface.GetWidth();
bool a_field_is_selected = m_selection_type == SelectionType::Field;
for (int i = 0; i < m_delegate_sp->GetNumberOfFields(); i++) {
+ if (!m_delegate_sp->GetField(i)->FieldDelegateIsVisible())
+ continue;
bool is_field_selected = a_field_is_selected && m_selection_index == i;
- FieldDelegateSP &field = m_delegate_sp->GetField(i);
+ FieldDelegateUP &field = m_delegate_sp->GetField(i);
int height = field->FieldDelegateGetHeight();
Rect bounds = Rect(Point(0, line), Size(width, height));
SubPad field_surface = SubPad(surface, bounds);
@@ -2080,10 +2108,12 @@
}
bool WindowDelegateDraw(Window &window, bool force) override {
+ m_delegate_sp->UpdateFieldsVisibility();
window.Erase();
- window.DrawTitleBox(window.GetName(), "Press Esc to cancel");
+ window.DrawTitleBox(m_delegate_sp->GetName().c_str(),
+ "Press Esc to cancel");
Rect content_bounds = window.GetFrame();
content_bounds.Inset(2, 2);
@@ -2093,7 +2123,22 @@
return true;
}
- HandleCharResult SelecteNext(int key) {
+ void SkipNextHiddenFields() {
+ while (true) {
+ if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
+ return;
+
+ if (m_selection_index == m_delegate_sp->GetNumberOfFields() - 1) {
+ m_selection_type = SelectionType::Action;
+ m_selection_index = 0;
+ return;
+ }
+
+ m_selection_index++;
+ }
+ }
+
+ HandleCharResult SelectNext(int key) {
if (m_selection_type == SelectionType::Action) {
if (m_selection_index < m_delegate_sp->GetNumberOfActions() - 1) {
m_selection_index++;
@@ -2102,12 +2147,16 @@
m_selection_index = 0;
m_selection_type = SelectionType::Field;
- FieldDelegateSP &next_field = m_delegate_sp->GetField(m_selection_index);
- next_field->FieldDelegateSelectFirstElement();
+ SkipNextHiddenFields();
+ if (m_selection_type == SelectionType::Field) {
+ FieldDelegateUP &next_field =
+ m_delegate_sp->GetField(m_selection_index);
+ next_field->FieldDelegateSelectFirstElement();
+ }
return eKeyHandled;
}
- FieldDelegateSP &field = m_delegate_sp->GetField(m_selection_index);
+ FieldDelegateUP &field = m_delegate_sp->GetField(m_selection_index);
if (!field->FieldDelegateOnLastOrOnlyElement()) {
return field->FieldDelegateHandleChar(key);
}
@@ -2121,14 +2170,32 @@
}
m_selection_index++;
+ SkipNextHiddenFields();
- FieldDelegateSP &next_field = m_delegate_sp->GetField(m_selection_index);
- next_field->FieldDelegateSelectFirstElement();
+ if (m_selection_type == SelectionType::Field) {
+ FieldDelegateUP &next_field = m_delegate_sp->GetField(m_selection_index);
+ next_field->FieldDelegateSelectFirstElement();
+ }
return eKeyHandled;
}
- HandleCharResult SelectePrevious(int key) {
+ void SkipPreviousHiddenFields() {
+ while (true) {
+ if (m_delegate_sp->GetField(m_selection_index)->FieldDelegateIsVisible())
+ return;
+
+ if (m_selection_index == 0) {
+ m_selection_type = SelectionType::Action;
+ m_selection_index = 0;
+ return;
+ }
+
+ m_selection_index--;
+ }
+ }
+
+ HandleCharResult SelectPrevious(int key) {
if (m_selection_type == SelectionType::Action) {
if (m_selection_index > 0) {
m_selection_index--;
@@ -2136,13 +2203,16 @@
}
m_selection_index = m_delegate_sp->GetNumberOfFields() - 1;
m_selection_type = SelectionType::Field;
- FieldDelegateSP &previous_field =
- m_delegate_sp->GetField(m_selection_index);
- previous_field->FieldDelegateSelectLastElement();
+ SkipPreviousHiddenFields();
+ if (m_selection_type == SelectionType::Field) {
+ FieldDelegateUP &previous_field =
+ m_delegate_sp->GetField(m_selection_index);
+ previous_field->FieldDelegateSelectLastElement();
+ }
return eKeyHandled;
}
- FieldDelegateSP &field = m_delegate_sp->GetField(m_selection_index);
+ FieldDelegateUP &field = m_delegate_sp->GetField(m_selection_index);
if (!field->FieldDelegateOnFirstOrOnlyElement()) {
return field->FieldDelegateHandleChar(key);
}
@@ -2156,10 +2226,13 @@
}
m_selection_index--;
+ SkipPreviousHiddenFields();
- FieldDelegateSP &previous_field =
- m_delegate_sp->GetField(m_selection_index);
- previous_field->FieldDelegateSelectLastElement();
+ if (m_selection_type == SelectionType::Field) {
+ FieldDelegateUP &previous_field =
+ m_delegate_sp->GetField(m_selection_index);
+ previous_field->FieldDelegateSelectLastElement();
+ }
return eKeyHandled;
}
@@ -2167,9 +2240,11 @@
void ExecuteAction(Window &window) {
FormAction &action = m_delegate_sp->GetAction(m_selection_index);
action.Execute(window);
- m_first_visible_line = 0;
- m_selection_index = 0;
- m_selection_type = SelectionType::Field;
+ if (m_delegate_sp->HasError()) {
+ m_first_visible_line = 0;
+ m_selection_index = 0;
+ m_selection_type = SelectionType::Field;
+ }
}
HandleCharResult WindowDelegateHandleChar(Window &window, int key) override {
@@ -2183,9 +2258,9 @@
}
break;
case '\t':
- return SelecteNext(key);
+ return SelectNext(key);
case KEY_SHIFT_TAB:
- return SelectePrevious(key);
+ return SelectPrevious(key);
case KEY_ESCAPE:
window.GetParent()->RemoveSubWindow(&window);
return eKeyHandled;
@@ -2196,7 +2271,7 @@
// If the key wasn't handled and one of the fields is selected, pass the key
// to that field.
if (m_selection_type == SelectionType::Field) {
- FieldDelegateSP &field = m_delegate_sp->GetField(m_selection_index);
+ FieldDelegateUP &field = m_delegate_sp->GetField(m_selection_index);
return field->FieldDelegateHandleChar(key);
}
@@ -2213,6 +2288,217 @@
int m_first_visible_line;
};
+///////////////////////////
+// Form Delegate Instances
+///////////////////////////
+
+class DetachOrKillProcessFormDelegate : public FormDelegate {
+public:
+ DetachOrKillProcessFormDelegate(Process *process) : m_process(process) {
+ if (process->GetShouldDetach()) {
+ SetError("There is a running process, detach from it?");
+ AddAction("Detach", [this](Window &window) { Detach(window); });
+ } else {
+ SetError("There is a running process, kill it?");
+ AddAction("Kill", [this](Window &window) { Kill(window); });
+ }
+ }
+
+ std::string GetName() override { return "Detach/Kill Process"; }
+
+ void Kill(Window &window) {
+ Status destroy_status(m_process->Destroy(false));
+ if (destroy_status.Fail()) {
+ SetError("Failed to kill process.");
+ return;
+ }
+ window.GetParent()->RemoveSubWindow(&window);
+ }
+
+ void Detach(Window &window) {
+ Status detach_status(m_process->Detach(false));
+ if (detach_status.Fail()) {
+ SetError("Failed to detach from process.");
+ return;
+ }
+ window.GetParent()->RemoveSubWindow(&window);
+ }
+
+protected:
+ Process *m_process;
+};
+
+class ProcessAttachFormDelegate : public FormDelegate {
+public:
+ ProcessAttachFormDelegate(Debugger &debugger, WindowSP main_window_sp)
+ : m_debugger(debugger), m_main_window_sp(main_window_sp) {
+ std::vector<std::string> types;
+ types.push_back(std::string("Name"));
+ types.push_back(std::string("PID"));
+ m_type_field = AddChoicesField("Attach By", 2, types);
+ m_pid_field = AddIntegerField("PID", 0);
+ m_name_field =
+ AddTextField("Process Name", GetDefaultProcessName().c_str());
+ m_plugin_field =
+ AddChoicesField("Plugin Name", 3, GetPossiblePluginNames());
+ m_continue_field = AddBooleanField("Continue once attached.", false);
+ m_wait_for_field = AddBooleanField("Wait for process to launch.", false);
+ m_include_existing_field =
+ AddBooleanField("Include existing processes.", false);
+
+ AddAction("Attach", [this](Window &window) { Attach(window); });
+ }
+
+ std::string GetName() override { return "Attach Process"; }
+
+ void UpdateFieldsVisibility() override {
+ if (m_type_field->GetChoiceContent() == "Name") {
+ m_pid_field->FieldDelegateHide();
+ m_name_field->FieldDelegateShow();
+ m_wait_for_field->FieldDelegateShow();
+ if (m_wait_for_field->GetBoolean())
+ m_include_existing_field->FieldDelegateShow();
+ else
+ m_include_existing_field->FieldDelegateHide();
+ } else {
+ m_pid_field->FieldDelegateShow();
+ m_name_field->FieldDelegateHide();
+ m_wait_for_field->FieldDelegateHide();
+ m_include_existing_field->FieldDelegateHide();
+ }
+ }
+
+ // Get the basename of the target's main executable if available, empty string
+ // otherwise.
+ std::string GetDefaultProcessName() {
+ Target *target = m_debugger.GetSelectedTarget().get();
+ if (target == nullptr)
+ return "";
+
+ ModuleSP module_sp = target->GetExecutableModule();
+ if (!module_sp->IsExecutable())
+ return "";
+
+ return module_sp->GetFileSpec().GetFilename().AsCString();
+ }
+
+ std::vector<std::string> GetPossiblePluginNames() {
+ std::vector<std::string> names;
+ names.push_back("<default>");
+
+ const char *plugin_name;
+ for (int i = 0;
+ (plugin_name = PluginManager::GetProcessPluginNameAtIndex(i)) !=
+ nullptr;
+ i++) {
+ names.push_back(plugin_name);
+ }
+ return names;
+ }
+
+ 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, 7);
+ 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)
+ return target;
+
+ TargetSP new_target_sp;
+ m_debugger.GetTargetList().CreateTarget(
+ m_debugger, "", "", eLoadDependentsNo, nullptr, new_target_sp);
+
+ target = new_target_sp.get();
+
+ if (target == nullptr)
+ SetError("Failed to create target.");
+
+ m_debugger.GetTargetList().SetSelectedTarget(new_target_sp);
+
+ return target;
+ }
+
+ ProcessAttachInfo GetAttachInfo() {
+ ProcessAttachInfo attach_info;
+ attach_info.SetContinueOnceAttached(m_continue_field->GetBoolean());
+ if (m_type_field->GetChoiceContent() == "Name") {
+ attach_info.GetExecutableFile().SetFile(m_name_field->GetText(),
+ FileSpec::Style::native);
+ attach_info.SetWaitForLaunch(m_wait_for_field->GetBoolean());
+ if (m_wait_for_field->GetBoolean())
+ attach_info.SetIgnoreExisting(!m_include_existing_field->GetBoolean());
+ } else {
+ attach_info.SetProcessID(m_pid_field->GetInteger());
+ }
+ if (m_plugin_field->GetChoiceContent() != "<default>")
+ attach_info.SetProcessPluginName(m_plugin_field->GetChoiceContent());
+
+ return attach_info;
+ }
+
+ void Attach(Window &window) {
+ ClearError();
+
+ bool process_is_running = StopRunningProcess();
+ if (process_is_running)
+ return;
+
+ Target *target = GetTarget();
+ if (HasError())
+ return;
+
+ StreamString stream;
+ ProcessAttachInfo attach_info = GetAttachInfo();
+ Status status = target->Attach(attach_info, &stream);
+
+ if (status.Fail()) {
+ SetError(status.AsCString());
+ return;
+ }
+
+ ProcessSP process_sp(target->GetProcessSP());
+ if (!process_sp) {
+ SetError("Attached sucessfully but target has no process.");
+ return;
+ }
+
+ window.GetParent()->RemoveSubWindow(&window);
+ }
+
+protected:
+ Debugger &m_debugger;
+ WindowSP m_main_window_sp;
+
+ ChoicesFieldDelegate *m_type_field;
+ IntegerFieldDelegate *m_pid_field;
+ TextFieldDelegate *m_name_field;
+ ChoicesFieldDelegate *m_plugin_field;
+ BooleanFieldDelegate *m_continue_field;
+ BooleanFieldDelegate *m_wait_for_field;
+ BooleanFieldDelegate *m_include_existing_field;
+};
+
class MenuDelegate {
public:
virtual ~MenuDelegate() = default;
@@ -4462,6 +4748,19 @@
}
return MenuActionResult::Handled;
+ case eMenuID_ProcessAttach: {
+ WindowSP main_window_sp = m_app.GetMainWindow();
+ FormDelegateSP form_delegate_sp = FormDelegateSP(
+ new ProcessAttachFormDelegate(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 =
m_debugger.GetCommandInterpreter().GetExecutionContext();
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits