mgorny created this revision. mgorny added reviewers: labath, emaste, krytarowski, clayborg. Herald added subscribers: omjavaid, kristof.beyls, arichardson. mgorny requested review of this revision.
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. https://reviews.llvm.org/D95696 Files: lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.cpp lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.h lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp
Index: lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp =================================================================== --- lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp +++ lldb/unittests/Process/Utility/RegisterContextFreeBSDTest.cpp @@ -9,6 +9,9 @@ // clang-format off #include <sys/types.h> #include <machine/reg.h> +#if defined(__arm__) +#include <machine/vfp.h> +#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 @@ #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) \ Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.h =================================================================== --- /dev/null +++ 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 <sys/types.h> +#include <machine/reg.h> +#include <machine/vfp.h> +// clang-format on + +#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterInfoPOSIX_arm.h" + +#include <array> + +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<uint8_t, sizeof(reg) + sizeof(vfp_state)> 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__) Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_arm.cpp =================================================================== --- /dev/null +++ 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 <sys/param.h> +#include <sys/ptrace.h> +#include <sys/types.h> +// 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<RegisterInfoPOSIX_arm &>(*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 + : "<unknown register>"); + + 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 + : "<unknown register>"); + + 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__) Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h =================================================================== --- lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h +++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.h @@ -84,6 +84,10 @@ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, int data = 0, int *result = nullptr); +protected: + virtual llvm::Expected<llvm::ArrayRef<uint8_t>> + GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; + private: MainLoop::SignalHandleUP m_sigchld_handle; ArchSpec m_arch; Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp +++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp @@ -354,6 +354,27 @@ return error; } +llvm::Expected<llvm::ArrayRef<uint8_t>> +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()); Index: lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt =================================================================== --- lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt +++ 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 Index: lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp =================================================================== --- lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp +++ lldb/source/Plugins/Platform/FreeBSD/PlatformFreeBSD.cpp @@ -254,6 +254,7 @@ 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");
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits