aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/lldb/source/Plugins/Architecture
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/lldb/source/Plugins/Architecture')
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.cpp124
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/AArch64/ArchitectureAArch64.h50
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp152
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.h39
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp232
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.h49
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.cpp62
-rw-r--r--contrib/llvm-project/lldb/source/Plugins/Architecture/PPC64/ArchitecturePPC64.h40
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 &reg : 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 &reg : 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 &reg_info,
+ DataExtractor &reg_data,
+ RegisterContext &reg_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 &reg_info,
+ DataExtractor &reg_data,
+ RegisterContext &reg_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 &section_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