mirror of
https://github.com/llvm/llvm-project.git
synced 2025-04-14 15:46:32 +00:00
[lldb][AIX] Added base files for NativeProcess Support for AIX (#118160)
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. https://github.com/llvm/llvm-project/issues/101657 The complete changes for porting are present in this draft PR: https://github.com/llvm/llvm-project/pull/102601 Added base files for NativeProcess Support for AIX. Will be adding further support in consequent incremental PR.
This commit is contained in:
parent
11d35a0a94
commit
ec95ce358c
@ -292,7 +292,7 @@ endif()
|
||||
|
||||
# Figure out if lldb could use lldb-server. If so, then we'll
|
||||
# ensure we build lldb-server when an lldb target is being built.
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows")
|
||||
if (CMAKE_SYSTEM_NAME MATCHES "AIX|Android|Darwin|FreeBSD|Linux|NetBSD|OpenBSD|Windows")
|
||||
set(LLDB_CAN_USE_LLDB_SERVER ON)
|
||||
else()
|
||||
set(LLDB_CAN_USE_LLDB_SERVER OFF)
|
||||
|
16
lldb/source/Plugins/Process/AIX/CMakeLists.txt
Normal file
16
lldb/source/Plugins/Process/AIX/CMakeLists.txt
Normal file
@ -0,0 +1,16 @@
|
||||
add_lldb_library(lldbPluginProcessAIX
|
||||
NativeProcessAIX.cpp
|
||||
|
||||
LINK_LIBS
|
||||
lldbCore
|
||||
lldbHost
|
||||
lldbSymbol
|
||||
lldbTarget
|
||||
lldbUtility
|
||||
lldbPluginProcessPOSIX
|
||||
lldbPluginProcessUtility
|
||||
LINK_COMPONENTS
|
||||
Support
|
||||
)
|
||||
|
||||
target_compile_definitions(lldbPluginProcessAIX PRIVATE "-D_ALL_SOURCE")
|
254
lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
Normal file
254
lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
//===-- NativeProcessAIX.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 "NativeProcessAIX.h"
|
||||
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
|
||||
#include "lldb/Host/Host.h"
|
||||
#include "lldb/Host/HostInfo.h"
|
||||
#include "lldb/Host/HostProcess.h"
|
||||
#include "lldb/Host/ProcessLaunchInfo.h"
|
||||
#include "lldb/Host/posix/ProcessLauncherPosixFork.h"
|
||||
#include "lldb/Symbol/ObjectFile.h"
|
||||
#include "lldb/Utility/Log.h"
|
||||
#include "lldb/Utility/State.h"
|
||||
#include "lldb/Utility/Status.h"
|
||||
#include "llvm/Support/Errno.h"
|
||||
#include "llvm/Support/Error.h"
|
||||
#include <cerrno>
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <sstream>
|
||||
#include <string>
|
||||
#include <sys/ptrace.h>
|
||||
#include <unistd.h>
|
||||
|
||||
using namespace lldb;
|
||||
using namespace lldb_private;
|
||||
using namespace lldb_private::process_aix;
|
||||
using namespace llvm;
|
||||
|
||||
static constexpr unsigned k_ptrace_word_size = sizeof(void *);
|
||||
static_assert(sizeof(long) >= k_ptrace_word_size,
|
||||
"Size of long must be larger than ptrace word size");
|
||||
|
||||
// Simple helper function to ensure flags are enabled on the given file
|
||||
// descriptor.
|
||||
static llvm::Error SetFDFlags(int fd, int flags) {
|
||||
int status = fcntl(fd, F_GETFL);
|
||||
if (status == -1)
|
||||
return errorCodeToError(errnoAsErrorCode());
|
||||
if (fcntl(fd, F_SETFL, status | flags) == -1)
|
||||
return errorCodeToError(errnoAsErrorCode());
|
||||
return Error::success();
|
||||
}
|
||||
|
||||
NativeProcessAIX::Manager::Manager(MainLoop &mainloop)
|
||||
: NativeProcessProtocol::Manager(mainloop) {
|
||||
Status status;
|
||||
m_sigchld_handle = mainloop.RegisterSignal(
|
||||
SIGCHLD, [this](MainLoopBase &) { SigchldHandler(); }, status);
|
||||
assert(m_sigchld_handle && status.Success());
|
||||
}
|
||||
|
||||
// Public Static Methods
|
||||
|
||||
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
|
||||
NativeProcessAIX::Manager::Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate) {
|
||||
Log *log = GetLog(POSIXLog::Process);
|
||||
|
||||
Status status;
|
||||
::pid_t pid = ProcessLauncherPosixFork()
|
||||
.LaunchProcess(launch_info, status)
|
||||
.GetProcessId();
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
if (status.Fail()) {
|
||||
LLDB_LOG(log, "failed to launch process: {0}", status);
|
||||
return status.ToError();
|
||||
}
|
||||
|
||||
// Wait for the child process to trap on its call to execve.
|
||||
int wstatus = 0;
|
||||
::pid_t wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, &wstatus, 0);
|
||||
assert(wpid == pid);
|
||||
UNUSED_IF_ASSERT_DISABLED(wpid);
|
||||
if (!WIFSTOPPED(wstatus)) {
|
||||
LLDB_LOG(log, "Could not sync with inferior process: wstatus={1}",
|
||||
WaitStatus::Decode(wstatus));
|
||||
return llvm::make_error<StringError>("Could not sync with inferior process",
|
||||
llvm::inconvertibleErrorCode());
|
||||
}
|
||||
LLDB_LOG(log, "inferior started, now in stopped state");
|
||||
|
||||
return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
|
||||
pid, launch_info.GetPTY().ReleasePrimaryFileDescriptor(), native_delegate,
|
||||
HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, {pid}));
|
||||
}
|
||||
|
||||
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
|
||||
NativeProcessAIX::Manager::Attach(
|
||||
lldb::pid_t pid, NativeProcessProtocol::NativeDelegate &native_delegate) {
|
||||
Log *log = GetLog(POSIXLog::Process);
|
||||
LLDB_LOG(log, "pid = {0:x}", pid);
|
||||
|
||||
auto tids_or = NativeProcessAIX::Attach(pid);
|
||||
if (!tids_or)
|
||||
return tids_or.takeError();
|
||||
|
||||
return std::unique_ptr<NativeProcessAIX>(new NativeProcessAIX(
|
||||
pid, -1, native_delegate,
|
||||
HostInfo::GetArchitecture(HostInfo::eArchKind64), *this, *tids_or));
|
||||
}
|
||||
|
||||
lldb::addr_t NativeProcessAIX::GetSharedLibraryInfoAddress() {
|
||||
return LLDB_INVALID_ADDRESS;
|
||||
}
|
||||
|
||||
static std::optional<std::pair<lldb::pid_t, WaitStatus>> WaitPid() {
|
||||
Log *log = GetLog(POSIXLog::Process);
|
||||
|
||||
int status;
|
||||
::pid_t wait_pid =
|
||||
llvm::sys::RetryAfterSignal(-1, ::waitpid, -1, &status, WNOHANG);
|
||||
|
||||
if (wait_pid == 0)
|
||||
return std::nullopt;
|
||||
|
||||
if (wait_pid == -1) {
|
||||
Status error(errno, eErrorTypePOSIX);
|
||||
LLDB_LOG(log, "waitpid(-1, &status, _) failed: {0}", error);
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
WaitStatus wait_status = WaitStatus::Decode(status);
|
||||
|
||||
LLDB_LOG(log, "waitpid(-1, &status, _) = {0}, status = {1}", wait_pid,
|
||||
wait_status);
|
||||
return std::make_pair(wait_pid, wait_status);
|
||||
}
|
||||
|
||||
void NativeProcessAIX::Manager::SigchldHandler() {
|
||||
while (true) {
|
||||
auto wait_result = WaitPid();
|
||||
if (!wait_result)
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void NativeProcessAIX::Manager::CollectThread(::pid_t tid) {}
|
||||
|
||||
// Public Instance Methods
|
||||
|
||||
NativeProcessAIX::NativeProcessAIX(::pid_t pid, int terminal_fd,
|
||||
NativeDelegate &delegate,
|
||||
const ArchSpec &arch, Manager &manager,
|
||||
llvm::ArrayRef<::pid_t> tids)
|
||||
: NativeProcessProtocol(pid, terminal_fd, delegate), m_manager(manager),
|
||||
m_arch(arch) {
|
||||
manager.AddProcess(*this);
|
||||
if (m_terminal_fd != -1)
|
||||
cantFail(SetFDFlags(m_terminal_fd, O_NONBLOCK));
|
||||
|
||||
// Let our process instance know the thread has stopped.
|
||||
SetCurrentThreadID(tids[0]);
|
||||
SetState(StateType::eStateStopped, false);
|
||||
}
|
||||
|
||||
llvm::Expected<std::vector<::pid_t>> NativeProcessAIX::Attach(::pid_t pid) {
|
||||
Log *log = GetLog(POSIXLog::Process);
|
||||
Status status;
|
||||
if (llvm::Error err = PtraceWrapper(PT_ATTACH, pid).takeError())
|
||||
return err;
|
||||
|
||||
int wpid = llvm::sys::RetryAfterSignal(-1, ::waitpid, pid, nullptr, WNOHANG);
|
||||
if (wpid <= 0)
|
||||
return llvm::errorCodeToError(errnoAsErrorCode());
|
||||
LLDB_LOG(log, "adding pid = {0}", pid);
|
||||
|
||||
return std::vector<::pid_t>{pid};
|
||||
}
|
||||
|
||||
bool NativeProcessAIX::SupportHardwareSingleStepping() const { return false; }
|
||||
|
||||
Status NativeProcessAIX::Resume(const ResumeActionList &resume_actions) {
|
||||
return Status("unsupported");
|
||||
}
|
||||
|
||||
Status NativeProcessAIX::Halt() { return Status("unsupported"); }
|
||||
|
||||
Status NativeProcessAIX::Detach() { return Status("unsupported"); }
|
||||
|
||||
Status NativeProcessAIX::Signal(int signo) { return Status("unsupported"); }
|
||||
|
||||
Status NativeProcessAIX::Interrupt() { return Status("unsupported"); }
|
||||
|
||||
Status NativeProcessAIX::Kill() { return Status("unsupported"); }
|
||||
|
||||
Status NativeProcessAIX::ReadMemory(lldb::addr_t addr, void *buf, size_t size,
|
||||
size_t &bytes_read) {
|
||||
return Status("unsupported");
|
||||
}
|
||||
|
||||
Status NativeProcessAIX::WriteMemory(lldb::addr_t addr, const void *buf,
|
||||
size_t size, size_t &bytes_written) {
|
||||
return Status("unsupported");
|
||||
}
|
||||
|
||||
size_t NativeProcessAIX::UpdateThreads() {
|
||||
// The NativeProcessAIX monitoring threads are always up to date with
|
||||
// respect to thread state and they keep the thread list populated properly.
|
||||
// All this method needs to do is return the thread count.
|
||||
return m_threads.size();
|
||||
}
|
||||
|
||||
Status NativeProcessAIX::GetLoadedModuleFileSpec(const char *module_path,
|
||||
FileSpec &file_spec) {
|
||||
return Status("unsupported");
|
||||
}
|
||||
|
||||
Status NativeProcessAIX::SetBreakpoint(lldb::addr_t addr, uint32_t size,
|
||||
bool hardware) {
|
||||
if (hardware)
|
||||
return SetHardwareBreakpoint(addr, size);
|
||||
return SetSoftwareBreakpoint(addr, size);
|
||||
}
|
||||
|
||||
Status NativeProcessAIX::RemoveBreakpoint(lldb::addr_t addr, bool hardware) {
|
||||
if (hardware)
|
||||
return RemoveHardwareBreakpoint(addr);
|
||||
return NativeProcessProtocol::RemoveBreakpoint(addr);
|
||||
}
|
||||
|
||||
llvm::Error NativeProcessAIX::Detach(lldb::tid_t tid) {
|
||||
return PtraceWrapper(PT_DETACH, tid).takeError();
|
||||
}
|
||||
|
||||
llvm::Expected<int> NativeProcessAIX::PtraceWrapper(int req, lldb::pid_t pid,
|
||||
void *addr, void *data,
|
||||
size_t data_size) {
|
||||
int ret;
|
||||
|
||||
Log *log = GetLog(POSIXLog::Ptrace);
|
||||
switch (req) {
|
||||
case PT_ATTACH:
|
||||
case PT_DETACH:
|
||||
ret = ptrace64(req, pid, 0, 0, nullptr);
|
||||
break;
|
||||
default:
|
||||
llvm_unreachable("PT_ request not supported yet.");
|
||||
}
|
||||
|
||||
LLDB_LOG(log, "ptrace({0}, {1}, {2}, {3}, {4})={5:x}", req, pid, addr, data,
|
||||
data_size, ret);
|
||||
|
||||
if (ret == -1) {
|
||||
LLDB_LOG(log, "ptrace() failed");
|
||||
return llvm::errorCodeToError(errnoAsErrorCode());
|
||||
}
|
||||
return ret;
|
||||
}
|
134
lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
Normal file
134
lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
Normal file
@ -0,0 +1,134 @@
|
||||
//===-- NativeProcessAIX.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_PROCESS_AIX_NATIVEPROCESSAIX_H
|
||||
#define LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVEPROCESSAIX_H
|
||||
|
||||
#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"
|
||||
#include "lldb/Host/Debug.h"
|
||||
#include "lldb/Host/common/NativeProcessProtocol.h"
|
||||
#include "lldb/Host/linux/Support.h"
|
||||
#include "lldb/Target/MemoryRegionInfo.h"
|
||||
#include "lldb/Utility/ArchSpec.h"
|
||||
#include "lldb/Utility/FileSpec.h"
|
||||
#include "lldb/lldb-types.h"
|
||||
#include "llvm/ADT/SmallPtrSet.h"
|
||||
#include <csignal>
|
||||
#include <unordered_set>
|
||||
|
||||
namespace lldb_private::process_aix {
|
||||
/// \class NativeProcessAIX
|
||||
/// Manages communication with the inferior (debugee) process.
|
||||
///
|
||||
/// Upon construction, this class prepares and launches an inferior process
|
||||
/// for debugging.
|
||||
///
|
||||
/// Changes in the inferior process state are broadcasted.
|
||||
class NativeProcessAIX : public NativeProcessProtocol {
|
||||
public:
|
||||
class Manager : public NativeProcessProtocol::Manager {
|
||||
public:
|
||||
Manager(MainLoop &mainloop);
|
||||
|
||||
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
|
||||
Launch(ProcessLaunchInfo &launch_info,
|
||||
NativeDelegate &native_delegate) override;
|
||||
|
||||
llvm::Expected<std::unique_ptr<NativeProcessProtocol>>
|
||||
Attach(lldb::pid_t pid, NativeDelegate &native_delegate) override;
|
||||
|
||||
void AddProcess(NativeProcessAIX &process) { m_processes.insert(&process); }
|
||||
|
||||
void RemoveProcess(NativeProcessAIX &process) {
|
||||
m_processes.erase(&process);
|
||||
}
|
||||
|
||||
// Collect an event for the given tid, waiting for it if necessary.
|
||||
void CollectThread(::pid_t tid);
|
||||
|
||||
private:
|
||||
MainLoop::SignalHandleUP m_sigchld_handle;
|
||||
|
||||
llvm::SmallPtrSet<NativeProcessAIX *, 2> m_processes;
|
||||
|
||||
void SigchldHandler();
|
||||
};
|
||||
|
||||
// NativeProcessProtocol Interface
|
||||
|
||||
~NativeProcessAIX() override { m_manager.RemoveProcess(*this); }
|
||||
|
||||
Status Resume(const ResumeActionList &resume_actions) override;
|
||||
|
||||
Status Halt() override;
|
||||
|
||||
Status Detach() override;
|
||||
|
||||
Status Signal(int signo) override;
|
||||
|
||||
Status Interrupt() override;
|
||||
|
||||
Status Kill() override;
|
||||
|
||||
lldb::addr_t GetSharedLibraryInfoAddress() override;
|
||||
|
||||
Status ReadMemory(lldb::addr_t addr, void *buf, size_t size,
|
||||
size_t &bytes_read) override;
|
||||
|
||||
Status WriteMemory(lldb::addr_t addr, const void *buf, size_t size,
|
||||
size_t &bytes_written) override;
|
||||
|
||||
size_t UpdateThreads() override;
|
||||
|
||||
const ArchSpec &GetArchitecture() const override { return m_arch; }
|
||||
|
||||
Status SetBreakpoint(lldb::addr_t addr, uint32_t size,
|
||||
bool hardware) override;
|
||||
|
||||
Status RemoveBreakpoint(lldb::addr_t addr, bool hardware = false) override;
|
||||
|
||||
Status GetLoadedModuleFileSpec(const char *module_path,
|
||||
FileSpec &file_spec) override;
|
||||
|
||||
llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
|
||||
GetAuxvData() const override {
|
||||
return getProcFile(GetID(), "auxv");
|
||||
}
|
||||
|
||||
Status GetFileLoadAddress(const llvm::StringRef &file_name,
|
||||
lldb::addr_t &load_addr) override;
|
||||
|
||||
static llvm::Expected<int> PtraceWrapper(int req, lldb::pid_t pid,
|
||||
void *addr = nullptr,
|
||||
void *data = nullptr,
|
||||
size_t data_size = 0);
|
||||
|
||||
bool SupportHardwareSingleStepping() const;
|
||||
|
||||
private:
|
||||
Manager &m_manager;
|
||||
ArchSpec m_arch;
|
||||
|
||||
// Private Instance Methods
|
||||
NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
|
||||
const ArchSpec &arch, Manager &manager,
|
||||
llvm::ArrayRef<::pid_t> tids);
|
||||
|
||||
bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status);
|
||||
|
||||
// Returns a list of process threads that we have attached to.
|
||||
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);
|
||||
|
||||
llvm::Error Detach(lldb::tid_t tid);
|
||||
|
||||
void SigchldHandler();
|
||||
};
|
||||
|
||||
} // namespace lldb_private::process_aix
|
||||
|
||||
#endif // #ifndef LLDB_SOURCE_PLUGINS_PROCESS_AIX_NATIVEPROCESSAIX_H
|
@ -7,6 +7,9 @@ elseif (CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "NetBSD")
|
||||
add_subdirectory(NetBSD)
|
||||
add_subdirectory(POSIX)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "AIX")
|
||||
add_subdirectory(AIX)
|
||||
add_subdirectory(POSIX)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "OpenBSD")
|
||||
add_subdirectory(POSIX)
|
||||
elseif (CMAKE_SYSTEM_NAME MATCHES "Windows")
|
||||
|
@ -8,6 +8,10 @@ if(CMAKE_SYSTEM_NAME MATCHES "Linux|Android")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessLinux)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "AIX")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessAIX)
|
||||
endif()
|
||||
|
||||
if(CMAKE_SYSTEM_NAME MATCHES "FreeBSD")
|
||||
list(APPEND LLDB_PLUGINS lldbPluginProcessFreeBSD)
|
||||
endif()
|
||||
|
Loading…
x
Reference in New Issue
Block a user