Path: blob/main/contrib/llvm-project/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp
39648 views
//===-- ArchitectureArm.cpp -----------------------------------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//78#include "Plugins/Architecture/Arm/ArchitectureArm.h"9#include "Plugins/Process/Utility/ARMDefines.h"10#include "Plugins/Process/Utility/InstructionUtils.h"11#include "lldb/Core/PluginManager.h"12#include "lldb/Target/RegisterContext.h"13#include "lldb/Target/Thread.h"14#include "lldb/Utility/ArchSpec.h"1516using namespace lldb_private;17using namespace lldb;1819LLDB_PLUGIN_DEFINE(ArchitectureArm)2021void ArchitectureArm::Initialize() {22PluginManager::RegisterPlugin(GetPluginNameStatic(),23"Arm-specific algorithms",24&ArchitectureArm::Create);25}2627void ArchitectureArm::Terminate() {28PluginManager::UnregisterPlugin(&ArchitectureArm::Create);29}3031std::unique_ptr<Architecture> ArchitectureArm::Create(const ArchSpec &arch) {32if (arch.GetMachine() != llvm::Triple::arm)33return nullptr;34return std::unique_ptr<Architecture>(new ArchitectureArm());35}3637void ArchitectureArm::OverrideStopInfo(Thread &thread) const {38// We need to check if we are stopped in Thumb mode in a IT instruction and39// detect if the condition doesn't pass. If this is the case it means we40// won't actually execute this instruction. If this happens we need to clear41// the stop reason to no thread plans think we are stopped for a reason and42// the plans should keep going.43//44// We do this because when single stepping many ARM processes, debuggers45// often use the BVR/BCR registers that says "stop when the PC is not equal46// to its current value". This method of stepping means we can end up47// stopping on instructions inside an if/then block that wouldn't get48// executed. By fixing this we can stop the debugger from seeming like you49// stepped through both the "if" _and_ the "else" clause when source level50// stepping because the debugger stops regardless due to the BVR/BCR51// triggering a stop.52//53// It also means we can set breakpoints on instructions inside an if/then54// block and correctly skip them if we use the BKPT instruction. The ARM and55// Thumb BKPT instructions are unconditional even when executed in a Thumb IT56// block.57//58// If your debugger inserts software traps in ARM/Thumb code, it will need to59// use 16 and 32 bit instruction for 16 and 32 bit thumb instructions60// respectively. If your debugger inserts a 16 bit thumb trap on top of a 3261// bit thumb instruction for an opcode that is inside an if/then, it will62// change the it/then to conditionally execute your63// 16 bit trap and then cause your program to crash if it executes the64// trailing 16 bits (the second half of the 32 bit thumb instruction you65// partially overwrote).6667RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());68if (!reg_ctx_sp)69return;7071const uint32_t cpsr = reg_ctx_sp->GetFlags(0);72if (cpsr == 0)73return;7475// Read the J and T bits to get the ISETSTATE76const uint32_t J = Bit32(cpsr, 24);77const uint32_t T = Bit32(cpsr, 5);78const uint32_t ISETSTATE = J << 1 | T;79if (ISETSTATE == 0) {80// NOTE: I am pretty sure we want to enable the code below81// that detects when we stop on an instruction in ARM mode that is conditional82// and the condition doesn't pass. This can happen if you set a breakpoint on83// an instruction that is conditional. We currently will _always_ stop on the84// instruction which is bad. You can also run into this while single stepping85// and you could appear to run code in the "if" and in the "else" clause86// because it would stop at all of the conditional instructions in both. In87// such cases, we really don't want to stop at this location.88// I will check with the lldb-dev list first before I enable this.89#if 090// ARM mode: check for condition on instruction91const addr_t pc = reg_ctx_sp->GetPC();92Status error;93// If we fail to read the opcode we will get UINT64_MAX as the result in94// "opcode" which we can use to detect if we read a valid opcode.95const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error);96if (opcode <= UINT32_MAX)97{98const uint32_t condition = Bits32((uint32_t)opcode, 31, 28);99if (!ARMConditionPassed(condition, cpsr))100{101// We ARE stopped on an ARM instruction whose condition doesn't102// pass so this instruction won't get executed. Regardless of why103// it stopped, we need to clear the stop info104thread.SetStopInfo (StopInfoSP());105}106}107#endif108} else if (ISETSTATE == 1) {109// Thumb mode110const uint32_t ITSTATE = Bits32(cpsr, 15, 10) << 2 | Bits32(cpsr, 26, 25);111if (ITSTATE != 0) {112const uint32_t condition = Bits32(ITSTATE, 7, 4);113if (!ARMConditionPassed(condition, cpsr)) {114// We ARE stopped in a Thumb IT instruction on an instruction whose115// condition doesn't pass so this instruction won't get executed.116// Regardless of why it stopped, we need to clear the stop info117thread.SetStopInfo(StopInfoSP());118}119}120}121}122123addr_t ArchitectureArm::GetCallableLoadAddress(addr_t code_addr,124AddressClass addr_class) const {125bool is_alternate_isa = false;126127switch (addr_class) {128case AddressClass::eData:129case AddressClass::eDebug:130return LLDB_INVALID_ADDRESS;131case AddressClass::eCodeAlternateISA:132is_alternate_isa = true;133break;134default: break;135}136137if ((code_addr & 2u) || is_alternate_isa)138return code_addr | 1u;139return code_addr;140}141142addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr,143AddressClass addr_class) const {144switch (addr_class) {145case AddressClass::eData:146case AddressClass::eDebug:147return LLDB_INVALID_ADDRESS;148default: break;149}150return opcode_addr & ~(1ull);151}152153154