mgorny created this revision. mgorny added reviewers: krytarowski, emaste, labath. Herald added subscribers: atanasyan, arichardson, sdardis. mgorny requested review of this revision.
Introduce mips64 support to match the legacy FreeBSD plugin. This includes support for software single stepping that's in most part copied from Linux. The code explicitly ignores EINVAL from PT_CLEARSTEP since this is easier to implement than checking whether hardware single-stepping were used. Similarly to the legacy plugin, the code does not support FPU registers at the moment. The support for them will be submitted separately as it requires changes to the register context shared by both plugins. https://reviews.llvm.org/D95802 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_mips64.cpp lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp 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 @@ -17,13 +17,15 @@ #include "gmock/gmock.h" #include "gtest/gtest.h" -#include "Plugins/Process/Utility/lldb-x86-register-enums.h" #include "Plugins/Process/Utility/RegisterContextFreeBSD_i386.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.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" +#include "Plugins/Process/Utility/lldb-mips-freebsd-register-enums.h" +#include "Plugins/Process/Utility/lldb-x86-register-enums.h" using namespace lldb; using namespace lldb_private; @@ -398,3 +400,61 @@ } #endif // defined(__aarch64__) + +#if defined(__mips64__) + +#define EXPECT_GPR_MIPS64(lldb_reg, fbsd_regno) \ + EXPECT_THAT(GetRegParams(reg_ctx, gpr_##lldb_reg##_mips64), \ + ::testing::Pair(offsetof(reg, r_regs[fbsd_regno]), \ + sizeof(reg::r_regs[fbsd_regno]))) + +TEST(RegisterContextFreeBSDTest, mips64) { + ArchSpec arch{"mips64-unknown-freebsd"}; + RegisterContextFreeBSD_mips64 reg_ctx{arch}; + + // we can not use aliases from <machine/regnum.h> because macros defined + // there are not namespaced and collide a lot, e.g. 'A1' + + EXPECT_GPR_MIPS64(zero, 0); + EXPECT_GPR_MIPS64(r1, 1); + EXPECT_GPR_MIPS64(r2, 2); + EXPECT_GPR_MIPS64(r3, 3); + EXPECT_GPR_MIPS64(r4, 4); + EXPECT_GPR_MIPS64(r5, 5); + EXPECT_GPR_MIPS64(r6, 6); + EXPECT_GPR_MIPS64(r7, 7); + EXPECT_GPR_MIPS64(r8, 8); + EXPECT_GPR_MIPS64(r9, 9); + EXPECT_GPR_MIPS64(r10, 10); + EXPECT_GPR_MIPS64(r11, 11); + EXPECT_GPR_MIPS64(r12, 12); + EXPECT_GPR_MIPS64(r13, 13); + EXPECT_GPR_MIPS64(r14, 14); + EXPECT_GPR_MIPS64(r15, 15); + EXPECT_GPR_MIPS64(r16, 16); + EXPECT_GPR_MIPS64(r17, 17); + EXPECT_GPR_MIPS64(r18, 18); + EXPECT_GPR_MIPS64(r19, 19); + EXPECT_GPR_MIPS64(r20, 20); + EXPECT_GPR_MIPS64(r21, 21); + EXPECT_GPR_MIPS64(r22, 22); + EXPECT_GPR_MIPS64(r23, 23); + EXPECT_GPR_MIPS64(r24, 24); + EXPECT_GPR_MIPS64(r25, 25); + EXPECT_GPR_MIPS64(r26, 26); + EXPECT_GPR_MIPS64(r27, 27); + EXPECT_GPR_MIPS64(gp, 28); + EXPECT_GPR_MIPS64(sp, 29); + EXPECT_GPR_MIPS64(r30, 30); + EXPECT_GPR_MIPS64(ra, 31); + EXPECT_GPR_MIPS64(sr, 32); + EXPECT_GPR_MIPS64(mullo, 33); + EXPECT_GPR_MIPS64(mulhi, 34); + EXPECT_GPR_MIPS64(badvaddr, 35); + EXPECT_GPR_MIPS64(cause, 36); + EXPECT_GPR_MIPS64(pc, 37); + EXPECT_GPR_MIPS64(ic, 38); + EXPECT_GPR_MIPS64(dummy, 39); +} + +#endif // defined(__mips64__) Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp +++ lldb/source/Plugins/Process/FreeBSDRemote/NativeThreadFreeBSD.cpp @@ -46,6 +46,11 @@ if (!ret.Success()) return ret; ret = NativeProcessFreeBSD::PtraceWrapper(PT_CLEARSTEP, GetID()); + // we can get EINVAL if the architecture in question does not support + // hardware single-stepping -- that's fine, we have nothing to clear + // then + if (ret.GetError() == EINVAL) + ret.Clear(); if (ret.Success()) SetRunning(); return ret; Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h =================================================================== --- /dev/null +++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.h @@ -0,0 +1,70 @@ +//===-- NativeRegisterContextFreeBSD_mips64.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(__mips64__) + +#ifndef lldb_NativeRegisterContextFreeBSD_mips64_h +#define lldb_NativeRegisterContextFreeBSD_mips64_h + +// clang-format off +#include <sys/types.h> +#include <machine/reg.h> +// clang-format on + +#include "Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD.h" +#include "Plugins/Process/Utility/RegisterContextFreeBSD_mips64.h" + +#include <array> + +namespace lldb_private { +namespace process_freebsd { + +class NativeProcessFreeBSD; + +class NativeRegisterContextFreeBSD_mips64 : public NativeRegisterContextFreeBSD { +public: + NativeRegisterContextFreeBSD_mips64(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: + enum RegSetKind { + GPRegSet, + }; + std::array<uint8_t, sizeof(reg)> m_reg_data; + + Status ReadRegisterSet(RegSetKind set); + Status WriteRegisterSet(RegSetKind set); + + RegisterContextFreeBSD_mips64 &GetRegisterInfo() const; +}; + +} // namespace process_freebsd +} // namespace lldb_private + +#endif // #ifndef lldb_NativeRegisterContextFreeBSD_mips64_h + +#endif // defined (__mips64__) Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.cpp =================================================================== --- /dev/null +++ lldb/source/Plugins/Process/FreeBSDRemote/NativeRegisterContextFreeBSD_mips64.cpp @@ -0,0 +1,219 @@ +//===-- NativeRegisterContextFreeBSD_mips64.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(__mips64__) + +#include "NativeRegisterContextFreeBSD_mips64.h" + +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/RegisterValue.h" +#include "lldb/Utility/Status.h" + +#include "Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.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_mips64(target_arch, native_thread); +} + +NativeRegisterContextFreeBSD_mips64::NativeRegisterContextFreeBSD_mips64( + const ArchSpec &target_arch, NativeThreadProtocol &native_thread) + : NativeRegisterContextRegisterInfo( + native_thread, new RegisterContextFreeBSD_mips64(target_arch)) {} + +RegisterContextFreeBSD_mips64 & +NativeRegisterContextFreeBSD_mips64::GetRegisterInfo() const { + return static_cast<RegisterContextFreeBSD_mips64 &>(*m_register_info_interface_up); +} + +uint32_t NativeRegisterContextFreeBSD_mips64::GetRegisterSetCount() const { + return GetRegisterInfo().GetRegisterSetCount(); +} + +const RegisterSet * +NativeRegisterContextFreeBSD_mips64::GetRegisterSet(uint32_t set_index) const { + return GetRegisterInfo().GetRegisterSet(set_index); +} + +uint32_t NativeRegisterContextFreeBSD_mips64::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_mips64::ReadRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_GETREGS, m_thread.GetID(), + m_reg_data.data()); +#if 0 + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_GETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterContextFreeBSD_mips64::GPR)); +#endif + } + llvm_unreachable("NativeRegisterContextFreeBSD_mips64::ReadRegisterSet"); +} + +Status NativeRegisterContextFreeBSD_mips64::WriteRegisterSet(RegSetKind set) { + switch (set) { + case GPRegSet: + return NativeProcessFreeBSD::PtraceWrapper(PT_SETREGS, m_thread.GetID(), + m_reg_data.data()); +#if 0 + case FPRegSet: + return NativeProcessFreeBSD::PtraceWrapper( + PT_SETVFPREGS, m_thread.GetID(), + m_reg_data.data() + sizeof(RegisterContextFreeBSD_mips64::GPR)); +#endif + } + llvm_unreachable("NativeRegisterContextFreeBSD_mips64::WriteRegisterSet"); +} + +Status +NativeRegisterContextFreeBSD_mips64::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>"); + +#if 0 + RegSetKind set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); +#else + RegSetKind set = GPRegSet; +#endif + 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_mips64::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>"); + +#if 0 + RegSetKind set = GetRegisterInfo().GetRegisterSetFromRegisterIndex(reg); +#else + RegSetKind set = GPRegSet; +#endif + 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_mips64::ReadAllRegisterValues( + lldb::DataBufferSP &data_sp) { + Status error; + + error = ReadRegisterSet(GPRegSet); + if (error.Fail()) + return error; + +#if 0 + error = ReadRegisterSet(FPRegSet); + if (error.Fail()) + return error; +#endif + + 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_mips64::WriteAllRegisterValues( + const lldb::DataBufferSP &data_sp) { + Status error; + + if (!data_sp) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_mips64::%s invalid data_sp provided", + __FUNCTION__); + return error; + } + + if (data_sp->GetByteSize() != m_reg_data.size()) { + error.SetErrorStringWithFormat( + "NativeRegisterContextFreeBSD_mips64::%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_mips64::%s " + "DataBuffer::GetBytes() returned a null " + "pointer", + __FUNCTION__); + return error; + } + ::memcpy(m_reg_data.data(), src, m_reg_data.size()); + +#if 1 + return WriteRegisterSet(GPRegSet); +#else + error = WriteRegisterSet(GPRegSet); + if (error.Fail()) + return error; + + return WriteRegisterSet(FPRegSet); +#endif +} + +llvm::Error NativeRegisterContextFreeBSD_mips64::CopyHardwareWatchpointsFrom( + NativeRegisterContextFreeBSD &source) { + return llvm::Error::success(); +} + +#endif // defined (__mips64__) 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,8 @@ static Status PtraceWrapper(int req, lldb::pid_t pid, void *addr = nullptr, int data = 0, int *result = nullptr); + bool SupportHardwareSingleStepping() const; + protected: llvm::Expected<llvm::ArrayRef<uint8_t>> GetSoftwareBreakpointTrapOpcode(size_t size_hint) override; @@ -94,6 +96,10 @@ LazyBool m_supports_mem_region = eLazyBoolCalculate; std::vector<std::pair<MemoryRegionInfo, FileSpec>> m_mem_region_cache; + // List of thread ids stepping with a breakpoint with the address of + // the relevan breakpoint + std::map<lldb::tid_t, lldb::addr_t> m_threads_stepping_with_breakpoint; + // Private Instance Methods NativeProcessFreeBSD(::pid_t pid, int terminal_fd, NativeDelegate &delegate, const ArchSpec &arch, MainLoop &mainloop); @@ -115,6 +121,8 @@ Status Attach(); Status SetupTrace(); Status ReinitializeThreads(); + + Status SetupSoftwareSingleStepping(NativeThreadFreeBSD &thread); }; } // namespace process_freebsd Index: lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp =================================================================== --- lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp +++ lldb/source/Plugins/Process/FreeBSDRemote/NativeProcessFreeBSD.cpp @@ -21,6 +21,7 @@ #include "lldb/Host/HostProcess.h" #include "lldb/Host/posix/ProcessLauncherPosixFork.h" #include "lldb/Target/Process.h" +#include "lldb/Utility/RegisterValue.h" #include "lldb/Utility/State.h" #include "llvm/Support/Errno.h" @@ -265,7 +266,16 @@ switch (info.pl_siginfo.si_code) { case TRAP_BRKPT: if (thread) { - thread->SetStoppedByBreakpoint(); + auto thread_info = m_threads_stepping_with_breakpoint.find(thread->GetID()); + if (thread_info != m_threads_stepping_with_breakpoint.end()) { + thread->SetStoppedByTrace(); + Status brkpt_error = RemoveBreakpoint(thread_info->second); + if (brkpt_error.Fail()) + LLDB_LOG(log, "pid = {0} remove stepping breakpoint: {1}", + thread_info->first, brkpt_error); + m_threads_stepping_with_breakpoint.erase(thread_info); + } else + thread->SetStoppedByBreakpoint(); FixupBreakpointPCAsNeeded(*thread); } SetState(StateType::eStateStopped, true); @@ -899,3 +909,170 @@ return error; } + +namespace { + +struct EmulatorBaton { + NativeProcessFreeBSD &m_process; + NativeRegisterContext &m_reg_context; + + // eRegisterKindDWARF -> RegsiterValue + std::unordered_map<uint32_t, RegisterValue> m_register_values; + + EmulatorBaton(NativeProcessFreeBSD &process, NativeRegisterContext ®_context) + : m_process(process), m_reg_context(reg_context) {} +}; + +} // anonymous namespace + +static size_t ReadMemoryCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, void *dst, size_t length) { + EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); + + size_t bytes_read; + emulator_baton->m_process.ReadMemory(addr, dst, length, bytes_read); + return bytes_read; +} + +static bool ReadRegisterCallback(EmulateInstruction *instruction, void *baton, + const RegisterInfo *reg_info, + RegisterValue ®_value) { + EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); + + auto it = emulator_baton->m_register_values.find( + reg_info->kinds[eRegisterKindDWARF]); + if (it != emulator_baton->m_register_values.end()) { + reg_value = it->second; + return true; + } + + // The emulator only fill in the dwarf regsiter numbers (and in some case the + // generic register numbers). Get the full register info from the register + // context based on the dwarf register numbers. + const RegisterInfo *full_reg_info = + emulator_baton->m_reg_context.GetRegisterInfo( + eRegisterKindDWARF, reg_info->kinds[eRegisterKindDWARF]); + + Status error = + emulator_baton->m_reg_context.ReadRegister(full_reg_info, reg_value); + if (error.Success()) + return true; + + return false; +} + +static bool WriteRegisterCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + const RegisterInfo *reg_info, + const RegisterValue ®_value) { + EmulatorBaton *emulator_baton = static_cast<EmulatorBaton *>(baton); + emulator_baton->m_register_values[reg_info->kinds[eRegisterKindDWARF]] = + reg_value; + return true; +} + +static size_t WriteMemoryCallback(EmulateInstruction *instruction, void *baton, + const EmulateInstruction::Context &context, + lldb::addr_t addr, const void *dst, + size_t length) { + return length; +} + +static lldb::addr_t ReadFlags(NativeRegisterContext ®siter_context) { + const RegisterInfo *flags_info = regsiter_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + return regsiter_context.ReadRegisterAsUnsigned(flags_info, + LLDB_INVALID_ADDRESS); +} + +Status +NativeProcessFreeBSD::SetupSoftwareSingleStepping(NativeThreadFreeBSD &thread) { + Status error; + NativeRegisterContext& register_context = thread.GetRegisterContext(); + + std::unique_ptr<EmulateInstruction> emulator_up( + EmulateInstruction::FindPlugin(m_arch, eInstructionTypePCModifying, + nullptr)); + + if (emulator_up == nullptr) + return Status("Instruction emulator not found!"); + + EmulatorBaton baton(*this, register_context); + emulator_up->SetBaton(&baton); + emulator_up->SetReadMemCallback(&ReadMemoryCallback); + emulator_up->SetReadRegCallback(&ReadRegisterCallback); + emulator_up->SetWriteMemCallback(&WriteMemoryCallback); + emulator_up->SetWriteRegCallback(&WriteRegisterCallback); + + if (!emulator_up->ReadInstruction()) + return Status("Read instruction failed!"); + + bool emulation_result = + emulator_up->EvaluateInstruction(eEmulateInstructionOptionAutoAdvancePC); + + const RegisterInfo *reg_info_pc = register_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); + const RegisterInfo *reg_info_flags = register_context.GetRegisterInfo( + eRegisterKindGeneric, LLDB_REGNUM_GENERIC_FLAGS); + + auto pc_it = + baton.m_register_values.find(reg_info_pc->kinds[eRegisterKindDWARF]); + auto flags_it = + baton.m_register_values.find(reg_info_flags->kinds[eRegisterKindDWARF]); + + lldb::addr_t next_pc; + lldb::addr_t next_flags; + if (emulation_result) { + assert(pc_it != baton.m_register_values.end() && + "Emulation was successfull but PC wasn't updated"); + next_pc = pc_it->second.GetAsUInt64(); + + if (flags_it != baton.m_register_values.end()) + next_flags = flags_it->second.GetAsUInt64(); + else + next_flags = ReadFlags(register_context); + } else if (pc_it == baton.m_register_values.end()) { + // Emulate instruction failed and it haven't changed PC. Advance PC with + // the size of the current opcode because the emulation of all + // PC modifying instruction should be successful. The failure most + // likely caused by a not supported instruction which don't modify PC. + next_pc = register_context.GetPC() + emulator_up->GetOpcode().GetByteSize(); + next_flags = ReadFlags(register_context); + } else { + // The instruction emulation failed after it modified the PC. It is an + // unknown error where we can't continue because the next instruction is + // modifying the PC but we don't know how. + return Status("Instruction emulation failed unexpectedly."); + } + + if (m_arch.GetMachine() == llvm::Triple::arm) { + if (next_flags & 0x20) { + // Thumb mode + error = SetSoftwareBreakpoint(next_pc, 2); + } else { + // Arm mode + error = SetSoftwareBreakpoint(next_pc, 4); + } + } else if (m_arch.IsMIPS() || m_arch.GetTriple().isPPC64()) + error = SetSoftwareBreakpoint(next_pc, 4); + else { + // No size hint is given for the next breakpoint + error = SetSoftwareBreakpoint(next_pc, 0); + } + + // If setting the breakpoint fails because next_pc is out of the address + // space, ignore it and let the debugee segfault. + if (error.GetError() == EIO || error.GetError() == EFAULT) { + return Status(); + } else if (error.Fail()) + return error; + + m_threads_stepping_with_breakpoint.insert({thread.GetID(), next_pc}); + + return Status(); +} + +bool NativeProcessFreeBSD::SupportHardwareSingleStepping() const { + return !m_arch.IsMIPS(); +} Index: lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt =================================================================== --- lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt +++ lldb/source/Plugins/Process/FreeBSDRemote/CMakeLists.txt @@ -3,6 +3,7 @@ NativeRegisterContextFreeBSD.cpp NativeRegisterContextFreeBSD_arm.cpp NativeRegisterContextFreeBSD_arm64.cpp + NativeRegisterContextFreeBSD_mips64.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 @@ -255,6 +255,7 @@ switch (host_triple.getArch()) { case llvm::Triple::aarch64: case llvm::Triple::arm: + case llvm::Triple::mips64: 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