diff options
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Architecture')
8 files changed, 748 insertions, 0 deletions
diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp new file mode 100644 index 000000000000..181ba4e7d877 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp @@ -0,0 +1,124 @@ +//===-- ArchitectureAArch64.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 "Plugins/Architecture/AArch64/ArchitectureAArch64.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/DataBufferHeap.h" +#include "lldb/Utility/DataExtractor.h" + +using namespace lldb_private; +using namespace lldb; + +LLDB_PLUGIN_DEFINE(ArchitectureAArch64) + +void ArchitectureAArch64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "AArch64-specific algorithms", + &ArchitectureAArch64::Create); +} + +void ArchitectureAArch64::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureAArch64::Create); +} + +std::unique_ptr<Architecture> +ArchitectureAArch64::Create(const ArchSpec &arch) { + auto machine = arch.GetMachine(); + if (machine != llvm::Triple::aarch64 && machine != llvm::Triple::aarch64_be && + machine != llvm::Triple::aarch64_32) { + return nullptr; + } + return std::unique_ptr<Architecture>(new ArchitectureAArch64()); +} + +static void +UpdateARM64SVERegistersInfos(DynamicRegisterInfo::reg_collection_range regs, + uint64_t vg) { + // SVE Z register size is vg x 8 bytes. + uint32_t z_reg_byte_size = vg * 8; + + // SVE vector length has changed, accordingly set size of Z, P and FFR + // registers. Also invalidate register offsets it will be recalculated + // after SVE register size update. + for (auto ® : regs) { + if (reg.value_regs == nullptr) { + if (reg.name[0] == 'z' && isdigit(reg.name[1])) + reg.byte_size = z_reg_byte_size; + else if (reg.name[0] == 'p' && isdigit(reg.name[1])) + reg.byte_size = vg; + else if (strcmp(reg.name, "ffr") == 0) + reg.byte_size = vg; + } + reg.byte_offset = LLDB_INVALID_INDEX32; + } +} + +static void +UpdateARM64SMERegistersInfos(DynamicRegisterInfo::reg_collection_range regs, + uint64_t svg) { + for (auto ® : regs) { + if (strcmp(reg.name, "za") == 0) { + // ZA is a register with size (svg*8) * (svg*8). A square essentially. + reg.byte_size = (svg * 8) * (svg * 8); + } + reg.byte_offset = LLDB_INVALID_INDEX32; + } +} + +bool ArchitectureAArch64::ReconfigureRegisterInfo(DynamicRegisterInfo ®_info, + DataExtractor ®_data, + RegisterContext ®_context + +) const { + // Once we start to reconfigure registers, we cannot read any of them. + // So we must read VG and SVG up front. + + const uint64_t fail_value = LLDB_INVALID_ADDRESS; + std::optional<uint64_t> vg_reg_value; + const RegisterInfo *vg_reg_info = reg_info.GetRegisterInfo("vg"); + if (vg_reg_info) { + uint32_t vg_reg_num = vg_reg_info->kinds[eRegisterKindLLDB]; + uint64_t reg_value = + reg_context.ReadRegisterAsUnsigned(vg_reg_num, fail_value); + if (reg_value != fail_value && reg_value <= 32) + vg_reg_value = reg_value; + } + + std::optional<uint64_t> svg_reg_value; + const RegisterInfo *svg_reg_info = reg_info.GetRegisterInfo("svg"); + if (svg_reg_info) { + uint32_t svg_reg_num = svg_reg_info->kinds[eRegisterKindLLDB]; + uint64_t reg_value = + reg_context.ReadRegisterAsUnsigned(svg_reg_num, fail_value); + if (reg_value != fail_value && reg_value <= 32) + svg_reg_value = reg_value; + } + + if (!vg_reg_value && !svg_reg_value) + return false; + + auto regs = reg_info.registers<DynamicRegisterInfo::reg_collection_range>(); + if (vg_reg_value) + UpdateARM64SVERegistersInfos(regs, *vg_reg_value); + if (svg_reg_value) + UpdateARM64SMERegistersInfos(regs, *svg_reg_value); + + // At this point if we have updated any registers, their offsets will all be + // invalid. If we did, we need to update them all. + reg_info.ConfigureOffsets(); + // From here we are able to read registers again. + + // Make a heap based buffer that is big enough to store all registers + reg_data.SetData( + std::make_shared<DataBufferHeap>(reg_info.GetRegisterDataByteSize(), 0)); + reg_data.SetByteOrder(reg_context.GetByteOrder()); + + return true; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h new file mode 100644 index 000000000000..ba409428c951 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h @@ -0,0 +1,50 @@ +//===-- ArchitectureAArch64.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_ARCHITECTURE_AARCH64_ARCHITECTUREAARCH64_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_AARCH64_ARCHITECTUREAARCH64_H + +#include "Plugins/Process/Utility/MemoryTagManagerAArch64MTE.h" +#include "lldb/Core/Architecture.h" + +namespace lldb_private { + +class ArchitectureAArch64 : public Architecture { +public: + static llvm::StringRef GetPluginNameStatic() { return "aarch64"; } + static void Initialize(); + static void Terminate(); + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + void OverrideStopInfo(Thread &thread) const override {} + + const MemoryTagManager *GetMemoryTagManager() const override { + return &m_memory_tag_manager; + } + + bool + RegisterWriteCausesReconfigure(const llvm::StringRef name) const override { + // lldb treats svg as read only, so only vg can be written. This results in + // the SVE registers changing size. + return name == "vg"; + } + + bool ReconfigureRegisterInfo(DynamicRegisterInfo ®_info, + DataExtractor ®_data, + RegisterContext ®_context) const override; + +private: + static std::unique_ptr<Architecture> Create(const ArchSpec &arch); + ArchitectureAArch64() = default; + MemoryTagManagerAArch64MTE m_memory_tag_manager; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_AARCH64_ARCHITECTUREAARCH64_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp b/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp new file mode 100644 index 000000000000..81c72122cb7e --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -0,0 +1,152 @@ +//===-- ArchitectureArm.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 "Plugins/Architecture/Arm/ArchitectureArm.h" +#include "Plugins/Process/Utility/ARMDefines.h" +#include "Plugins/Process/Utility/InstructionUtils.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ArchSpec.h" + +using namespace lldb_private; +using namespace lldb; + +LLDB_PLUGIN_DEFINE(ArchitectureArm) + +void ArchitectureArm::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Arm-specific algorithms", + &ArchitectureArm::Create); +} + +void ArchitectureArm::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureArm::Create); +} + +std::unique_ptr<Architecture> ArchitectureArm::Create(const ArchSpec &arch) { + if (arch.GetMachine() != llvm::Triple::arm) + return nullptr; + return std::unique_ptr<Architecture>(new ArchitectureArm()); +} + +void ArchitectureArm::OverrideStopInfo(Thread &thread) const { + // We need to check if we are stopped in Thumb mode in a IT instruction and + // detect if the condition doesn't pass. If this is the case it means we + // won't actually execute this instruction. If this happens we need to clear + // the stop reason to no thread plans think we are stopped for a reason and + // the plans should keep going. + // + // We do this because when single stepping many ARM processes, debuggers + // often use the BVR/BCR registers that says "stop when the PC is not equal + // to its current value". This method of stepping means we can end up + // stopping on instructions inside an if/then block that wouldn't get + // executed. By fixing this we can stop the debugger from seeming like you + // stepped through both the "if" _and_ the "else" clause when source level + // stepping because the debugger stops regardless due to the BVR/BCR + // triggering a stop. + // + // It also means we can set breakpoints on instructions inside an if/then + // block and correctly skip them if we use the BKPT instruction. The ARM and + // Thumb BKPT instructions are unconditional even when executed in a Thumb IT + // block. + // + // If your debugger inserts software traps in ARM/Thumb code, it will need to + // use 16 and 32 bit instruction for 16 and 32 bit thumb instructions + // respectively. If your debugger inserts a 16 bit thumb trap on top of a 32 + // bit thumb instruction for an opcode that is inside an if/then, it will + // change the it/then to conditionally execute your + // 16 bit trap and then cause your program to crash if it executes the + // trailing 16 bits (the second half of the 32 bit thumb instruction you + // partially overwrote). + + RegisterContextSP reg_ctx_sp(thread.GetRegisterContext()); + if (!reg_ctx_sp) + return; + + const uint32_t cpsr = reg_ctx_sp->GetFlags(0); + if (cpsr == 0) + return; + + // Read the J and T bits to get the ISETSTATE + const uint32_t J = Bit32(cpsr, 24); + const uint32_t T = Bit32(cpsr, 5); + const uint32_t ISETSTATE = J << 1 | T; + if (ISETSTATE == 0) { +// NOTE: I am pretty sure we want to enable the code below +// that detects when we stop on an instruction in ARM mode that is conditional +// and the condition doesn't pass. This can happen if you set a breakpoint on +// an instruction that is conditional. We currently will _always_ stop on the +// instruction which is bad. You can also run into this while single stepping +// and you could appear to run code in the "if" and in the "else" clause +// because it would stop at all of the conditional instructions in both. In +// such cases, we really don't want to stop at this location. +// I will check with the lldb-dev list first before I enable this. +#if 0 + // ARM mode: check for condition on instruction + const addr_t pc = reg_ctx_sp->GetPC(); + Status error; + // If we fail to read the opcode we will get UINT64_MAX as the result in + // "opcode" which we can use to detect if we read a valid opcode. + const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error); + if (opcode <= UINT32_MAX) + { + const uint32_t condition = Bits32((uint32_t)opcode, 31, 28); + if (!ARMConditionPassed(condition, cpsr)) + { + // We ARE stopped on an ARM instruction whose condition doesn't + // pass so this instruction won't get executed. Regardless of why + // it stopped, we need to clear the stop info + thread.SetStopInfo (StopInfoSP()); + } + } +#endif + } else if (ISETSTATE == 1) { + // Thumb mode + const uint32_t ITSTATE = Bits32(cpsr, 15, 10) << 2 | Bits32(cpsr, 26, 25); + if (ITSTATE != 0) { + const uint32_t condition = Bits32(ITSTATE, 7, 4); + if (!ARMConditionPassed(condition, cpsr)) { + // We ARE stopped in a Thumb IT instruction on an instruction whose + // condition doesn't pass so this instruction won't get executed. + // Regardless of why it stopped, we need to clear the stop info + thread.SetStopInfo(StopInfoSP()); + } + } + } +} + +addr_t ArchitectureArm::GetCallableLoadAddress(addr_t code_addr, + AddressClass addr_class) const { + bool is_alternate_isa = false; + + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + is_alternate_isa = true; + break; + default: break; + } + + if ((code_addr & 2u) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } + return opcode_addr & ~(1ull); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h b/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h new file mode 100644 index 000000000000..f579d6b62505 --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h @@ -0,0 +1,39 @@ +//===-- ArchitectureArm.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_ARCHITECTURE_ARM_ARCHITECTUREARM_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_ARM_ARCHITECTUREARM_H + +#include "lldb/Core/Architecture.h" + +namespace lldb_private { + +class ArchitectureArm : public Architecture { +public: + static llvm::StringRef GetPluginNameStatic() { return "arm"; } + static void Initialize(); + static void Terminate(); + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + void OverrideStopInfo(Thread &thread) const override; + + lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + + lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + +private: + static std::unique_ptr<Architecture> Create(const ArchSpec &arch); + ArchitectureArm() = default; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_ARM_ARCHITECTUREARM_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp b/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp new file mode 100644 index 000000000000..a9f2e7af601d --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -0,0 +1,232 @@ +//===-- ArchitectureMips.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 "Plugins/Architecture/Mips/ArchitectureMips.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/LLDBLog.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; +using namespace lldb; + +LLDB_PLUGIN_DEFINE(ArchitectureMips) + +void ArchitectureMips::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Mips-specific algorithms", + &ArchitectureMips::Create); +} + +void ArchitectureMips::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureMips::Create); +} + +std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) { + return arch.IsMIPS() ? + std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr; +} + +addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr, + AddressClass addr_class) const { + bool is_alternate_isa = false; + + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + is_alternate_isa = true; + break; + default: break; + } + + if ((code_addr & 2ull) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr, + AddressClass addr_class) const { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } + return opcode_addr & ~(1ull); +} + +lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr, + Target &target) const { + + Log *log = GetLog(LLDBLog::Breakpoints); + + Address resolved_addr; + + SectionLoadList §ion_load_list = target.GetSectionLoadList(); + if (section_load_list.IsEmpty()) + // No sections are loaded, so we must assume we are not running yet and + // need to operate only on file address. + target.ResolveFileAddress(addr, resolved_addr); + else + target.ResolveLoadAddress(addr, resolved_addr); + + addr_t current_offset = 0; + + // Get the function boundaries to make sure we don't scan back before the + // beginning of the current function. + ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); + if (temp_addr_module_sp) { + SymbolContext sc; + SymbolContextItem resolve_scope = + eSymbolContextFunction | eSymbolContextSymbol; + temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, + resolve_scope, sc); + Address sym_addr; + if (sc.function) + sym_addr = sc.function->GetAddressRange().GetBaseAddress(); + else if (sc.symbol) + sym_addr = sc.symbol->GetAddress(); + + addr_t function_start = sym_addr.GetLoadAddress(&target); + if (function_start == LLDB_INVALID_ADDRESS) + function_start = sym_addr.GetFileAddress(); + + if (function_start) + current_offset = addr - function_start; + } + + // If breakpoint address is start of function then we dont have to do + // anything. + if (current_offset == 0) + return addr; + + auto insn = GetInstructionAtAddress(target, current_offset, addr); + + if (nullptr == insn || !insn->HasDelaySlot()) + return addr; + + // Adjust the breakable address + uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize(); + LLDB_LOGF(log, + "Target::%s Breakpoint at 0x%8.8" PRIx64 + " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", + __FUNCTION__, addr, breakable_addr); + + return breakable_addr; +} + +Instruction *ArchitectureMips::GetInstructionAtAddress( + Target &target, const Address &resolved_addr, addr_t symbol_offset) const { + + auto loop_count = symbol_offset / 2; + + uint32_t arch_flags = m_arch.GetFlags(); + bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; + bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; + + if (loop_count > 3) { + // Scan previous 6 bytes + if (IsMips16 | IsMicromips) + loop_count = 3; + // For mips-only, instructions are always 4 bytes, so scan previous 4 + // bytes only. + else + loop_count = 2; + } + + // Create Disassembler Instance + lldb::DisassemblerSP disasm_sp( + Disassembler::FindPlugin(m_arch, nullptr, nullptr)); + + InstructionList instruction_list; + InstructionSP prev_insn; + uint32_t inst_to_choose = 0; + + Address addr = resolved_addr; + + for (uint32_t i = 1; i <= loop_count; i++) { + // Adjust the address to read from. + addr.Slide(-2); + uint32_t insn_size = 0; + + disasm_sp->ParseInstructions(target, addr, + {Disassembler::Limit::Bytes, i * 2}, nullptr); + + uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); + if (num_insns) { + prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); + insn_size = prev_insn->GetOpcode().GetByteSize(); + if (i == 1 && insn_size == 2) { + // This looks like a valid 2-byte instruction (but it could be a part + // of upper 4 byte instruction). + instruction_list.Append(prev_insn); + inst_to_choose = 1; + } + else if (i == 2) { + // Here we may get one 4-byte instruction or two 2-byte instructions. + if (num_insns == 2) { + // Looks like there are two 2-byte instructions above our + // breakpoint target address. Now the upper 2-byte instruction is + // either a valid 2-byte instruction or could be a part of it's + // upper 4-byte instruction. In both cases we don't care because in + // this case lower 2-byte instruction is definitely a valid + // instruction and whatever i=1 iteration has found out is true. + inst_to_choose = 1; + break; + } + else if (insn_size == 4) { + // This instruction claims its a valid 4-byte instruction. But it + // could be a part of it's upper 4-byte instruction. Lets try + // scanning upper 2 bytes to verify this. + instruction_list.Append(prev_insn); + inst_to_choose = 2; + } + } + else if (i == 3) { + if (insn_size == 4) + // FIXME: We reached here that means instruction at [target - 4] has + // already claimed to be a 4-byte instruction, and now instruction + // at [target - 6] is also claiming that it's a 4-byte instruction. + // This can not be true. In this case we can not decide the valid + // previous instruction so we let lldb set the breakpoint at the + // address given by user. + inst_to_choose = 0; + else + // This is straight-forward + inst_to_choose = 2; + break; + } + } + else { + // Decode failed, bytes do not form a valid instruction. So whatever + // previous iteration has found out is true. + if (i > 1) { + inst_to_choose = i - 1; + break; + } + } + } + + // Check if we are able to find any valid instruction. + if (inst_to_choose) { + if (inst_to_choose > instruction_list.GetSize()) + inst_to_choose--; + return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get(); + } + + return nullptr; +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h b/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h new file mode 100644 index 000000000000..cedd4127afcb --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h @@ -0,0 +1,49 @@ +//===-- ArchitectureMips.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_ARCHITECTURE_MIPS_ARCHITECTUREMIPS_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_MIPS_ARCHITECTUREMIPS_H + +#include "lldb/Core/Architecture.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { + +class ArchitectureMips : public Architecture { +public: + static llvm::StringRef GetPluginNameStatic() { return "mips"; } + static void Initialize(); + static void Terminate(); + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + void OverrideStopInfo(Thread &thread) const override {} + + lldb::addr_t GetBreakableLoadAddress(lldb::addr_t addr, + Target &) const override; + + lldb::addr_t GetCallableLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + + lldb::addr_t GetOpcodeLoadAddress(lldb::addr_t load_addr, + AddressClass addr_class) const override; + +private: + Instruction *GetInstructionAtAddress(Target &target, + const Address &resolved_addr, + lldb::addr_t symbol_offset) const; + + static std::unique_ptr<Architecture> Create(const ArchSpec &arch); + ArchitectureMips(const ArchSpec &arch) : m_arch(arch) {} + + ArchSpec m_arch; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_MIPS_ARCHITECTUREMIPS_H diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp b/contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp new file mode 100644 index 000000000000..b8fac55e41da --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp @@ -0,0 +1,62 @@ +//===-- ArchitecturePPC64.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 "Plugins/Architecture/PPC64/ArchitecturePPC64.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/Symbol.h" +#include "lldb/Target/RegisterContext.h" +#include "lldb/Target/Target.h" +#include "lldb/Target/Thread.h" +#include "lldb/Utility/ArchSpec.h" + +#include "llvm/BinaryFormat/ELF.h" + +using namespace lldb_private; +using namespace lldb; + +LLDB_PLUGIN_DEFINE(ArchitecturePPC64) + +void ArchitecturePPC64::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "PPC64-specific algorithms", + &ArchitecturePPC64::Create); +} + +void ArchitecturePPC64::Terminate() { + PluginManager::UnregisterPlugin(&ArchitecturePPC64::Create); +} + +std::unique_ptr<Architecture> ArchitecturePPC64::Create(const ArchSpec &arch) { + if (arch.GetTriple().isPPC64() && + arch.GetTriple().getObjectFormat() == llvm::Triple::ObjectFormatType::ELF) + return std::unique_ptr<Architecture>(new ArchitecturePPC64()); + return nullptr; +} + +static int32_t GetLocalEntryOffset(const Symbol &sym) { + unsigned char other = sym.GetFlags() >> 8 & 0xFF; + return llvm::ELF::decodePPC64LocalEntryOffset(other); +} + +size_t ArchitecturePPC64::GetBytesToSkip(Symbol &func, + const Address &curr_addr) const { + if (curr_addr.GetFileAddress() == + func.GetFileAddress() + GetLocalEntryOffset(func)) + return func.GetPrologueByteSize(); + return 0; +} + +void ArchitecturePPC64::AdjustBreakpointAddress(const Symbol &func, + Address &addr) const { + int32_t loffs = GetLocalEntryOffset(func); + if (!loffs) + return; + + addr.SetOffset(addr.GetOffset() + loffs); +} diff --git a/contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h b/contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h new file mode 100644 index 000000000000..80f7f27b54cc --- /dev/null +++ b/contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h @@ -0,0 +1,40 @@ +//===-- ArchitecturePPC64.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_ARCHITECTURE_PPC64_ARCHITECTUREPPC64_H +#define LLDB_SOURCE_PLUGINS_ARCHITECTURE_PPC64_ARCHITECTUREPPC64_H + +#include "lldb/Core/Architecture.h" + +namespace lldb_private { + +class ArchitecturePPC64 : public Architecture { +public: + static llvm::StringRef GetPluginNameStatic() { return "ppc64"; } + static void Initialize(); + static void Terminate(); + + llvm::StringRef GetPluginName() override { return GetPluginNameStatic(); } + + void OverrideStopInfo(Thread &thread) const override {} + + /// This method compares current address with current function's + /// local entry point, returning the bytes to skip if they match. + size_t GetBytesToSkip(Symbol &func, const Address &curr_addr) const override; + + void AdjustBreakpointAddress(const Symbol &func, + Address &addr) const override; + +private: + static std::unique_ptr<Architecture> Create(const ArchSpec &arch); + ArchitecturePPC64() = default; +}; + +} // namespace lldb_private + +#endif // LLDB_SOURCE_PLUGINS_ARCHITECTURE_PPC64_ARCHITECTUREPPC64_H |