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 Create Target form for the LLDB GUI. Additionally, an
Arch Field was introduced to input an arch and the file and directory
fields now have a required property.


Repository:
  rG LLVM Github Monorepo

https://reviews.llvm.org/D106192

Files:
  lldb/source/Core/IOHandlerCursesGUI.cpp

Index: lldb/source/Core/IOHandlerCursesGUI.cpp
===================================================================
--- lldb/source/Core/IOHandlerCursesGUI.cpp
+++ lldb/source/Core/IOHandlerCursesGUI.cpp
@@ -36,6 +36,7 @@
 
 #include "lldb/Interpreter/CommandCompletions.h"
 #include "lldb/Interpreter/CommandInterpreter.h"
+#include "lldb/Interpreter/OptionGroupPlatform.h"
 
 #if LLDB_ENABLE_CURSES
 #include "lldb/Breakpoint/BreakpointLocation.h"
@@ -56,6 +57,7 @@
 #include "lldb/Utility/State.h"
 #endif
 
+#include "llvm/ADT/ScopeExit.h"
 #include "llvm/ADT/StringRef.h"
 
 #ifdef _WIN32
@@ -1279,13 +1281,15 @@
 class FileFieldDelegate : public TextFieldDelegate {
 public:
   FileFieldDelegate(const char *label, const char *content,
-                    bool need_to_exist = true)
-      : TextFieldDelegate(label, content), m_need_to_exist(need_to_exist) {}
+                    bool need_to_exist = true, bool required = true)
+      : TextFieldDelegate(label, content), m_need_to_exist(need_to_exist),
+        m_required(required) {}
 
-  // Set appropriate error messages if the file doesn't exists or is, in fact, a
-  // directory.
   void FieldDelegateExitCallback() override {
-    FileSpec file(GetPath());
+    if (m_content.empty() && !m_required)
+      return;
+
+    FileSpec file = GetFileSpec();
     if (m_need_to_exist && !FileSystem::Instance().Exists(file)) {
       SetError("File doesn't exist!");
       return;
@@ -1296,23 +1300,33 @@
     }
   }
 
-  // Returns the path of the file.
   const std::string &GetPath() { return m_content; }
 
+  bool IsSpecified() { return !m_content.empty(); }
+
+  FileSpec GetFileSpec() {
+    FileSpec file_spec(m_content);
+    FileSystem::Instance().Resolve(file_spec);
+    return file_spec;
+  }
+
 protected:
   bool m_need_to_exist;
+  bool m_required;
 };
 
 class DirectoryFieldDelegate : public TextFieldDelegate {
 public:
   DirectoryFieldDelegate(const char *label, const char *content,
-                         bool need_to_exist = true)
-      : TextFieldDelegate(label, content), m_need_to_exist(need_to_exist) {}
+                         bool need_to_exist = true, bool required = true)
+      : TextFieldDelegate(label, content), m_need_to_exist(need_to_exist),
+        m_required(required) {}
 
-  // Set appropriate error messages if the directory doesn't exists or is, in
-  // fact, a file.
   void FieldDelegateExitCallback() override {
-    FileSpec file(GetPath());
+    if (m_content.empty() && !m_required)
+      return;
+
+    FileSpec file = GetFileSpec();
     if (m_need_to_exist && !FileSystem::Instance().Exists(file)) {
       SetError("Directory doesn't exist!");
       return;
@@ -1323,11 +1337,43 @@
     }
   }
 
-  // Returns the path of the file.
   const std::string &GetPath() { return m_content; }
 
+  bool IsSpecified() { return !m_content.empty(); }
+
+  FileSpec GetFileSpec() {
+    FileSpec file_spec(m_content);
+    FileSystem::Instance().Resolve(file_spec);
+    return file_spec;
+  }
+
 protected:
   bool m_need_to_exist;
+  bool m_required;
+};
+
+class ArchFieldDelegate : public TextFieldDelegate {
+public:
+  ArchFieldDelegate(const char *label, const char *content,
+                    bool required = false)
+      : TextFieldDelegate(label, content), m_required(required) {}
+
+  void FieldDelegateExitCallback() override {
+    if (m_content.empty() && !m_required)
+      return;
+
+    if (GetArchSpec().IsValid())
+      return;
+
+    SetError("Not a valid arch!");
+  }
+
+  const std::string &GetArchString() { return m_content; }
+
+  ArchSpec GetArchSpec() { return ArchSpec(GetArchString()); }
+
+protected:
+  bool m_required;
 };
 
 class BooleanFieldDelegate : public FieldDelegate {
@@ -1863,18 +1909,28 @@
   }
 
   FileFieldDelegate *AddFileField(const char *label, const char *content,
-                                  bool need_to_exist = true) {
+                                  bool need_to_exist = true,
+                                  bool required = true) {
     FileFieldDelegate *delegate =
-        new FileFieldDelegate(label, content, need_to_exist);
+        new FileFieldDelegate(label, content, need_to_exist, required);
     m_fields.push_back(FieldDelegateUP(delegate));
     return delegate;
   }
 
   DirectoryFieldDelegate *AddDirectoryField(const char *label,
                                             const char *content,
-                                            bool need_to_exist = true) {
+                                            bool need_to_exist = true,
+                                            bool required = true) {
     DirectoryFieldDelegate *delegate =
-        new DirectoryFieldDelegate(label, content, need_to_exist);
+        new DirectoryFieldDelegate(label, content, need_to_exist, required);
+    m_fields.push_back(FieldDelegateUP(delegate));
+    return delegate;
+  }
+
+  ArchFieldDelegate *AddArchField(const char *label, const char *content,
+                                  bool required = false) {
+    ArchFieldDelegate *delegate =
+        new ArchFieldDelegate(label, content, required);
     m_fields.push_back(FieldDelegateUP(delegate));
     return delegate;
   }
@@ -2507,6 +2563,174 @@
   ChoicesFieldDelegate *m_plugin_field;
 };
 
+class TargetCreateFormDelegate : public FormDelegate {
+public:
+  TargetCreateFormDelegate(Debugger &debugger) : m_debugger(debugger) {
+    m_file_field = AddFileField("File", "");
+    m_core_file_field = AddFileField("Core File", "", true, false);
+    m_symbol_file_field = AddFileField("Symbol File", "", true, false);
+    m_show_advanced_field = AddBooleanField("Show advanced settings.", false);
+    m_arch_field = AddArchField("Architecture", "");
+    std::vector<std::string> load_depentents_options;
+    load_depentents_options.push_back(
+        std::string("Only if the target is an executable."));
+    load_depentents_options.push_back(std::string("Yes."));
+    load_depentents_options.push_back(std::string("No."));
+    m_load_dependent_files_field =
+        AddChoicesField("Load Dependents", 3, load_depentents_options);
+
+    AddAction("Create", [this](Window &window) { CreateTarget(window); });
+  }
+
+  std::string GetName() override { return "Create Target"; }
+
+  void UpdateFieldsVisibility() override {
+    if (m_show_advanced_field->GetBoolean()) {
+      m_arch_field->FieldDelegateShow();
+      m_load_dependent_files_field->FieldDelegateShow();
+    } else {
+      m_arch_field->FieldDelegateHide();
+      m_load_dependent_files_field->FieldDelegateHide();
+    }
+  }
+
+  LoadDependentFiles GetLoadDependentFiles() {
+    std::string choice = m_load_dependent_files_field->GetChoiceContent();
+    if (choice == "No.")
+      return eLoadDependentsNo;
+    if (choice == "Yes.")
+      return eLoadDependentsYes;
+    return eLoadDependentsDefault;
+  }
+
+  TargetSP GetTarget() {
+    FileSpec file_spec = m_file_field->GetFileSpec();
+
+    if (!FileSystem::Instance().Exists(file_spec)) {
+      SetError("File doesn't exist!");
+      return nullptr;
+    }
+
+    if (!FileSystem::Instance().Open(file_spec,
+                                     lldb_private::File::eOpenOptionRead)) {
+      SetError("Can't open file!");
+      return nullptr;
+    }
+
+    OptionGroupPlatform platform_options(false);
+    TargetSP target_sp;
+    Status status = m_debugger.GetTargetList().CreateTarget(
+        m_debugger, m_file_field->GetPath(), m_arch_field->GetArchString(),
+        GetLoadDependentFiles(), &platform_options, target_sp);
+
+    if (status.Fail()) {
+      SetError(status.AsCString());
+      return nullptr;
+    }
+
+    m_debugger.GetTargetList().SetSelectedTarget(target_sp);
+
+    return target_sp;
+  }
+
+  void SetSymbolFile(TargetSP target_sp) {
+    if (!m_symbol_file_field->IsSpecified()) {
+      return;
+    }
+
+    FileSpec symbol_file_spec = m_symbol_file_field->GetFileSpec();
+
+    if (!FileSystem::Instance().Exists(symbol_file_spec)) {
+      SetError("Symbol file doesn't exist!");
+      return;
+    }
+
+    if (!FileSystem::Instance().Open(symbol_file_spec,
+                                     lldb_private::File::eOpenOptionRead)) {
+      SetError("Can't open symbol file!");
+      return;
+    }
+
+    ModuleSP module_sp(target_sp->GetExecutableModule());
+    if (!module_sp)
+      return;
+
+    module_sp->SetSymbolFileFileSpec(symbol_file_spec);
+  }
+
+  void SetCoreFile(TargetSP target_sp) {
+    if (!m_core_file_field->IsSpecified()) {
+      return;
+    }
+
+    FileSpec core_file_spec = m_core_file_field->GetFileSpec();
+
+    if (!FileSystem::Instance().Exists(core_file_spec)) {
+      SetError("Core file doesn't exist!");
+      return;
+    }
+
+    if (!FileSystem::Instance().Open(core_file_spec,
+                                     lldb_private::File::eOpenOptionRead)) {
+      SetError("Can't open core file!");
+      return;
+    }
+
+    FileSpec core_file_directory_spec;
+    core_file_directory_spec.GetDirectory() = core_file_spec.GetDirectory();
+    target_sp->AppendExecutableSearchPaths(core_file_directory_spec);
+
+    ProcessSP process_sp(target_sp->CreateProcess(
+        m_debugger.GetListener(), llvm::StringRef(), &core_file_spec, false));
+
+    if (!process_sp) {
+      SetError("Unable to find process plug-in for core file!");
+    }
+
+    Status status = process_sp->LoadCore();
+    if (status.Fail()) {
+      SetError("Can't find plug-in for core file!");
+      return;
+    }
+  }
+
+  void RemoveTarget(TargetSP target_sp) {
+    m_debugger.GetTargetList().DeleteTarget(target_sp);
+  }
+
+  void CreateTarget(Window &window) {
+    ClearError();
+
+    TargetSP target_sp = GetTarget();
+    if (HasError())
+      return;
+
+    SetSymbolFile(target_sp);
+    if (HasError()) {
+      RemoveTarget(target_sp);
+      return;
+    }
+
+    SetCoreFile(target_sp);
+    if (HasError()) {
+      RemoveTarget(target_sp);
+      return;
+    }
+
+    window.GetParent()->RemoveSubWindow(&window);
+  }
+
+protected:
+  Debugger &m_debugger;
+
+  FileFieldDelegate *m_file_field;
+  FileFieldDelegate *m_core_file_field;
+  FileFieldDelegate *m_symbol_file_field;
+  BooleanFieldDelegate *m_show_advanced_field;
+  ArchFieldDelegate *m_arch_field;
+  ChoicesFieldDelegate *m_load_dependent_files_field;
+};
+
 class MenuDelegate {
 public:
   virtual ~MenuDelegate() = default;
@@ -2934,15 +3158,15 @@
     bool done = false;
     int delay_in_tenths_of_a_second = 1;
 
-    // Alas the threading model in curses is a bit lame so we need to resort to
-    // polling every 0.5 seconds. We could poll for stdin ourselves and then
-    // pass the keys down but then we need to translate all of the escape
+    // Alas the threading model in curses is a bit lame so we need to resort
+    // to polling every 0.5 seconds. We could poll for stdin ourselves and
+    // then pass the keys down but then we need to translate all of the escape
     // sequences ourselves. So we resort to polling for input because we need
     // to receive async process events while in this loop.
 
-    halfdelay(delay_in_tenths_of_a_second); // Poll using some number of tenths
-                                            // of seconds seconds when calling
-                                            // Window::GetChar()
+    halfdelay(delay_in_tenths_of_a_second); // Poll using some number of
+                                            // tenths of seconds seconds when
+                                            // calling Window::GetChar()
 
     ListenerSP listener_sp(
         Listener::MakeListener("lldb.IOHandler.curses.Application"));
@@ -4718,6 +4942,18 @@
 
   MenuActionResult MenuDelegateAction(Menu &menu) override {
     switch (menu.GetIdentifier()) {
+    case eMenuID_TargetCreate: {
+      WindowSP main_window_sp = m_app.GetMainWindow();
+      FormDelegateSP form_delegate_sp =
+          FormDelegateSP(new TargetCreateFormDelegate(m_debugger));
+      Rect bounds = main_window_sp->GetCenteredRect(80, 19);
+      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_ThreadStepIn: {
       ExecutionContext exe_ctx =
           m_debugger.GetCommandInterpreter().GetExecutionContext();
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to