From 9d029362d1ed48c38565aeab0ca04bf4143d3e5b Mon Sep 17 00:00:00 2001 From: =?utf8?q?Micha=C5=82=20G=C3=B3rny?= Date: Wed, 27 Jan 2021 15:34:15 +0100 Subject: [PATCH] [lldb] [Process/FreeBSDRemote] Introduce arm (32-bit) support Introduce a NativeRegisterContextFreeBSD for 32-bit ARM platform. This includes support for GPR + VFP registers as exposed by FreeBSD's ptrace(2) API. Hardware breakpoints or watchpoints are not supported due to missing kernel support. The code is roughly based on the arm64 context. It also includes an override for GetSoftwareBreakpointTrapOpcode() based on the matching code in the PlatformFreeBSD plugin. Differential Revision: https://reviews.llvm.org/D95696 --- .../Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp | 1 + .../Plugins/Process/FreeBSDRemote/CMakeLists.txt | 1 + .../Process/FreeBSDRemote/NativeProcessFreeBSD.cpp | 21 +++ .../Process/FreeBSDRemote/NativeProcessFreeBSD.h | 4 + .../NativeRegisterContextFreeBSD_arm.cpp | 202 +++++++++++++++++++++ .../NativeRegisterContextFreeBSD_arm.h | 68 +++++++ .../Process/Utility/RegisterContextFreeBSDTest.cpp | 76 ++++++++ 7 files changed, 373 insertions(+) create mode 100644 lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.cpp create mode 100644 lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.h diff --git a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp index 0c9068e..40fef59 100644 --- a/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ b/lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -254,6 +254,7 @@ bool PlatformFreeBSD::CanDebugProcess() { switch (host_triple.getArch()) { case llvm::Triple::aarch64: + case llvm::Triple::arm: case llvm::Triple::x86: case llvm::Triple::x86_64: use_legacy_plugin = !!getenv("FREEBSD_LEGACY_PLUGIN"); diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt b/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt index 2b19255..9d102be 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt +++ b/lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt @@ -1,6 +1,7 @@ add_lldb_library(lldbPluginProcessFreeBSDRemote NativeProcessFreeBSD.cpp NativeRegisterContextFreeBSD.cpp + NativeRegisterContextFreeBSD_arm.cpp NativeRegisterContextFreeBSD_arm64.cpp NativeRegisterContextFreeBSD_x86_64.cpp NativeThreadFreeBSD.cpp diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp index 163093c..139313b 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp @@ -354,6 +354,27 @@ Status NativeProcessFreeBSD::PtraceWrapper(int req, lldb::pid_t pid, void *addr, return error; } +llvm::Expected> +NativeProcessFreeBSD::GetSoftwareBreakpointTrapOpcode(size_t size_hint) { + static const uint8_t g_arm_opcode[] = {0xfe, 0xde, 0xff, 0xe7}; + static const uint8_t g_thumb_opcode[] = {0x01, 0xde}; + + switch (GetArchitecture().GetMachine()) { + case llvm::Triple::arm: + switch (size_hint) { + case 2: + return llvm::makeArrayRef(g_thumb_opcode); + case 4: + return llvm::makeArrayRef(g_arm_opcode); + default: + return llvm::createStringError(llvm::inconvertibleErrorCode(), + "Unrecognised trap opcode size hint!"); + } + default: + return NativeProcessProtocol::GetSoftwareBreakpointTrapOpcode(size_hint); + } +} + Status NativeProcessFreeBSD::Resume(const ResumeActionList &resume_actions) { Log *log(ProcessPOSIXLog::GetLogIfAllCategoriesSet(POSIX_LOG_PROCESS)); LLDB_LOG(log, "pid {0}", GetID()); diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h index 3c7a940..99123d5 100644 --- a/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h @@ -84,6 +84,10 @@ public: static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, int data = 0, int *result = nullptr); +protected: + llvm::Expected> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.cpp b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.cpp new file mode 100644 index 0000000..18926d7 --- /dev/null +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.cpp @@ -0,0 +1,202 @@ +//===-- NativeRegisterContextFreeBSD_arm.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__arm__) + +#include "NativeRegisterContextFreeBSD_arm.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +// clang-format off +#include +#include +#include +// clang-format on + +using namespace lldb; +using namespace lldb_private; +using namespace lldb_private::process_freebsd; + +NativeRegisterContextFreeBSD * +NativeRegisterContextFreeBSD::CreateHostNativeRegisterContextFreeBSD( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) { + return new NativeRegisterContextFreeBSD_arm(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_arm::NativeRegisterContextFreeBSD_arm( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterInfoPOSIX_arm(target_arch)) {} + +RegisterInfoPOSIX_arm & +NativeRegisterContextFreeBSD_arm::GetRegisterInfo() const { + return static_cast(*m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_arm::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_arm::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_arm::GetUserRegisterCount() const { + uint32_t count = 0; + for (uint32_t set_index = 0; set_index < GetRegisterSetCount(); ++set_index) + count += GetRegisterSet(set_index)->num_registers; + return count; +} + +Status NativeRegisterContextFreeBSD_arm::ReadRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_arm::WriteRegisterSet(uint32_t set) { + switch (set) { + case RegisterInfoPOSIX_arm::GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); + case RegisterInfoPOSIX_arm::FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterInfoPOSIX_arm::GPR)); + } + llvm_unreachable("NativeRegisterContextFreeBSD_arm::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_arm::ReadRegister(const RegisterInfo *reg_info, + RegisterValue ®_value) { + Status error; + + if (!reg_info) { + error.SetErrorString("reg_info NULL"); + return error; + } + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + reg_value.SetBytes(m_reg_data.data() + reg_info->byte_offset, + reg_info->byte_size, endian::InlHostByteOrder()); + return error; +} + +Status NativeRegisterContextFreeBSD_arm::WriteRegister( + const RegisterInfo *reg_info, const RegisterValue ®_value) { + Status error; + + if (!reg_info) + return Status("reg_info NULL"); + + const uint32_t reg = reg_info->kinds[lldb::eRegisterKindLLDB]; + + if (reg == LLDB_INVALID_REGNUM) + return Status("no lldb regnum for %s", reg_info && reg_info->name + ? reg_info->name + : ""); + + uint32_t set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); + error = ReadRegisterSet(set); + if (error.Fail()) + return error; + + assert(reg_info->byte_offset + reg_info->byte_size <= m_reg_data.size()); + ::memcpy(m_reg_data.data() + reg_info->byte_offset, reg_value.GetBytes(), + reg_info->byte_size); + + return WriteRegisterSet(set); +} + +Status NativeRegisterContextFreeBSD_arm::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm::GPRegSet); + if (error.Fail()) + return error; + + error = ReadRegisterSet(RegisterInfoPOSIX_arm::FPRegSet); + if (error.Fail()) + return error; + + data_sp.reset(new DataBufferHeap(m_reg_data.size(), 0)); + uint8_t *dst = data_sp->GetBytes(); + ::memcpy(dst, m_reg_data.data(), m_reg_data.size()); + + return error; +} + +Status NativeRegisterContextFreeBSD_arm::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_arm::%s data_sp contained mismatched " + "data size, expected %" PRIu64 ", actual %" PRIu64, + __FUNCTION__, m_reg_data.size(), data_sp->GetByteSize()); + return error; + } + + uint8_t *src = data_sp->GetBytes(); + if (src == nullptr) { + error.SetErrorStringWithFormat("NativeRegisterContextFreeBSD_arm::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + + error = WriteRegisterSet(RegisterInfoPOSIX_arm::GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(RegisterInfoPOSIX_arm::FPRegSet); +} + +llvm::Error NativeRegisterContextFreeBSD_arm::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__arm__) diff --git a/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.h b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.h new file mode 100644 index 0000000..106aa07 --- /dev/null +++ b/lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.h @@ -0,0 +1,68 @@ +//===-- NativeRegisterContextFreeBSD_arm.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 +// +//===----------------------------------------------------------------------===// + +#if defined(__arm__) + +#ifndef lldb_NativeRegisterContextFreeBSD_arm_h +#define lldb_NativeRegisterContextFreeBSD_arm_h + +// clang-format off +#include +#include +#include +// clang-format on + +#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +#include + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_arm : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_arm(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::DataBufferSP &data_sp) override; + + Status WriteAllRegisterValues(const lldb::DataBufferSP &data_sp) override; + + llvm::Error + CopyHardwareWatchpointsFrom(NativeRegisterContextFreeBSD &source) override; + +private: + std::array m_reg_data; + + Status ReadRegisterSet(uint32_t set); + Status WriteRegisterSet(uint32_t set); + + RegisterInfoPOSIX_arm &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_arm_h + +#endif // defined (__arm__) diff --git a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp index 083e29d..145b8b2 100644 --- a/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp +++ b/lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp @@ -9,6 +9,9 @@ // clang-format off #include #include +#if defined(__arm__) +#include +#endif // clang-format on #include "gmock/gmock.h" @@ -17,7 +20,9 @@ #include "Plugins/Process/Utility/lldb-x86-register-enums.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_x86_64.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" #include "Plugins/Process/Utility/RegisterInfoPOSIX_arm64.h" +#include "Plugins/Process/Utility/lldb-arm-register-enums.h" #include "Plugins/Process/Utility/lldb-arm64-register-enums.h" using namespace lldb; @@ -234,6 +239,77 @@ TEST(RegisterContextFreeBSDTest, i386) { #endif // defined(__i386__) || defined(__x86_64__) +#if defined(__arm__) + +#define EXPECT_GPR_ARM(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_arm), \ + ::testing::Pair(offsetof(reg, fbsd_reg), sizeof(reg::fbsd_reg))) +#define EXPECT_FPU_ARM(lldb_reg, fbsd_reg) \ + EXPECT_THAT(GetRegParams(reg_ctx, fpu_##lldb_reg##_arm), \ + ::testing::Pair(offsetof(vfp_state, fbsd_reg) + base_offset, \ + sizeof(vfp_state::fbsd_reg))) + +TEST(RegisterContextFreeBSDTest, arm) { + ArchSpec arch{"arm-unknown-freebsd"}; + RegisterInfoPOSIX_arm reg_ctx{arch}; + + EXPECT_GPR_ARM(r0, r[0]); + EXPECT_GPR_ARM(r1, r[1]); + EXPECT_GPR_ARM(r2, r[2]); + EXPECT_GPR_ARM(r3, r[3]); + EXPECT_GPR_ARM(r4, r[4]); + EXPECT_GPR_ARM(r5, r[5]); + EXPECT_GPR_ARM(r6, r[6]); + EXPECT_GPR_ARM(r7, r[7]); + EXPECT_GPR_ARM(r8, r[8]); + EXPECT_GPR_ARM(r9, r[9]); + EXPECT_GPR_ARM(r10, r[10]); + EXPECT_GPR_ARM(r11, r[11]); + EXPECT_GPR_ARM(r12, r[12]); + EXPECT_GPR_ARM(sp, r_sp); + EXPECT_GPR_ARM(lr, r_lr); + EXPECT_GPR_ARM(pc, r_pc); + EXPECT_GPR_ARM(cpsr, r_cpsr); + + size_t base_offset = reg_ctx.GetRegisterInfo()[fpu_d0_arm].byte_offset; + + EXPECT_FPU_ARM(d0, reg[0]); + EXPECT_FPU_ARM(d1, reg[1]); + EXPECT_FPU_ARM(d2, reg[2]); + EXPECT_FPU_ARM(d3, reg[3]); + EXPECT_FPU_ARM(d4, reg[4]); + EXPECT_FPU_ARM(d5, reg[5]); + EXPECT_FPU_ARM(d6, reg[6]); + EXPECT_FPU_ARM(d7, reg[7]); + EXPECT_FPU_ARM(d8, reg[8]); + EXPECT_FPU_ARM(d9, reg[9]); + EXPECT_FPU_ARM(d10, reg[10]); + EXPECT_FPU_ARM(d11, reg[11]); + EXPECT_FPU_ARM(d12, reg[12]); + EXPECT_FPU_ARM(d13, reg[13]); + EXPECT_FPU_ARM(d14, reg[14]); + EXPECT_FPU_ARM(d15, reg[15]); + EXPECT_FPU_ARM(d16, reg[16]); + EXPECT_FPU_ARM(d17, reg[17]); + EXPECT_FPU_ARM(d18, reg[18]); + EXPECT_FPU_ARM(d19, reg[19]); + EXPECT_FPU_ARM(d20, reg[20]); + EXPECT_FPU_ARM(d21, reg[21]); + EXPECT_FPU_ARM(d22, reg[22]); + EXPECT_FPU_ARM(d23, reg[23]); + EXPECT_FPU_ARM(d24, reg[24]); + EXPECT_FPU_ARM(d25, reg[25]); + EXPECT_FPU_ARM(d26, reg[26]); + EXPECT_FPU_ARM(d27, reg[27]); + EXPECT_FPU_ARM(d28, reg[28]); + EXPECT_FPU_ARM(d29, reg[29]); + EXPECT_FPU_ARM(d30, reg[30]); + EXPECT_FPU_ARM(d31, reg[31]); + EXPECT_FPU_ARM(fpscr, fpscr); +} + +#endif // defined(__arm__) + #if defined(__aarch64__) #define EXPECT_GPR_ARM64(lldb_reg, fbsd_reg) \ -- 2.7.4