Skip to content

[lldb][AIX] Added new plugin AIX-DYLD (Dynamic Loader) Base Support #115714

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: main
Choose a base branch
from

Conversation

Lakshmi-Surekha
Copy link
Contributor

@Lakshmi-Surekha Lakshmi-Surekha commented Nov 11, 2024

This PR is in reference to porting LLDB on AIX.

Link to discussions on llvm discourse and github:

  1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640
  2. Extending LLDB to work on AIX #101657
    The complete changes for porting are present in this draft PR:
    Extending LLDB to work on AIX #102601
    Added Dynamic Loader base implementation for LLDB support on AIX

Added base functionality. Will enhance the files in incremental PRs

@DavidSpickett @labath @DhruvSrivastavaX

Copy link

Thank you for submitting a Pull Request (PR) to the LLVM Project!

This PR will be automatically labeled and the relevant teams will be notified.

If you wish to, you can add reviewers by using the "Reviewers" section on this page.

If this is not working for you, it is probably because you do not have write permissions for the repository. In which case you can instead tag reviewers by name in a comment by using @ followed by their GitHub username.

If you have received no comments on your PR for a week, you can request a review by "ping"ing the PR by adding a comment “Ping”. The common courtesy "ping" rate is once a week. Please remember that you are asking for valuable time from other developers.

If you have further questions, they may be answered by the LLVM GitHub User Guide.

You can also ask questions in a comment on this PR, on the LLVM Discord or on the forums.

@llvmbot llvmbot added the lldb label Nov 11, 2024
@llvmbot
Copy link
Member

llvmbot commented Nov 11, 2024

@llvm/pr-subscribers-lldb

Author: None (Lakshmi-Surekha)

Changes

This PR is in reference to porting LLDB on AIX.

Link to discussions on llvm discourse and github:

  1. https://discourse.llvm.org/t/port-lldb-to-ibm-aix/80640
  2. Extending LLDB to work on AIX #101657
    The complete changes for porting are present in this draft PR:
    Extending LLDB to work on AIX #102601
    Added Dynamic Loader base implementation for LLDB support for AIX

Added base functionality. Will enhance the files in incremental PRs

@DavidSpickett @labath @DhruvSrivastavaX


Full diff: https://github.com/llvm/llvm-project/pull/115714.diff

4 Files Affected:

  • (added) lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt (+9)
  • (added) lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp (+146)
  • (added) lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h (+53)
  • (modified) lldb/source/Plugins/DynamicLoader/CMakeLists.txt (+1)
diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt
new file mode 100644
index 00000000000000..c3bd424479f17c
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/CMakeLists.txt
@@ -0,0 +1,9 @@
+add_lldb_library(lldbPluginDynamicLoaderAIXDYLD PLUGIN
+  DynamicLoaderAIXDYLD.cpp
+
+  LINK_LIBS
+    lldbCore
+    lldbTarget
+  LINK_COMPONENTS
+    Support
+  )
diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp
new file mode 100644
index 00000000000000..6b48737551bfb4
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.cpp
@@ -0,0 +1,146 @@
+//===-- DynamicLoaderAIXDYLD.cpp --------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "DynamicLoaderAIXDYLD.h"
+
+#include "lldb/Core/Module.h"
+#include "lldb/Core/PluginManager.h"
+#include "lldb/Target/ExecutionContext.h"
+#include "lldb/Target/Platform.h"
+#include "lldb/Target/Process.h"
+#include "lldb/Target/RegisterContext.h"
+#include "lldb/Target/Target.h"
+#include "lldb/Target/ThreadPlanStepInstruction.h"
+#include "lldb/Utility/LLDBLog.h"
+#include "lldb/Utility/Log.h"
+
+using namespace lldb;
+using namespace lldb_private;
+
+LLDB_PLUGIN_DEFINE(DynamicLoaderAIXDYLD)
+
+DynamicLoaderAIXDYLD::DynamicLoaderAIXDYLD(Process *process)
+    : DynamicLoader(process) {}
+
+DynamicLoaderAIXDYLD::~DynamicLoaderAIXDYLD() = default;
+
+void DynamicLoaderAIXDYLD::Initialize() {
+  PluginManager::RegisterPlugin(GetPluginNameStatic(),
+                                GetPluginDescriptionStatic(), CreateInstance);
+}
+
+void DynamicLoaderAIXDYLD::Terminate() {}
+
+llvm::StringRef DynamicLoaderAIXDYLD::GetPluginDescriptionStatic() {
+  return "Dynamic loader plug-in that watches for shared library "
+         "loads/unloads in AIX processes.";
+}
+
+DynamicLoader *DynamicLoaderAIXDYLD::CreateInstance(Process *process,
+                                                    bool force) {
+  bool should_create = force;
+  if (!should_create) {
+    const llvm::Triple &triple_ref =
+        process->GetTarget().GetArchitecture().GetTriple();
+    if (triple_ref.getOS() == llvm::Triple::AIX)
+      should_create = true;
+  }
+
+  if (should_create)
+    return new DynamicLoaderAIXDYLD(process);
+
+  return nullptr;
+}
+
+void DynamicLoaderAIXDYLD::OnLoadModule(lldb::ModuleSP module_sp,
+                                        const ModuleSpec module_spec,
+                                        lldb::addr_t module_addr) {
+
+  // Resolve the module unless we already have one.
+  if (!module_sp) {
+    Status error;
+    module_sp = m_process->GetTarget().GetOrCreateModule(
+        module_spec, true /* notify */, &error);
+    if (error.Fail())
+      return;
+  }
+
+  m_loaded_modules[module_sp] = module_addr;
+  UpdateLoadedSectionsCommon(module_sp, module_addr, false);
+  ModuleList module_list;
+  module_list.Append(module_sp);
+  m_process->GetTarget().ModulesDidLoad(module_list);
+}
+
+void DynamicLoaderAIXDYLD::OnUnloadModule(lldb::addr_t module_addr) {
+  Address resolved_addr;
+  if (!m_process->GetTarget().ResolveLoadAddress(module_addr, resolved_addr))
+    return;
+
+  ModuleSP module_sp = resolved_addr.GetModule();
+  if (module_sp) {
+    m_loaded_modules.erase(module_sp);
+    UnloadSectionsCommon(module_sp);
+    ModuleList module_list;
+    module_list.Append(module_sp);
+    m_process->GetTarget().ModulesDidUnload(module_list, false);
+  }
+}
+
+lldb::addr_t DynamicLoaderAIXDYLD::GetLoadAddress(ModuleSP executable) {
+  // First, see if the load address is already cached.
+  auto it = m_loaded_modules.find(executable);
+  if (it != m_loaded_modules.end() && it->second != LLDB_INVALID_ADDRESS)
+    return it->second;
+
+  lldb::addr_t load_addr = LLDB_INVALID_ADDRESS;
+
+  // Second, try to get it through the process plugins.  For a remote process,
+  // the remote platform will be responsible for providing it.
+  FileSpec file_spec(executable->GetPlatformFileSpec());
+  bool is_loaded = false;
+  Status status =
+      m_process->GetFileLoadAddress(file_spec, is_loaded, load_addr);
+  // Servers other than lldb server could respond with a bogus address.
+  if (status.Success() && is_loaded && load_addr != LLDB_INVALID_ADDRESS) {
+    m_loaded_modules[executable] = load_addr;
+    return load_addr;
+  }
+  return LLDB_INVALID_ADDRESS;
+}
+
+void DynamicLoaderAIXDYLD::DidAttach() {}
+
+void DynamicLoaderAIXDYLD::DidLaunch() {
+  Log *log = GetLog(LLDBLog::DynamicLoader);
+  LLDB_LOGF(log, "DynamicLoaderAIXDYLD::%s()", __FUNCTION__);
+
+  ModuleSP executable = GetTargetExecutable();
+  if (!executable.get())
+    return;
+
+  lldb::addr_t load_addr = GetLoadAddress(executable);
+  if (load_addr != LLDB_INVALID_ADDRESS) {
+    // Update the loaded sections so that the breakpoints can be resolved.
+    UpdateLoadedSections(executable, LLDB_INVALID_ADDRESS, load_addr, false);
+
+    ModuleList module_list;
+    module_list.Append(executable);
+    m_process->GetTarget().ModulesDidLoad(module_list);
+    auto error = m_process->LoadModules();
+    LLDB_LOG_ERROR(log, std::move(error), "failed to load modules: {0}");
+  }
+}
+
+Status DynamicLoaderAIXDYLD::CanLoadImage() { return Status(); }
+
+ThreadPlanSP DynamicLoaderAIXDYLD::GetStepThroughTrampolinePlan(Thread &thread,
+                                                                bool stop) {
+  // FIXME
+  return ThreadPlanSP();
+}
diff --git a/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h
new file mode 100644
index 00000000000000..ba690d66997366
--- /dev/null
+++ b/lldb/source/Plugins/DynamicLoader/AIX-DYLD/DynamicLoaderAIXDYLD.h
@@ -0,0 +1,53 @@
+//===-- DynamicLoaderAIXDYLD.h ------------------------------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H
+#define LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERAIXDYLD_H
+
+#include "lldb/Target/DynamicLoader.h"
+#include "lldb/lldb-forward.h"
+
+#include <map>
+
+namespace lldb_private {
+
+class DynamicLoaderAIXDYLD : public DynamicLoader {
+public:
+  DynamicLoaderAIXDYLD(Process *process);
+
+  ~DynamicLoaderAIXDYLD() override;
+
+  static void Initialize();
+  static void Terminate();
+  static llvm::StringRef GetPluginNameStatic() { return "aix-dyld"; }
+  static llvm::StringRef GetPluginDescriptionStatic();
+
+  static DynamicLoader *CreateInstance(Process *process, bool force);
+
+  void OnLoadModule(lldb::ModuleSP module_sp, const ModuleSpec module_spec,
+                    lldb::addr_t module_addr);
+  void OnUnloadModule(lldb::addr_t module_addr);
+
+  void DidAttach() override;
+  void DidLaunch() override;
+  Status CanLoadImage() override;
+  lldb::ThreadPlanSP GetStepThroughTrampolinePlan(Thread &thread,
+                                                  bool stop) override;
+
+  llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); }
+
+protected:
+  lldb::addr_t GetLoadAddress(lldb::ModuleSP executable);
+
+private:
+  std::map<lldb::ModuleSP, lldb::addr_t> m_loaded_modules;
+};
+
+} // namespace lldb_private
+
+#endif // LLDB_SOURCE_PLUGINS_DYNAMICLOADER_AIX_DYLD_DYNAMICLOADERWAIXDYLD_H
diff --git a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
index 30607159acdc08..4f3fb693faae18 100644
--- a/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
+++ b/lldb/source/Plugins/DynamicLoader/CMakeLists.txt
@@ -5,4 +5,5 @@ add_subdirectory(POSIX-DYLD)
 add_subdirectory(Static)
 add_subdirectory(Hexagon-DYLD)
 add_subdirectory(Windows-DYLD)
+add_subdirectory(AIX-DYLD)
 add_subdirectory(wasm-DYLD)

@labath
Copy link
Collaborator

labath commented Nov 12, 2024

It's very hard to review this without seeing the related code as well (who calls On(Un)loadModule and why?), and I don't think it's a high priority for review/upstreaming. You should be able to go quite a long way without a dynamic loader plugin. The first thing you need to do it get the basic functionality covered. Parsing object files, reading registers (object file and process plugins) as well as all of the changes in common code (what's up with those hacks in the DWARF parser?). I would expect the dynamic loader to be one of the last things you need to implement.

@DhruvSrivastavaX
Copy link
Contributor

DhruvSrivastavaX commented Nov 13, 2024

Hi @labath ,
I agree that we can put a hold on this one for now.
But on that note, we want to start integrating multiple plugins Parallely, but Systematically,
to make the upstreaming pick up some pace and also be in order.
Keeping that in mind, I think right now, the best candidates will be: xcoff plugin, process plugin, and host plugin.
Hope thats alright?
Please do suggest if you have something more in mind.

Can we also start PR for base setup for other plugins which come later,
just hold them for now and integrate them when the time comes?

@labath
Copy link
Collaborator

labath commented Nov 13, 2024

That sounds reasonable. Those three parts should be mostly independent. The dynamic loader plugin is tricky as it sort of binds everything together. Basically my criterion is: "can this code be useful (e.g. tested) without the functionality that is not implemented yet". If the answer is no, then we ought deal with the things that make it useful first.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants