471 changes: 471 additions & 0 deletions lldb/source/Plugins/Platform/AIX/PlatformAIX.cpp

Large diffs are not rendered by default.

74 changes: 74 additions & 0 deletions lldb/source/Plugins/Platform/AIX/PlatformAIX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,74 @@
//===-- PlatformAIX.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_PLATFORM_AIX_PLATFORMAIX_H
#define LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H

#include "Plugins/Platform/POSIX/PlatformPOSIX.h"
#include "Plugins/TypeSystem/Clang/TypeSystemClang.h"

namespace lldb_private {
namespace platform_aix {

class PlatformAIX : public PlatformPOSIX {
public:
PlatformAIX(bool is_host);

static void Initialize();

static void Terminate();

// lldb_private::PluginInterface functions
static lldb::PlatformSP CreateInstance(bool force, const ArchSpec *arch);

static llvm::StringRef GetPluginNameStatic(bool is_host) {
return is_host ? Platform::GetHostPlatformName() : "remote-AIX";
}

static llvm::StringRef GetPluginDescriptionStatic(bool is_host);

llvm::StringRef GetPluginName() override {
return GetPluginNameStatic(IsHost());
}

// lldb_private::Platform functions
llvm::StringRef GetDescription() override {
return GetPluginDescriptionStatic(IsHost());
}

void GetStatus(Stream &strm) override;

std::vector<ArchSpec>
GetSupportedArchitectures(const ArchSpec &process_host_arch) override;

uint32_t GetResumeCountForLaunchInfo(ProcessLaunchInfo &launch_info) override;

bool CanDebugProcess() override;

void CalculateTrapHandlerSymbolNames() override;

lldb::UnwindPlanSP GetTrapHandlerUnwindPlan(const llvm::Triple &triple,
ConstString name) override;

MmapArgList GetMmapArgumentList(const ArchSpec &arch, lldb::addr_t addr,
lldb::addr_t length, unsigned prot,
unsigned flags, lldb::addr_t fd,
lldb::addr_t offset) override;

CompilerType GetSiginfoType(const llvm::Triple &triple) override;

std::vector<ArchSpec> m_supported_architectures;

private:
std::unique_ptr<TypeSystemClang> m_type_system_up;
};

} // namespace platform_AIX
} // namespace lldb_private

#endif // LLDB_SOURCE_PLUGINS_PLATFORM_AIX_PLATFORMAIX_H
1 change: 1 addition & 0 deletions lldb/source/Plugins/Platform/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -8,3 +8,4 @@ add_subdirectory(OpenBSD)
add_subdirectory(POSIX)
add_subdirectory(QemuUser)
add_subdirectory(Windows)
add_subdirectory(AIX)
19 changes: 19 additions & 0 deletions lldb/source/Plugins/Process/AIX/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
add_definitions("-D_ALL_SOURCE")

add_lldb_library(lldbPluginProcessAIX
NativeProcessAIX.cpp
NativeRegisterContextAIX.cpp
NativeRegisterContextAIX_ppc64.cpp
NativeThreadAIX.cpp

LINK_LIBS
lldbCore
lldbHost
lldbSymbol
lldbTarget
lldbUtility
lldbPluginProcessPOSIX
lldbPluginProcessUtility
LINK_COMPONENTS
Support
)
2,050 changes: 2,050 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeProcessAIX.cpp

Large diffs are not rendered by default.

283 changes: 283 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeProcessAIX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,283 @@
//===-- 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 liblldb_NativeProcessAIX_H_
#define liblldb_NativeProcessAIX_H_

#include <csignal>
#include <unordered_set>

#include "lldb/Host/Debug.h"
#include "lldb/Host/HostThread.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 "lldb/Host/aix/Support.h"

#include "NativeThreadAIX.h"
#include "lldb/Host/common/NativeProcessProtocol.h"
#include "Plugins/Process/Utility/NativeProcessSoftwareSingleStep.h"

namespace lldb_private {
class Status;
class Scalar;

namespace 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,
private NativeProcessSoftwareSingleStep {
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;

Extension GetSupportedExtensions() const 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;

// Threads (events) which haven't been claimed by any process.
llvm::DenseSet<::pid_t> m_unowned_threads;

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 GetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &range_info) 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;

llvm::Expected<lldb::addr_t> AllocateMemory(size_t size,
uint32_t permissions) override;

llvm::Error DeallocateMemory(lldb::addr_t addr) override;

Status ReadMemoryTags(int32_t type, lldb::addr_t addr, size_t len,
std::vector<uint8_t> &tags) override;

Status WriteMemoryTags(int32_t type, lldb::addr_t addr, size_t len,
const std::vector<uint8_t> &tags) 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;

void DoStopIDBumped(uint32_t newBumpId) override;

Status GetLoadedModuleFileSpec(const char *module_path,
FileSpec &file_spec) override;

Status GetFileLoadAddress(const llvm::StringRef &file_name,
lldb::addr_t &load_addr) override;

NativeThreadAIX *GetThreadByID(lldb::tid_t id);
NativeThreadAIX *GetCurrentThread();

llvm::ErrorOr<std::unique_ptr<llvm::MemoryBuffer>>
GetAuxvData() const override {
// Not available on this target.
return llvm::errc::not_supported;
}

/// Tracing
/// These methods implement the jLLDBTrace packets
/// \{
llvm::Error TraceStart(llvm::StringRef json_request,
llvm::StringRef type) override;

llvm::Error TraceStop(const TraceStopRequest &request) override;

llvm::Expected<llvm::json::Value>
TraceGetState(llvm::StringRef type) override;

llvm::Expected<std::vector<uint8_t>>
TraceGetBinaryData(const TraceGetBinaryDataRequest &request) override;

llvm::Expected<TraceSupportedResponse> TraceSupported() override;
/// }

// Interface used by NativeRegisterContext-derived classes.
static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr,
void *data = nullptr, size_t data_size = 0,
long *result = nullptr);

bool SupportHardwareSingleStepping() const;

/// Writes a siginfo_t structure corresponding to the given thread ID to the
/// memory region pointed to by \p siginfo.
int8_t GetSignalInfo(WaitStatus wstatus) const;

protected:
llvm::Expected<llvm::ArrayRef<uint8_t>>
GetSoftwareBreakpointTrapOpcode(size_t size_hint) override;

llvm::Expected<uint64_t> Syscall(llvm::ArrayRef<uint64_t> args);

private:
Manager &m_manager;
/*MainLoop::SignalHandleUP m_sigchld_handle;*/
ArchSpec m_arch;
/*MainLoop& m_main_loop;*/

LazyBool m_supports_mem_region = eLazyBoolCalculate;
std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache;

lldb::tid_t m_pending_notification_tid = LLDB_INVALID_THREAD_ID;

/// Inferior memory (allocated by us) and its size.
llvm::DenseMap<lldb::addr_t, lldb::addr_t> m_allocated_memory;

// Private Instance Methods
NativeProcessAIX(::pid_t pid, int terminal_fd, NativeDelegate &delegate,
const ArchSpec &arch, Manager &manager,
llvm::ArrayRef<::pid_t> tids);

// Returns a list of process threads that we have attached to.
static llvm::Expected<std::vector<::pid_t>> Attach(::pid_t pid);

static Status SetDefaultPtraceOpts(const lldb::pid_t);

bool TryHandleWaitStatus(lldb::pid_t pid, WaitStatus status);

void MonitorCallback(NativeThreadAIX &thread, WaitStatus status);

void MonitorSIGTRAP(const WaitStatus status, NativeThreadAIX &thread);

void MonitorTrace(NativeThreadAIX &thread);

void MonitorBreakpoint(NativeThreadAIX &thread);

void MonitorWatchpoint(NativeThreadAIX &thread, uint32_t wp_index);

void MonitorSignal(const WaitStatus status, NativeThreadAIX &thread);

bool HasThreadNoLock(lldb::tid_t thread_id);

void StopTrackingThread(NativeThreadAIX &thread);

/// Create a new thread.
///
/// If process tracing is enabled and the thread can't be traced, then the
/// thread is left stopped with a \a eStopReasonProcessorTrace status, and
/// then the process is stopped.
///
/// \param[in] resume
/// If a tracing error didn't happen, then resume the thread after
/// creation if \b true, or leave it stopped with SIGSTOP if \b false.
NativeThreadAIX &AddThread(lldb::tid_t thread_id, bool resume);

/// Start tracing a new thread if process tracing is enabled.
///
/// Trace mechanisms should modify this method to provide automatic tracing
/// for new threads.
Status NotifyTracersOfNewThread(lldb::tid_t tid);

/// Stop tracing threads upon a destroy event.
///
/// Trace mechanisms should modify this method to provide automatic trace
/// stopping for threads being destroyed.
Status NotifyTracersOfThreadDestroyed(lldb::tid_t tid);

void NotifyTracersProcessWillResume() override;

void NotifyTracersProcessDidStop() override;
/// Writes the raw event message code (vis-a-vis PTRACE_GETEVENTMSG)
/// corresponding to the given thread ID to the memory pointed to by @p
/// message.
Status GetEventMessage(lldb::tid_t tid, unsigned long *message);

void NotifyThreadDeath(lldb::tid_t tid);

Status Detach(lldb::tid_t tid);

// This method is requests a stop on all threads which are still running. It
// sets up a
// deferred delegate notification, which will fire once threads report as
// stopped. The
// triggerring_tid will be set as the current thread (main stop reason).
void StopRunningThreads(lldb::tid_t triggering_tid);

// Notify the delegate if all threads have stopped.
void SignalIfAllThreadsStopped();

// Resume the given thread, optionally passing it the given signal. The type
// of resume
// operation (continue, single-step) depends on the state parameter.
Status ResumeThread(NativeThreadAIX &thread, lldb::StateType state,
int signo);

void ThreadWasCreated(NativeThreadAIX &thread);

void SigchldHandler();

Status PopulateMemoryRegionCache();

// Handle a clone()-like event.
bool MonitorClone(NativeThreadAIX &parent, lldb::pid_t child_pid,
int event);
};

} // namespace process_aix
} // namespace lldb_private

#endif // #ifndef liblldb_NativeProcessAIX_H_
157 changes: 157 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,157 @@
//===-- NativeRegisterContextAIX.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 "NativeRegisterContextAIX.h"

#include "lldb/Host/common/NativeProcessProtocol.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/Utility/RegisterValue.h"

#include "Plugins/Process/AIX/NativeProcessAIX.h"
#include "Plugins/Process/POSIX/ProcessPOSIXLog.h"
#include "lldb/Host/aix/Ptrace.h"

using namespace lldb_private;
using namespace lldb_private::process_aix;

lldb::ByteOrder NativeRegisterContextAIX::GetByteOrder() const {
return m_thread.GetProcess().GetByteOrder();
}

Status NativeRegisterContextAIX::ReadRegisterRaw(uint32_t reg_index,
RegisterValue &reg_value) {
const RegisterInfo *const reg_info = GetRegisterInfoAtIndex(reg_index);
if (!reg_info)
return Status::FromErrorStringWithFormat("register %" PRIu32 " not found", reg_index);

return DoReadRegisterValue(GetPtraceOffset(reg_index), reg_info->name,
reg_info->byte_size, reg_value);
}

Status
NativeRegisterContextAIX::WriteRegisterRaw(uint32_t reg_index,
const RegisterValue &reg_value) {
uint32_t reg_to_write = reg_index;
RegisterValue value_to_write = reg_value;

// Check if this is a subregister of a full register.
const RegisterInfo *reg_info = GetRegisterInfoAtIndex(reg_index);
if (reg_info->invalidate_regs &&
(reg_info->invalidate_regs[0] != LLDB_INVALID_REGNUM)) {
Status error;

RegisterValue full_value;
uint32_t full_reg = reg_info->invalidate_regs[0];
const RegisterInfo *full_reg_info = GetRegisterInfoAtIndex(full_reg);

// Read the full register.
error = ReadRegister(full_reg_info, full_value);
if (error.Fail())
return error;

lldb::ByteOrder byte_order = GetByteOrder();
uint8_t dst[RegisterValue::kMaxRegisterByteSize];

// Get the bytes for the full register.
const uint32_t dest_size = full_value.GetAsMemoryData(
*full_reg_info, dst, sizeof(dst), byte_order, error);
if (error.Success() && dest_size) {
uint8_t src[RegisterValue::kMaxRegisterByteSize];

// Get the bytes for the source data.
const uint32_t src_size = reg_value.GetAsMemoryData(
*reg_info, src, sizeof(src), byte_order, error);
if (error.Success() && src_size && (src_size < dest_size)) {
// Copy the src bytes to the destination.
memcpy(dst + (reg_info->byte_offset & 0x1), src, src_size);
// Set this full register as the value to write.
value_to_write.SetBytes(dst, full_value.GetByteSize(), byte_order);
value_to_write.SetType(*full_reg_info);
reg_to_write = full_reg;
}
}
}

const RegisterInfo *const register_to_write_info_p =
GetRegisterInfoAtIndex(reg_to_write);
assert(register_to_write_info_p &&
"register to write does not have valid RegisterInfo");
if (!register_to_write_info_p)
return Status::FromErrorStringWithFormat("NativeRegisterContextAIX::%s failed to get RegisterInfo "
"for write register index %" PRIu32,
__FUNCTION__, reg_to_write);

return DoWriteRegisterValue(GetPtraceOffset(reg_index), reg_info->name,
reg_value);
}

Status NativeRegisterContextAIX::ReadGPR() {
return NativeProcessAIX::PtraceWrapper(
PTRACE_GETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize());
}

Status NativeRegisterContextAIX::WriteGPR() {
return NativeProcessAIX::PtraceWrapper(
PTRACE_SETREGS, m_thread.GetID(), nullptr, GetGPRBuffer(), GetGPRSize());
}

Status NativeRegisterContextAIX::ReadFPR() {
return NativeProcessAIX::PtraceWrapper(PTRACE_GETFPREGS, m_thread.GetID(),
nullptr, GetFPRBuffer(),
GetFPRSize());
}

Status NativeRegisterContextAIX::WriteFPR() {
return NativeProcessAIX::PtraceWrapper(PTRACE_SETFPREGS, m_thread.GetID(),
nullptr, GetFPRBuffer(),
GetFPRSize());
}

Status NativeRegisterContextAIX::ReadRegisterSet(void *buf, size_t buf_size,
unsigned int regset) {
return NativeProcessAIX::PtraceWrapper(PTRACE_GETREGSET, m_thread.GetID(),
static_cast<void *>(&regset), buf,
buf_size);
}

Status NativeRegisterContextAIX::WriteRegisterSet(void *buf, size_t buf_size,
unsigned int regset) {
return NativeProcessAIX::PtraceWrapper(PTRACE_SETREGSET, m_thread.GetID(),
static_cast<void *>(&regset), buf,
buf_size);
}

Status NativeRegisterContextAIX::DoReadRegisterValue(uint32_t offset,
const char *reg_name,
uint32_t size,
RegisterValue &value) {
Log *log = GetLog(POSIXLog::Registers);

long data;
Status error = NativeProcessAIX::PtraceWrapper(
PTRACE_PEEKUSER, m_thread.GetID(), reinterpret_cast<void *>(offset),
nullptr, 0, &data);

if (error.Success())
// First cast to an unsigned of the same size to avoid sign extension.
value.SetUInt(static_cast<unsigned long>(data), size);

LLDB_LOG(log, "{0}: {1:x}", reg_name, data);
return error;
}

Status NativeRegisterContextAIX::DoWriteRegisterValue(
uint32_t offset, const char *reg_name, const RegisterValue &value) {
Log *log = GetLog(POSIXLog::Registers);

void *buf = reinterpret_cast<void *>(value.GetAsUInt64());
LLDB_LOG(log, "{0}: {1}", reg_name, buf);

return NativeProcessAIX::PtraceWrapper(
PTRACE_POKEUSER, m_thread.GetID(), reinterpret_cast<void *>(offset), buf);
}
133 changes: 133 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
//===-- NativeRegisterContextAIX.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_NativeRegisterContextAIX_h
#define lldb_NativeRegisterContextAIX_h

#include "Plugins/Process/Utility/NativeRegisterContextRegisterInfo.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/Target/MemoryTagManager.h"
#include "llvm/Support/Error.h"

namespace lldb_private {
namespace process_aix {

class NativeThreadAIX;

class NativeRegisterContextAIX
: public virtual NativeRegisterContextRegisterInfo {
public:
// This function is implemented in the NativeRegisterContextAIX_* subclasses
// to create a new instance of the host specific NativeRegisterContextAIX.
// The implementations can't collide as only one NativeRegisterContextAIX_*
// variant should be compiled into the final executable.
static std::unique_ptr<NativeRegisterContextAIX>
CreateHostNativeRegisterContextAIX(const ArchSpec &target_arch,
NativeThreadAIX &native_thread);

// Invalidates cached values in register context data structures
virtual void InvalidateAllRegisters(){}

struct SyscallData {
/// The syscall instruction. If the architecture uses software
/// single-stepping, the instruction should also be followed by a trap to
/// ensure the process is stopped after the syscall.
llvm::ArrayRef<uint8_t> Insn;

/// Registers used for syscall arguments. The first register is used to
/// store the syscall number.
llvm::ArrayRef<uint32_t> Args;

uint32_t Result; ///< Register containing the syscall result.
};
/// Return architecture-specific data needed to make inferior syscalls, if
/// they are supported.
virtual std::optional<SyscallData> GetSyscallData() { return std::nullopt; }

struct MmapData {
// Syscall numbers can be found (e.g.) in /usr/include/asm/unistd.h for the
// relevant architecture.
unsigned SysMmap; ///< mmap syscall number.
unsigned SysMunmap; ///< munmap syscall number
};
/// Return the architecture-specific data needed to make mmap syscalls, if
/// they are supported.
virtual std::optional<MmapData> GetMmapData() { return std::nullopt; }

struct MemoryTaggingDetails {
/// Object with tag handling utilities. If the function below returns
/// a valid structure, you can assume that this pointer is valid.
std::unique_ptr<MemoryTagManager> manager;
int ptrace_read_req; /// ptrace operation number for memory tag read
int ptrace_write_req; /// ptrace operation number for memory tag write
};
/// Return architecture specific data needed to use memory tags,
/// if they are supported.
virtual llvm::Expected<MemoryTaggingDetails>
GetMemoryTaggingDetails(int32_t type) {
return llvm::createStringError(
llvm::inconvertibleErrorCode(),
"Architecture does not support memory tagging");
}

protected:
// NB: This constructor is here only because gcc<=6.5 requires a virtual base
// class initializer on abstract class (even though it is never used). It can
// be deleted once we move to gcc>=7.0.
NativeRegisterContextAIX(NativeThreadProtocol &thread)
: NativeRegisterContextRegisterInfo(thread, nullptr) {}

lldb::ByteOrder GetByteOrder() const;

virtual Status ReadRegisterRaw(uint32_t reg_index, RegisterValue &reg_value);

virtual Status WriteRegisterRaw(uint32_t reg_index,
const RegisterValue &reg_value);

virtual Status ReadRegisterSet(void *buf, size_t buf_size,
unsigned int regset);

virtual Status WriteRegisterSet(void *buf, size_t buf_size,
unsigned int regset);

virtual Status ReadGPR();

virtual Status WriteGPR();

virtual Status ReadFPR();

virtual Status WriteFPR();

virtual void *GetGPRBuffer() = 0;

virtual size_t GetGPRSize() const {
return GetRegisterInfoInterface().GetGPRSize();
}

virtual void *GetFPRBuffer() = 0;

virtual size_t GetFPRSize() = 0;

virtual uint32_t GetPtraceOffset(uint32_t reg_index) {
return GetRegisterInfoAtIndex(reg_index)->byte_offset;
}

// The Do*** functions are executed on the privileged thread and can perform
// ptrace
// operations directly.
virtual Status DoReadRegisterValue(uint32_t offset, const char *reg_name,
uint32_t size, RegisterValue &value);

virtual Status DoWriteRegisterValue(uint32_t offset, const char *reg_name,
const RegisterValue &value);
};

} // namespace process_aix
} // namespace lldb_private

#endif // #ifndef lldb_NativeRegisterContextAIX_h
744 changes: 744 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.cpp

Large diffs are not rendered by default.

138 changes: 138 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeRegisterContextAIX_ppc64.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,138 @@
//===-- NativeRegisterContextAIX_ppc64.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
//
//===----------------------------------------------------------------------===//

// This implementation is related to the OpenPOWER ABI for Power Architecture
// 64-bit ELF V2 ABI

#if defined(__powerpc64__)

#ifndef lldb_NativeRegisterContextAIX_ppc64_h
#define lldb_NativeRegisterContextAIX_ppc64_h

#include "Plugins/Process/AIX/NativeRegisterContextAIX.h"
#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"

#define DECLARE_REGISTER_INFOS_PPC64LE_STRUCT
#include "Plugins/Process/Utility/RegisterInfos_ppc64le.h"
#undef DECLARE_REGISTER_INFOS_PPC64LE_STRUCT

namespace lldb_private {
namespace process_aix {

class NativeProcessAIX;

class NativeRegisterContextAIX_ppc64 : public NativeRegisterContextAIX {
public:
NativeRegisterContextAIX_ppc64(const ArchSpec &target_arch,
NativeThreadProtocol &native_thread);

uint32_t GetRegisterSetCount() const override;

uint32_t GetUserRegisterCount() const override;

const RegisterSet *GetRegisterSet(uint32_t set_index) const override;

Status ReadRegister(const RegisterInfo *reg_info,
RegisterValue &reg_value) override;

Status WriteRegister(const RegisterInfo *reg_info,
const RegisterValue &reg_value) override;

Status ReadAllRegisterValues(lldb::WritableDataBufferSP &data_sp) override;

Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override;

// Hardware watchpoint management functions

uint32_t NumSupportedHardwareWatchpoints() override;

uint32_t SetHardwareWatchpoint(lldb::addr_t addr, size_t size,
uint32_t watch_flags) override;

bool ClearHardwareWatchpoint(uint32_t hw_index) override;

Status GetWatchpointHitIndex(uint32_t &wp_index,
lldb::addr_t trap_addr) override;

lldb::addr_t GetWatchpointHitAddress(uint32_t wp_index) override;

lldb::addr_t GetWatchpointAddress(uint32_t wp_index) override;

uint32_t GetWatchpointSize(uint32_t wp_index);

bool WatchpointIsEnabled(uint32_t wp_index);

protected:
bool IsVMX(unsigned reg);

bool IsVSX(unsigned reg);

Status ReadVMX();

Status WriteVMX();

Status ReadVSX();

Status WriteVSX();

void *GetGPRBuffer() override { return &m_gpr_ppc64le; }

void *GetFPRBuffer() override { return &m_fpr_ppc64le; }

size_t GetFPRSize() override { return sizeof(m_fpr_ppc64le); }

private:
GPR m_gpr_ppc64le; // 64-bit general purpose registers.
FPR m_fpr_ppc64le; // floating-point registers including extended register.
VMX m_vmx_ppc64le; // VMX registers.
VSX m_vsx_ppc64le; // Last lower bytes from first VSX registers.

bool IsGPR(unsigned reg) const;

bool IsFPR(unsigned reg) const;

bool IsVMX(unsigned reg) const;

bool IsVSX(unsigned reg) const;

uint32_t CalculateFprOffset(const RegisterInfo *reg_info) const;

uint32_t CalculateVmxOffset(const RegisterInfo *reg_info) const;

uint32_t CalculateVsxOffset(const RegisterInfo *reg_info) const;

Status ReadHardwareDebugInfo();

Status WriteHardwareDebugRegs();

// Debug register info for hardware watchpoints management.
struct DREG {
lldb::addr_t address; // Breakpoint/watchpoint address value.
lldb::addr_t hit_addr; // Address at which last watchpoint trigger
// exception occurred.
lldb::addr_t real_addr; // Address value that should cause target to stop.
uint32_t control; // Breakpoint/watchpoint control value.
uint32_t refcount; // Serves as enable/disable and reference counter.
long slot; // Saves the value returned from PTRACE_SETHWDEBUG.
int mode; // Defines if watchpoint is read/write/access.
};

std::array<DREG, 4> m_hwp_regs;

// 16 is just a maximum value, query hardware for actual watchpoint count
uint32_t m_max_hwp_supported = 16;
uint32_t m_max_hbp_supported = 16;
bool m_refresh_hwdebug_info = true;
};

} // namespace process_aix
} // namespace lldb_private

#endif // #ifndef lldb_NativeRegisterContextAIX_ppc64_h

#endif // defined(__powerpc64__)
526 changes: 526 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeThreadAIX.cpp

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions lldb/source/Plugins/Process/AIX/NativeThreadAIX.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
//===-- NativeThreadAIX.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 liblldb_NativeThreadAIX_H_
#define liblldb_NativeThreadAIX_H_

#include "Plugins/Process/AIX/NativeRegisterContextAIX.h"
#include "lldb/Host/common/NativeThreadProtocol.h"
#include "lldb/lldb-private-forward.h"

#include "llvm/ADT/StringRef.h"

#include <csignal>
#include <map>
#include <memory>
#include <string>

namespace lldb_private {
namespace process_aix {

class NativeProcessAIX;

class NativeThreadAIX : public NativeThreadProtocol {
friend class NativeProcessAIX;

public:
NativeThreadAIX(NativeProcessAIX &process, lldb::tid_t tid);

// NativeThreadProtocol Interface
std::string GetName() override;

lldb::StateType GetState() override;

bool GetStopReason(ThreadStopInfo &stop_info,
std::string &description) override;

NativeRegisterContextAIX &GetRegisterContext() override {
return *m_reg_context_up;
}

Status SetWatchpoint(lldb::addr_t addr, size_t size, uint32_t watch_flags,
bool hardware) override;

Status RemoveWatchpoint(lldb::addr_t addr) override;

Status SetHardwareBreakpoint(lldb::addr_t addr, size_t size) override;

Status RemoveHardwareBreakpoint(lldb::addr_t addr) override;

NativeProcessAIX &GetProcess();

const NativeProcessAIX &GetProcess() const;

llvm::Expected<std::unique_ptr<llvm::MemoryBuffer>>
GetSiginfo() const override;

private:
// Interface for friend classes

/// Resumes the thread. If \p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
Status Resume(uint32_t signo);

/// Single steps the thread. If \p signo is anything but
/// LLDB_INVALID_SIGNAL_NUMBER, deliver that signal to the thread.
Status SingleStep(uint32_t signo);

void SetStoppedBySignal(uint32_t signo, const siginfo_t *info = nullptr);

/// Return true if the thread is stopped.
/// If stopped by a signal, indicate the signo in the signo argument.
/// Otherwise, return LLDB_INVALID_SIGNAL_NUMBER.
bool IsStopped(int *signo);

void SetStoppedByExec();

void SetStoppedByBreakpoint();

void SetStoppedByWatchpoint(uint32_t wp_index);

bool IsStoppedAtBreakpoint();

bool IsStoppedAtWatchpoint();

void SetStoppedByTrace();

void SetStoppedByFork(bool is_vfork, lldb::pid_t child_pid);

void SetStoppedByVForkDone();

void SetStoppedWithNoReason();

void SetStoppedByProcessorTrace(llvm::StringRef description);

void SetExited();

Status RequestStop();

// Private interface
void MaybeLogStateChange(lldb::StateType new_state);

void SetStopped();

/// Extend m_stop_description with logical and allocation tag values.
/// If there is an error along the way just add the information we were able
/// to get.
void AnnotateSyncTagCheckFault(const siginfo_t *info);

// Member Variables
lldb::StateType m_state;
ThreadStopInfo m_stop_info;
std::unique_ptr<NativeRegisterContextAIX> m_reg_context_up;
std::string m_stop_description;
using WatchpointIndexMap = std::map<lldb::addr_t, uint32_t>;
WatchpointIndexMap m_watchpoint_index_map;
WatchpointIndexMap m_hw_break_index_map;
};
} // namespace process_aix
} // namespace lldb_private

#endif // #ifndef liblldb_NativeThreadAIX_H_
3 changes: 3 additions & 0 deletions lldb/source/Plugins/Process/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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 "Windows")
add_subdirectory(Windows/Common)
elseif (CMAKE_SYSTEM_NAME MATCHES "Darwin")
Expand Down
33 changes: 33 additions & 0 deletions lldb/source/Plugins/Process/Utility/InferiorCallPOSIX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -46,8 +46,34 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
function_options.include_inlines = false;

SymbolContextList sc_list;
#if !defined(_AIX)
process->GetTarget().GetImages().FindFunctions(
ConstString("mmap"), eFunctionNameTypeFull, function_options, sc_list);
#else
process->GetTarget().GetImages().FindFunctions(
ConstString("mmap64"), eFunctionNameTypeFull, function_options, sc_list);
SymbolContextList toc_list;
process->GetTarget().GetImages().FindSymbolsWithNameAndType(
ConstString("TOC"), lldb::eSymbolTypeAny, toc_list);

AddressRange toc_range;
if (sc_list.GetSize() > 0) {
SymbolContext sc;
if (sc_list.GetContextAtIndex(0, sc)) {
for (int i = 0; i < toc_list.GetSize(); ++i) {
SymbolContext tocSC;
if (toc_list.GetContextAtIndex(i, tocSC)) {
if (tocSC.module_sp == sc.module_sp) {
if (tocSC.GetAddressRange(eSymbolContextSymbol, 0, false,
toc_range)) {
break;
}
}
}
}
}
}
#endif
const uint32_t count = sc_list.GetSize();
if (count > 0) {
SymbolContext sc;
Expand Down Expand Up @@ -96,9 +122,16 @@ bool lldb_private::InferiorCallMmap(Process *process, addr_t &allocated_addr,
MmapArgList args =
process->GetTarget().GetPlatform()->GetMmapArgumentList(
arch, addr, length, prot_arg, flags, fd, offset);
#if defined(_AIX)
lldb::ThreadPlanSP call_plan_sp(
new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(),
toc_range.GetBaseAddress(),
void_ptr_type, args, options));
#else
lldb::ThreadPlanSP call_plan_sp(
new ThreadPlanCallFunction(*thread, mmap_range.GetBaseAddress(),
void_ptr_type, args, options));
#endif
if (call_plan_sp) {
DiagnosticManager diagnostics;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,8 @@
static const lldb_private::RegisterInfo *
GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
//HH
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
return g_register_infos_ppc64le;
default:
Expand All @@ -34,6 +36,8 @@ GetRegisterInfoPtr(const lldb_private::ArchSpec &target_arch) {
static uint32_t
GetRegisterInfoCount(const lldb_private::ArchSpec &target_arch) {
switch (target_arch.GetMachine()) {
//HitchHike
case llvm::Triple::ppc64:
case llvm::Triple::ppc64le:
return static_cast<uint32_t>(sizeof(g_register_infos_ppc64le) /
sizeof(g_register_infos_ppc64le[0]));
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ lldb_tablegen(ProcessGDBRemotePropertiesEnum.inc -gen-lldb-property-enum-defs
SOURCE ProcessGDBRemoteProperties.td
TARGET LLDBPluginProcessGDBRemotePropertiesEnumGen)

if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
remove_definitions("-D_XOPEN_SOURCE=700")
add_definitions("-D_ALL_SOURCE")
endif()

set(LLDB_PLUGINS
lldbPluginProcessUtility
)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@
#include "llvm/Config/llvm-config.h" // for LLVM_ENABLE_ZLIB
#include "llvm/Support/JSON.h"

#if defined(_AIX)
#include <sys/ldr.h>
#endif

#if defined(HAVE_LIBCOMPRESSION)
#include <compression.h>
#endif
Expand Down Expand Up @@ -1711,6 +1715,32 @@ Status GDBRemoteCommunicationClient::GetMemoryRegionInfo(
return error;
}

#if defined(_AIX)
Status GDBRemoteCommunicationClient::GetLDXINFO(struct ld_xinfo *info_ptr)
{
Status error;

char packet[64];
const int packet_len = ::snprintf(packet, sizeof(packet), "qLDXINFO");
assert(packet_len < (int)sizeof(packet));
UNUSED_IF_ASSERT_DISABLED(packet_len);
StringExtractorGDBRemote response;
if (SendPacketAndWaitForResponse(packet, response) ==
PacketResult::Success &&
response.GetResponseType() == StringExtractorGDBRemote::eResponse) {
llvm::MutableArrayRef<uint8_t> infoData((uint8_t *)info_ptr, sizeof(struct ld_xinfo)*64);
size_t got_bytes = response.GetHexBytesAvail(infoData);
if (got_bytes != sizeof(struct ld_xinfo)*64) {
error.FromErrorString("qLDXINFO ret bad size");
return error;
}
} else {
error.FromErrorString("qLDXINFO is not supported");
}
return error;
}
#endif

Status GDBRemoteCommunicationClient::GetQXferMemoryMapRegionInfo(
lldb::addr_t addr, MemoryRegionInfo &region) {
Status error = LoadQXferMemoryMap();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,10 @@

#include "llvm/Support/VersionTuple.h"

#if defined(_AIX)
struct ld_xinfo;
#endif

namespace lldb_private {
namespace process_gdb_remote {

Expand Down Expand Up @@ -196,6 +200,9 @@ class GDBRemoteCommunicationClient : public GDBRemoteClientBase {
Status GetMemoryRegionInfo(lldb::addr_t addr, MemoryRegionInfo &range_info);

std::optional<uint32_t> GetWatchpointSlotCount();
#if defined(_AIX)
Status GetLDXINFO(struct ld_xinfo *info_ptr);
#endif

std::optional<bool> GetWatchpointReportedAfter();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@
#include "ProcessGDBRemote.h"
#include "ProcessGDBRemoteLog.h"
#include "lldb/Utility/StringExtractorGDBRemote.h"
#if defined(_AIX)
#include <sys/ldr.h>
#endif

using namespace lldb;
using namespace lldb_private;
Expand Down Expand Up @@ -193,6 +196,8 @@ void GDBRemoteCommunicationServerLLGS::RegisterPacketHandlers() {
&GDBRemoteCommunicationServerLLGS::Handle_Z);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_z,
&GDBRemoteCommunicationServerLLGS::Handle_z);
RegisterMemberFunctionHandler(StringExtractorGDBRemote::eServerPacketType_qLDXINFO,
&GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO);
RegisterMemberFunctionHandler(
StringExtractorGDBRemote::eServerPacketType_QPassSignals,
&GDBRemoteCommunicationServerLLGS::Handle_QPassSignals);
Expand Down Expand Up @@ -2997,6 +3002,29 @@ GDBRemoteCommunicationServerLLGS::Handle_z(StringExtractorGDBRemote &packet) {
}
}

GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_qLDXINFO(StringExtractorGDBRemote &packet) {
if (!m_current_process ||
(m_current_process->GetID() == LLDB_INVALID_PROCESS_ID)) {
Log *log = GetLog(LLDBLog::Process);
LLDB_LOG(log, "qLDXINFO failed, no process available");
return SendErrorResponse(0xff);
}

#if defined(_AIX)
// FIXME: buffer size
struct ld_xinfo info[64];
if (ptrace64(PT_LDXINFO, m_current_process->GetID(), (long long)&(info[0]), sizeof(info), nullptr) != 0) {
return SendErrorResponse(0xff);
}
StreamGDBRemote response;
response.PutBytesAsRawHex8(&(info[0]), sizeof(info));
return SendPacketNoLock(response.GetString());
#else
return SendErrorResponse(0xff);
#endif
}

GDBRemoteCommunication::PacketResult
GDBRemoteCommunicationServerLLGS::Handle_s(StringExtractorGDBRemote &packet) {
Log *log = GetLog(LLDBLog::Process | LLDBLog::Thread);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,8 @@ class GDBRemoteCommunicationServerLLGS

PacketResult Handle_z(StringExtractorGDBRemote &packet);

PacketResult Handle_qLDXINFO(StringExtractorGDBRemote &packet);

PacketResult Handle_s(StringExtractorGDBRemote &packet);

PacketResult Handle_qXfer(StringExtractorGDBRemote &packet);
Expand Down
11 changes: 11 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,10 @@
#include "llvm/Support/Threading.h"
#include "llvm/Support/raw_ostream.h"

#if defined(_AIX)
#include <sys/ldr.h>
#endif

#define DEBUGSERVER_BASENAME "debugserver"
using namespace lldb;
using namespace lldb_private;
Expand Down Expand Up @@ -2959,6 +2963,13 @@ Status ProcessGDBRemote::DoGetMemoryRegionInfo(addr_t load_addr,
return error;
}

#if defined(_AIX)
Status ProcessGDBRemote::DoGetLDXINFO(struct ld_xinfo *info_ptr) {
Status error(m_gdb_comm.GetLDXINFO(info_ptr));
return error;
}
#endif

std::optional<uint32_t> ProcessGDBRemote::GetWatchpointSlotCount() {
return m_gdb_comm.GetWatchpointSlotCount();
}
Expand Down
8 changes: 8 additions & 0 deletions lldb/source/Plugins/Process/gdb-remote/ProcessGDBRemote.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,10 @@
#include "GDBRemoteCommunicationClient.h"
#include "GDBRemoteRegisterContext.h"

#if defined(_AIX)
struct ld_xinfo;
#endif

#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/StringMap.h"

Expand Down Expand Up @@ -423,6 +427,10 @@ class ProcessGDBRemote : public Process,
Status DoGetMemoryRegionInfo(lldb::addr_t load_addr,
MemoryRegionInfo &region_info) override;

#if defined(_AIX)
Status DoGetLDXINFO(struct ld_xinfo *info_ptr) override;
#endif

private:
// For ProcessGDBRemote only
std::string m_partial_profile_data;
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Plugins/ScriptInterpreter/Python/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,11 @@ if (LLDB_ENABLE_LIBEDIT)
endif()

add_subdirectory(Interfaces)
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
remove_definitions("-D_XOPEN_SOURCE=700")
add_definitions("-D_ALL_SOURCE")
endif()


add_lldb_library(lldbPluginScriptInterpreterPython PLUGIN
PythonDataObjects.cpp
Expand Down
4 changes: 4 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFFormValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -505,6 +505,8 @@ dw_addr_t DWARFFormValue::Address() const {
&offset, index_size);
}

bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;

std::pair<DWARFUnit *, uint64_t>
DWARFFormValue::ReferencedUnitAndOffset() const {
uint64_t value = m_value.uval;
Expand All @@ -517,6 +519,8 @@ DWARFFormValue::ReferencedUnitAndOffset() const {
assert(m_unit); // Unit must be valid for DW_FORM_ref forms that are compile
// unit relative or we will get this wrong
value += m_unit->GetOffset();
if (UGLY_FLAG_FOR_AIX)
value -= 8;
if (!m_unit->ContainsDIEOffset(value)) {
m_unit->GetSymbolFileDWARF().GetObjectFile()->GetModule()->ReportError(
"DW_FORM_ref* DIE reference {0:x16} is outside of its CU", value);
Expand Down
10 changes: 10 additions & 0 deletions lldb/source/Plugins/SymbolFile/DWARF/DWARFUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -933,6 +933,12 @@ const DWARFDebugAranges &DWARFUnit::GetFunctionAranges() {
return *m_func_aranges_up;
}

/* AIX-NOTE - TODO: Removed conflicting code due to merge conflicts
* Refer Patches: 27,28,29,30,35 and 76
* and modify the code accordingly. */

bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;

llvm::Expected<DWARFUnitSP>
DWARFUnit::extract(SymbolFileDWARF &dwarf, user_id_t uid,
const DWARFDataExtractor &debug_info,
Expand Down Expand Up @@ -1011,6 +1017,10 @@ const lldb_private::DWARFDataExtractor &DWARFUnit::GetData() const {
uint32_t DWARFUnit::GetHeaderByteSize() const {
switch (m_header.getUnitType()) {
case llvm::dwarf::DW_UT_compile:
if (UGLY_FLAG_FOR_AIX)
return 11 + 4/*GetDWARFSizeOfOffset*/;
else
return GetVersion() < 5 ? 11 : 12;
case llvm::dwarf::DW_UT_partial:
return GetVersion() < 5 ? 11 : 12;
case llvm::dwarf::DW_UT_skeleton:
Expand Down
9 changes: 9 additions & 0 deletions lldb/source/Target/ABI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,15 @@ bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
llvm_unreachable("Should never get here!");
}

bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
lldb::addr_t functionAddress,
lldb::addr_t tocAddress,
lldb::addr_t returnAddress,
llvm::ArrayRef<lldb::addr_t> args) const {
// dummy prepare trivial call
llvm_unreachable("Should never get here!");
}

bool ABI::GetFallbackRegisterLocation(
const RegisterInfo *reg_info,
UnwindPlan::Row::AbstractRegisterLocation &unwind_regloc) {
Expand Down
5 changes: 5 additions & 0 deletions lldb/source/Target/CMakeLists.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,8 @@
if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
remove_definitions("-D_XOPEN_SOURCE=700")
add_definitions("-D_ALL_SOURCE")
endif()

lldb_tablegen(TargetProperties.inc -gen-lldb-property-defs
SOURCE TargetProperties.td
TARGET LLDBTargetPropertiesGen)
Expand Down
10 changes: 10 additions & 0 deletions lldb/source/Target/Process.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,10 @@
#include "lldb/Utility/State.h"
#include "lldb/Utility/Timer.h"

#if defined(_AIX)
#include <sys/ldr.h>
#endif

using namespace lldb;
using namespace lldb_private;
using namespace std::chrono;
Expand Down Expand Up @@ -6197,6 +6201,12 @@ Status Process::GetMemoryRegionInfo(lldb::addr_t load_addr,
return error;
}

#if defined(_AIX)
Status Process::GetLDXINFO(struct ld_xinfo *info_ptr) {
return DoGetLDXINFO(info_ptr);
}
#endif

Status Process::GetMemoryRegions(lldb_private::MemoryRegionInfos &region_list) {
Status error;

Expand Down
46 changes: 46 additions & 0 deletions lldb/source/Target/RegisterContextUnwind.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,9 @@

#include <cassert>
#include <memory>
#ifdef _AIX
#include "Plugins/Process/Utility/lldb-ppc64le-register-enums.h"
#endif

using namespace lldb;
using namespace lldb_private;
Expand Down Expand Up @@ -1257,6 +1260,10 @@ bool RegisterContextUnwind::IsTrapHandlerSymbol(
// Answer the question: Where did THIS frame save the CALLER frame ("previous"
// frame)'s register value?

#ifdef _AIX
extern bool UGLY_HACK_NULL_TOPFRAME;
#endif

enum UnwindLLDB::RegisterSearchResult
RegisterContextUnwind::SavedLocationForRegister(
uint32_t lldb_regnum,
Expand Down Expand Up @@ -1518,6 +1525,11 @@ RegisterContextUnwind::SavedLocationForRegister(
new_regloc.type =
UnwindLLDB::ConcreteRegisterLocation::eRegisterInLiveRegisterContext;
new_regloc.location.register_number = regnum.GetAsKind(eRegisterKindLLDB);
#ifdef _AIX
if (UGLY_HACK_NULL_TOPFRAME && new_regloc.location.register_number == 0x20) {
new_regloc.location.register_number = 0x24;
}
#endif
m_registers[regnum.GetAsKind(eRegisterKindLLDB)] = new_regloc;
regloc = new_regloc;
UnwindLogMsg("supplying caller's register %s (%d) from the live "
Expand Down Expand Up @@ -2378,6 +2390,40 @@ bool RegisterContextUnwind::ReadPC(addr_t &pc) {
}
}

#ifdef _AIX
bool RegisterContextUnwind::ReadLR(addr_t &lr) {
if (!IsValid())
return false;

bool above_trap_handler = false;
if (GetNextFrame().get() && GetNextFrame()->IsValid() &&
GetNextFrame()->IsTrapHandlerFrame())
above_trap_handler = true;

if (ReadGPRValue(eRegisterKindLLDB, gpr_lr_ppc64le, lr)) {
// A lr value of 0 or 1 is impossible in the middle of the stack -- it
// indicates the end of a stack walk.
// On the currently executing frame (or such a frame interrupted
// asynchronously by sigtramp et al) this may occur if code has jumped
// through a NULL pointer -- we want to be able to unwind past that frame
// to help find the bug.

ProcessSP process_sp (m_thread.GetProcess());
if (process_sp)
{
ABI *abi = process_sp->GetABI().get();
if (abi)
lr = abi->FixCodeAddress(lr);
}

return !(m_all_registers_available == false &&
above_trap_handler == false && (lr == 0 || lr == 1));
} else {
return false;
}
}
#endif

void RegisterContextUnwind::UnwindLogMsg(const char *fmt, ...) {
Log *log = GetLog(LLDBLog::Unwind);
if (!log)
Expand Down
34 changes: 34 additions & 0 deletions lldb/source/Target/ThreadPlanCallFunction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,40 @@ ThreadPlanCallFunction::ThreadPlanCallFunction(
m_valid = true;
}

ThreadPlanCallFunction::ThreadPlanCallFunction(
Thread &thread, const Address &function, const Address &toc,
const CompilerType &return_type,
llvm::ArrayRef<addr_t> args, const EvaluateExpressionOptions &options)
: ThreadPlan(ThreadPlan::eKindCallFunction, "Call function plan", thread,
eVoteNoOpinion, eVoteNoOpinion),
m_valid(false), m_stop_other_threads(options.GetStopOthers()),
m_unwind_on_error(options.DoesUnwindOnError()),
m_ignore_breakpoints(options.DoesIgnoreBreakpoints()),
m_debug_execution(options.GetDebug()),
m_trap_exceptions(options.GetTrapExceptions()), m_function_addr(function),
m_function_sp(0), m_takedown_done(false),
m_should_clear_objc_exception_bp(false),
m_should_clear_cxx_exception_bp(false),
m_stop_address(LLDB_INVALID_ADDRESS), m_return_type(return_type) {
lldb::addr_t start_load_addr = LLDB_INVALID_ADDRESS;
lldb::addr_t function_load_addr = LLDB_INVALID_ADDRESS;
lldb::addr_t toc_addr = LLDB_INVALID_ADDRESS;
ABI *abi = nullptr;

if (!ConstructorSetup(thread, abi, start_load_addr, function_load_addr))
return;

toc_addr = toc.GetLoadAddress(&GetTarget());

if (!abi->PrepareTrivialCall(thread, m_function_sp, function_load_addr,
toc_addr, start_load_addr, args))
return;

ReportRegisterState("Function call was set up. Register state was:");

m_valid = true;
}

ThreadPlanCallFunction::ThreadPlanCallFunction(
Thread &thread, const Address &function,
const EvaluateExpressionOptions &options)
Expand Down
15 changes: 15 additions & 0 deletions lldb/source/Target/UnwindLLDB.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,10 @@ uint32_t UnwindLLDB::DoGetFrameCount() {
return m_frames.size();
}

#ifdef _AIX
bool UGLY_HACK_NULL_TOPFRAME = false;
#endif

bool UnwindLLDB::AddFirstFrame() {
if (m_frames.size() > 0)
return true;
Expand All @@ -91,6 +95,17 @@ bool UnwindLLDB::AddFirstFrame() {
if (!reg_ctx_sp->ReadPC(first_cursor_sp->start_pc))
goto unwind_done;

#ifdef _AIX
lldb::addr_t lr;
if (!reg_ctx_sp->ReadLR(lr))
goto unwind_done;

if (first_cursor_sp->start_pc == 0) {
first_cursor_sp->start_pc = lr;
UGLY_HACK_NULL_TOPFRAME = true;
}
#endif

// Everything checks out, so release the auto pointer value and let the
// cursor own it in its shared pointer
first_cursor_sp->reg_ctx_lldb_sp = reg_ctx_sp;
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Utility/ArchSpec.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
#include "lldb/lldb-defines.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/BinaryFormat/COFF.h"
#include "llvm/BinaryFormat/XCOFF.h"
#include "llvm/BinaryFormat/ELF.h"
#include "llvm/BinaryFormat/MachO.h"
#include "llvm/BinaryFormat/XCOFF.h"
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/Utility/StringExtractorGDBRemote.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,8 @@ StringExtractorGDBRemote::GetServerPacketType() const {
return eServerPacketType_qLaunchGDBServer;
if (PACKET_MATCHES("qLaunchSuccess"))
return eServerPacketType_qLaunchSuccess;
if (PACKET_MATCHES("qLDXINFO"))
return eServerPacketType_qLDXINFO;
break;

case 'M':
Expand Down
2 changes: 1 addition & 1 deletion lldb/test/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ if(TARGET clang)
add_lldb_test_dependency(clang)

# TestFullLtoStepping depends on LTO, and only runs when the compiler is clang.
add_lldb_test_dependency(LTO)
#add_lldb_test_dependency(LTO)

if (TARGET libcxx OR ("libcxx" IN_LIST LLVM_ENABLE_RUNTIMES))
set(LLDB_HAS_LIBCXX ON)
Expand Down
5 changes: 5 additions & 0 deletions lldb/tools/driver/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,11 @@ if(APPLE)
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,-sectcreate,__TEXT,__info_plist,${CMAKE_CURRENT_BINARY_DIR}/lldb-Info.plist")
endif()

if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
remove_definitions("-D_XOPEN_SOURCE=700")
add_definitions("-D_ALL_SOURCE")
endif()

add_lldb_tool(lldb
Driver.cpp
Platform.cpp
Expand Down
5 changes: 4 additions & 1 deletion lldb/tools/driver/Driver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -642,7 +642,7 @@ void sigwinch_handler(int signo) {
}

void sigint_handler(int signo) {
#ifdef _WIN32 // Restore handler as it is not persistent on Windows
#if defined(_WIN32) || defined(_AIX) // Restore handler as it is not persistent on Windows
signal(SIGINT, sigint_handler);
#endif
static std::atomic_flag g_interrupt_sent = ATOMIC_FLAG_INIT;
Expand Down Expand Up @@ -730,8 +730,11 @@ static void printHelp(LLDBOptTable &table, llvm::StringRef tool_name) {

int main(int argc, char const *argv[]) {
// Editline uses for example iswprint which is dependent on LC_CTYPE.
// FIXME: this caused unexpected SIGTRAP on AIX
#ifndef _AIX
std::setlocale(LC_ALL, "");
std::setlocale(LC_CTYPE, "");
#endif

// Setup LLVM signal handlers and make sure we call llvm_shutdown() on
// destruction.
Expand Down
4 changes: 4 additions & 0 deletions lldb/tools/lldb-dap/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,10 @@ if (HAVE_LIBPTHREAD)
list(APPEND extra_libs pthread)
endif ()

if (UNIX AND ${CMAKE_SYSTEM_NAME} MATCHES "AIX")
add_definitions("-D_AIX")
add_definitions("-D_ALL_SOURCE")
endif()

if(APPLE)
configure_file(
Expand Down
5 changes: 5 additions & 0 deletions lldb/tools/lldb-server/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -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()
Expand Down Expand Up @@ -55,6 +59,7 @@ add_lldb_tool(lldb-server
lldbPluginInstructionMIPS
lldbPluginInstructionMIPS64
lldbPluginInstructionRISCV
lldbPluginInstructionPPC64
${LLDB_SYSTEM_LIBS}

LINK_COMPONENTS
Expand Down
12 changes: 12 additions & 0 deletions lldb/tools/lldb-server/SystemInitializerLLGS.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,10 @@ using HostObjectFile = ObjectFileELF;
#include "Plugins/Instruction/MIPS/EmulateInstructionMIPS.h"
#endif

#if defined(_AIX)
#include "Plugins/Instruction/PPC64/EmulateInstructionPPC64.h"
#endif

#if defined(__riscv)
#define LLDB_TARGET_RISCV
#include "Plugins/Instruction/RISCV/EmulateInstructionRISCV.h"
Expand Down Expand Up @@ -78,6 +82,10 @@ llvm::Error SystemInitializerLLGS::Initialize() {
EmulateInstructionRISCV::Initialize();
#endif

#if defined(_AIX)
EmulateInstructionPPC64::Initialize();
#endif

return llvm::Error::success();
}

Expand All @@ -100,5 +108,9 @@ void SystemInitializerLLGS::Terminate() {
EmulateInstructionRISCV::Terminate();
#endif

#if defined(_AIX)
EmulateInstructionPPC64::Terminate();
#endif

SystemInitializerCommon::Terminate();
}
4 changes: 4 additions & 0 deletions lldb/tools/lldb-server/lldb-gdbserver.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,8 @@
#include "Plugins/Process/NetBSD/NativeProcessNetBSD.h"
#elif defined(_WIN32)
#include "Plugins/Process/Windows/Common/NativeProcessWindows.h"
#elif defined(_AIX)
#include "Plugins/Process/AIX/NativeProcessAIX.h"
#endif

#ifndef LLGS_PROGRAM_NAME
Expand All @@ -70,6 +72,8 @@ typedef process_freebsd::NativeProcessFreeBSD::Manager NativeProcessManager;
typedef process_netbsd::NativeProcessNetBSD::Manager NativeProcessManager;
#elif defined(_WIN32)
typedef NativeProcessWindows::Manager NativeProcessManager;
#elif defined(_AIX)
typedef process_aix::NativeProcessAIX::Manager NativeProcessManager;
#else
// Dummy implementation to make sure the code compiles
class NativeProcessManager : public NativeProcessProtocol::Manager {
Expand Down
2 changes: 1 addition & 1 deletion lldb/unittests/Host/MainLoopTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ TEST_F(MainLoopTest, TimedCallbackShortensSleep) {
EXPECT_FALSE(long_callback_called);
}

#ifdef LLVM_ON_UNIX
#if defined(LLVM_ON_UNIX) && !defined(_AIX)
TEST_F(MainLoopTest, DetectsEOF) {

PseudoTerminal term;
Expand Down
2 changes: 2 additions & 0 deletions lldb/unittests/Host/PipeTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ TEST_F(PipeTest, OpenAsReader) {
}
#endif

#if !defined(_AIX)
// This test is flaky on Windows on Arm.
#ifndef _WIN32
TEST_F(PipeTest, WriteWithTimeout) {
Expand Down Expand Up @@ -152,4 +153,5 @@ TEST_F(PipeTest, WriteWithTimeout) {
.ToError(),
llvm::Succeeded());
}
#endif
#endif /*ifndef _WIN32*/
4 changes: 4 additions & 0 deletions lldb/unittests/Host/posix/TerminalTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -94,15 +94,19 @@ TEST_F(TerminalTest, SetRaw) {
TEST_F(TerminalTest, SetBaudRate) {
struct termios terminfo;

#if (defined(_AIX) && defined(B38400)) || !defined(_AIX)
ASSERT_THAT_ERROR(m_term.SetBaudRate(38400), llvm::Succeeded());
ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B38400));
EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B38400));
#endif

#if (defined(_AIX) && defined(B115200)) || !defined(_AIX)
ASSERT_THAT_ERROR(m_term.SetBaudRate(115200), llvm::Succeeded());
ASSERT_EQ(tcgetattr(m_fd, &terminfo), 0);
EXPECT_EQ(cfgetispeed(&terminfo), static_cast<speed_t>(B115200));
EXPECT_EQ(cfgetospeed(&terminfo), static_cast<speed_t>(B115200));
#endif

// uncommon value
#if defined(B153600)
Expand Down
4 changes: 3 additions & 1 deletion llvm/include/llvm/Object/XCOFFObjectFile.h
Original file line number Diff line number Diff line change
Expand Up @@ -543,7 +543,6 @@ class XCOFFObjectFile : public ObjectFile {
template <typename T> const T *sectionHeaderTable() const;

size_t getFileHeaderSize() const;
size_t getSectionHeaderSize() const;

const XCOFFSectionHeader32 *toSection32(DataRefImpl Ref) const;
const XCOFFSectionHeader64 *toSection64(DataRefImpl Ref) const;
Expand Down Expand Up @@ -579,6 +578,9 @@ class XCOFFObjectFile : public ObjectFile {
void checkSectionAddress(uintptr_t Addr, uintptr_t TableAddr) const;

public:
size_t getSectionHeaderSize() const;
Expected<uintptr_t> getLoaderSectionAddress() const;

static constexpr uint64_t InvalidRelocOffset =
std::numeric_limits<uint64_t>::max();

Expand Down
15 changes: 13 additions & 2 deletions llvm/lib/DebugInfo/DWARF/DWARFUnit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -251,10 +251,16 @@ Expected<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const {
return DA.getRelocatedValue(ItemSize, &Offset);
}

bool UGLY_FLAG_FOR_AIX __attribute__((weak)) = false;

Error DWARFUnitHeader::extract(DWARFContext &Context,
const DWARFDataExtractor &debug_info,
uint64_t *offset_ptr,
DWARFSectionKind SectionKind) {
if (UGLY_FLAG_FOR_AIX) {
// FIXME: hack to get version
*offset_ptr += 8;
}
Offset = *offset_ptr;
Error Err = Error::success();
IndexEntry = nullptr;
Expand All @@ -267,8 +273,13 @@ Error DWARFUnitHeader::extract(DWARFContext &Context,
AbbrOffset = debug_info.getRelocatedValue(
FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
} else {
AbbrOffset = debug_info.getRelocatedValue(
FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
if (UGLY_FLAG_FOR_AIX) {
AbbrOffset = debug_info.getRelocatedValue(
8, offset_ptr, nullptr, &Err);
} else {
AbbrOffset = debug_info.getRelocatedValue(
FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
}
FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err);
// Fake a unit type based on the section type. This isn't perfect,
// but distinguishing compile and type units is generally enough.
Expand Down