xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Architecture/Arm/ArchitectureArm.cpp (revision 061da546b983eb767bad15e67af1174fb0bcf31c)
1*061da546Spatrick //===-- ArchitectureArm.cpp -------------------------------------*- C++ -*-===//
2*061da546Spatrick //
3*061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5*061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*061da546Spatrick //
7*061da546Spatrick //===----------------------------------------------------------------------===//
8*061da546Spatrick 
9*061da546Spatrick #include "Plugins/Architecture/Arm/ArchitectureArm.h"
10*061da546Spatrick #include "Plugins/Process/Utility/ARMDefines.h"
11*061da546Spatrick #include "Plugins/Process/Utility/InstructionUtils.h"
12*061da546Spatrick #include "lldb/Core/PluginManager.h"
13*061da546Spatrick #include "lldb/Target/RegisterContext.h"
14*061da546Spatrick #include "lldb/Target/Thread.h"
15*061da546Spatrick #include "lldb/Utility/ArchSpec.h"
16*061da546Spatrick 
17*061da546Spatrick using namespace lldb_private;
18*061da546Spatrick using namespace lldb;
19*061da546Spatrick 
20*061da546Spatrick ConstString ArchitectureArm::GetPluginNameStatic() {
21*061da546Spatrick   return ConstString("arm");
22*061da546Spatrick }
23*061da546Spatrick 
24*061da546Spatrick void ArchitectureArm::Initialize() {
25*061da546Spatrick   PluginManager::RegisterPlugin(GetPluginNameStatic(),
26*061da546Spatrick                                 "Arm-specific algorithms",
27*061da546Spatrick                                 &ArchitectureArm::Create);
28*061da546Spatrick }
29*061da546Spatrick 
30*061da546Spatrick void ArchitectureArm::Terminate() {
31*061da546Spatrick   PluginManager::UnregisterPlugin(&ArchitectureArm::Create);
32*061da546Spatrick }
33*061da546Spatrick 
34*061da546Spatrick std::unique_ptr<Architecture> ArchitectureArm::Create(const ArchSpec &arch) {
35*061da546Spatrick   if (arch.GetMachine() != llvm::Triple::arm)
36*061da546Spatrick     return nullptr;
37*061da546Spatrick   return std::unique_ptr<Architecture>(new ArchitectureArm());
38*061da546Spatrick }
39*061da546Spatrick 
40*061da546Spatrick ConstString ArchitectureArm::GetPluginName() { return GetPluginNameStatic(); }
41*061da546Spatrick uint32_t ArchitectureArm::GetPluginVersion() { return 1; }
42*061da546Spatrick 
43*061da546Spatrick void ArchitectureArm::OverrideStopInfo(Thread &thread) const {
44*061da546Spatrick   // We need to check if we are stopped in Thumb mode in a IT instruction and
45*061da546Spatrick   // detect if the condition doesn't pass. If this is the case it means we
46*061da546Spatrick   // won't actually execute this instruction. If this happens we need to clear
47*061da546Spatrick   // the stop reason to no thread plans think we are stopped for a reason and
48*061da546Spatrick   // the plans should keep going.
49*061da546Spatrick   //
50*061da546Spatrick   // We do this because when single stepping many ARM processes, debuggers
51*061da546Spatrick   // often use the BVR/BCR registers that says "stop when the PC is not equal
52*061da546Spatrick   // to its current value". This method of stepping means we can end up
53*061da546Spatrick   // stopping on instructions inside an if/then block that wouldn't get
54*061da546Spatrick   // executed. By fixing this we can stop the debugger from seeming like you
55*061da546Spatrick   // stepped through both the "if" _and_ the "else" clause when source level
56*061da546Spatrick   // stepping because the debugger stops regardless due to the BVR/BCR
57*061da546Spatrick   // triggering a stop.
58*061da546Spatrick   //
59*061da546Spatrick   // It also means we can set breakpoints on instructions inside an an if/then
60*061da546Spatrick   // block and correctly skip them if we use the BKPT instruction. The ARM and
61*061da546Spatrick   // Thumb BKPT instructions are unconditional even when executed in a Thumb IT
62*061da546Spatrick   // block.
63*061da546Spatrick   //
64*061da546Spatrick   // If your debugger inserts software traps in ARM/Thumb code, it will need to
65*061da546Spatrick   // use 16 and 32 bit instruction for 16 and 32 bit thumb instructions
66*061da546Spatrick   // respectively. If your debugger inserts a 16 bit thumb trap on top of a 32
67*061da546Spatrick   // bit thumb instruction for an opcode that is inside an if/then, it will
68*061da546Spatrick   // change the it/then to conditionally execute your
69*061da546Spatrick   // 16 bit trap and then cause your program to crash if it executes the
70*061da546Spatrick   // trailing 16 bits (the second half of the 32 bit thumb instruction you
71*061da546Spatrick   // partially overwrote).
72*061da546Spatrick 
73*061da546Spatrick   RegisterContextSP reg_ctx_sp(thread.GetRegisterContext());
74*061da546Spatrick   if (!reg_ctx_sp)
75*061da546Spatrick     return;
76*061da546Spatrick 
77*061da546Spatrick   const uint32_t cpsr = reg_ctx_sp->GetFlags(0);
78*061da546Spatrick   if (cpsr == 0)
79*061da546Spatrick     return;
80*061da546Spatrick 
81*061da546Spatrick   // Read the J and T bits to get the ISETSTATE
82*061da546Spatrick   const uint32_t J = Bit32(cpsr, 24);
83*061da546Spatrick   const uint32_t T = Bit32(cpsr, 5);
84*061da546Spatrick   const uint32_t ISETSTATE = J << 1 | T;
85*061da546Spatrick   if (ISETSTATE == 0) {
86*061da546Spatrick // NOTE: I am pretty sure we want to enable the code below
87*061da546Spatrick // that detects when we stop on an instruction in ARM mode that is conditional
88*061da546Spatrick // and the condition doesn't pass. This can happen if you set a breakpoint on
89*061da546Spatrick // an instruction that is conditional. We currently will _always_ stop on the
90*061da546Spatrick // instruction which is bad. You can also run into this while single stepping
91*061da546Spatrick // and you could appear to run code in the "if" and in the "else" clause
92*061da546Spatrick // because it would stop at all of the conditional instructions in both. In
93*061da546Spatrick // such cases, we really don't want to stop at this location.
94*061da546Spatrick // I will check with the lldb-dev list first before I enable this.
95*061da546Spatrick #if 0
96*061da546Spatrick     // ARM mode: check for condition on instruction
97*061da546Spatrick     const addr_t pc = reg_ctx_sp->GetPC();
98*061da546Spatrick     Status error;
99*061da546Spatrick     // If we fail to read the opcode we will get UINT64_MAX as the result in
100*061da546Spatrick     // "opcode" which we can use to detect if we read a valid opcode.
101*061da546Spatrick     const uint64_t opcode = thread.GetProcess()->ReadUnsignedIntegerFromMemory(pc, 4, UINT64_MAX, error);
102*061da546Spatrick     if (opcode <= UINT32_MAX)
103*061da546Spatrick     {
104*061da546Spatrick         const uint32_t condition = Bits32((uint32_t)opcode, 31, 28);
105*061da546Spatrick         if (!ARMConditionPassed(condition, cpsr))
106*061da546Spatrick         {
107*061da546Spatrick             // We ARE stopped on an ARM instruction whose condition doesn't
108*061da546Spatrick             // pass so this instruction won't get executed. Regardless of why
109*061da546Spatrick             // it stopped, we need to clear the stop info
110*061da546Spatrick             thread.SetStopInfo (StopInfoSP());
111*061da546Spatrick         }
112*061da546Spatrick     }
113*061da546Spatrick #endif
114*061da546Spatrick   } else if (ISETSTATE == 1) {
115*061da546Spatrick     // Thumb mode
116*061da546Spatrick     const uint32_t ITSTATE = Bits32(cpsr, 15, 10) << 2 | Bits32(cpsr, 26, 25);
117*061da546Spatrick     if (ITSTATE != 0) {
118*061da546Spatrick       const uint32_t condition = Bits32(ITSTATE, 7, 4);
119*061da546Spatrick       if (!ARMConditionPassed(condition, cpsr)) {
120*061da546Spatrick         // We ARE stopped in a Thumb IT instruction on an instruction whose
121*061da546Spatrick         // condition doesn't pass so this instruction won't get executed.
122*061da546Spatrick         // Regardless of why it stopped, we need to clear the stop info
123*061da546Spatrick         thread.SetStopInfo(StopInfoSP());
124*061da546Spatrick       }
125*061da546Spatrick     }
126*061da546Spatrick   }
127*061da546Spatrick }
128*061da546Spatrick 
129*061da546Spatrick addr_t ArchitectureArm::GetCallableLoadAddress(addr_t code_addr,
130*061da546Spatrick                                                AddressClass addr_class) const {
131*061da546Spatrick   bool is_alternate_isa = false;
132*061da546Spatrick 
133*061da546Spatrick   switch (addr_class) {
134*061da546Spatrick   case AddressClass::eData:
135*061da546Spatrick   case AddressClass::eDebug:
136*061da546Spatrick     return LLDB_INVALID_ADDRESS;
137*061da546Spatrick   case AddressClass::eCodeAlternateISA:
138*061da546Spatrick     is_alternate_isa = true;
139*061da546Spatrick     break;
140*061da546Spatrick   default: break;
141*061da546Spatrick   }
142*061da546Spatrick 
143*061da546Spatrick   if ((code_addr & 2u) || is_alternate_isa)
144*061da546Spatrick     return code_addr | 1u;
145*061da546Spatrick   return code_addr;
146*061da546Spatrick }
147*061da546Spatrick 
148*061da546Spatrick addr_t ArchitectureArm::GetOpcodeLoadAddress(addr_t opcode_addr,
149*061da546Spatrick                                              AddressClass addr_class) const {
150*061da546Spatrick   switch (addr_class) {
151*061da546Spatrick   case AddressClass::eData:
152*061da546Spatrick   case AddressClass::eDebug:
153*061da546Spatrick     return LLDB_INVALID_ADDRESS;
154*061da546Spatrick   default: break;
155*061da546Spatrick   }
156*061da546Spatrick   return opcode_addr & ~(1ull);
157*061da546Spatrick }
158