| 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 |
| 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 | ||
| ) |
| 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_ |
| 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 ®_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 ®_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 *>(®set), 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 *>(®set), 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); | ||
| } |
| 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 ®_value); | ||
|
|
||
| virtual Status WriteRegisterRaw(uint32_t reg_index, | ||
| const RegisterValue ®_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 |
| 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 ®_value) override; | ||
|
|
||
| Status WriteRegister(const RegisterInfo *reg_info, | ||
| const RegisterValue ®_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__) |
| 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_ |