xref: /llvm-project/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp (revision c4fb7180cbbe977f1ab1ce945a691550f8fdd1fb)
1 //===-- ArchitectureMips.cpp ----------------------------------------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 
9 #include "Plugins/Architecture/Mips/ArchitectureMips.h"
10 #include "lldb/Core/Address.h"
11 #include "lldb/Core/Disassembler.h"
12 #include "lldb/Core/Module.h"
13 #include "lldb/Core/PluginManager.h"
14 #include "lldb/Symbol/Function.h"
15 #include "lldb/Symbol/SymbolContext.h"
16 #include "lldb/Target/SectionLoadList.h"
17 #include "lldb/Target/Target.h"
18 #include "lldb/Utility/ArchSpec.h"
19 #include "lldb/Utility/LLDBLog.h"
20 #include "lldb/Utility/Log.h"
21 
22 using namespace lldb_private;
23 using namespace lldb;
24 
25 LLDB_PLUGIN_DEFINE(ArchitectureMips)
26 
27 void ArchitectureMips::Initialize() {
28   PluginManager::RegisterPlugin(GetPluginNameStatic(),
29                                 "Mips-specific algorithms",
30                                 &ArchitectureMips::Create);
31 }
32 
33 void ArchitectureMips::Terminate() {
34   PluginManager::UnregisterPlugin(&ArchitectureMips::Create);
35 }
36 
37 std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) {
38   return arch.IsMIPS() ?
39       std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr;
40 }
41 
42 addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr,
43                                                 AddressClass addr_class) const {
44   bool is_alternate_isa = false;
45 
46   switch (addr_class) {
47   case AddressClass::eData:
48   case AddressClass::eDebug:
49     return LLDB_INVALID_ADDRESS;
50   case AddressClass::eCodeAlternateISA:
51     is_alternate_isa = true;
52     break;
53   default: break;
54   }
55 
56   if ((code_addr & 2ull) || is_alternate_isa)
57     return code_addr | 1u;
58   return code_addr;
59 }
60 
61 addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr,
62                                               AddressClass addr_class) const {
63   switch (addr_class) {
64   case AddressClass::eData:
65   case AddressClass::eDebug:
66     return LLDB_INVALID_ADDRESS;
67   default: break;
68   }
69   return opcode_addr & ~(1ull);
70 }
71 
72 lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr,
73                                                        Target &target) const {
74 
75   Log *log = GetLog(LLDBLog::Breakpoints);
76 
77   Address resolved_addr;
78 
79   if (!target.HasLoadedSections())
80     // No sections are loaded, so we must assume we are not running yet and
81     // need to operate only on file address.
82     target.ResolveFileAddress(addr, resolved_addr);
83   else
84     target.ResolveLoadAddress(addr, resolved_addr);
85 
86   addr_t current_offset = 0;
87 
88   // Get the function boundaries to make sure we don't scan back before the
89   // beginning of the current function.
90   ModuleSP temp_addr_module_sp(resolved_addr.GetModule());
91   if (temp_addr_module_sp) {
92     SymbolContext sc;
93     SymbolContextItem resolve_scope =
94         eSymbolContextFunction | eSymbolContextSymbol;
95     temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr,
96       resolve_scope, sc);
97     Address sym_addr;
98     if (sc.function)
99       sym_addr = sc.function->GetAddress();
100     else if (sc.symbol)
101       sym_addr = sc.symbol->GetAddress();
102 
103     addr_t function_start = sym_addr.GetLoadAddress(&target);
104     if (function_start == LLDB_INVALID_ADDRESS)
105       function_start = sym_addr.GetFileAddress();
106 
107     if (function_start)
108       current_offset = addr - function_start;
109   }
110 
111   // If breakpoint address is start of function then we dont have to do
112   // anything.
113   if (current_offset == 0)
114     return addr;
115 
116   auto insn = GetInstructionAtAddress(target, current_offset, addr);
117 
118   if (nullptr == insn || !insn->HasDelaySlot())
119     return addr;
120 
121   // Adjust the breakable address
122   uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize();
123   LLDB_LOGF(log,
124             "Target::%s Breakpoint at 0x%8.8" PRIx64
125             " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n",
126             __FUNCTION__, addr, breakable_addr);
127 
128   return breakable_addr;
129 }
130 
131 Instruction *ArchitectureMips::GetInstructionAtAddress(
132     Target &target, const Address &resolved_addr, addr_t symbol_offset) const {
133 
134   auto loop_count = symbol_offset / 2;
135 
136   uint32_t arch_flags = m_arch.GetFlags();
137   bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;
138   bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;
139 
140   if (loop_count > 3) {
141     // Scan previous 6 bytes
142     if (IsMips16 | IsMicromips)
143       loop_count = 3;
144     // For mips-only, instructions are always 4 bytes, so scan previous 4
145     // bytes only.
146     else
147       loop_count = 2;
148   }
149 
150   // Create Disassembler Instance
151   lldb::DisassemblerSP disasm_sp(
152       Disassembler::FindPlugin(m_arch, nullptr, nullptr, nullptr, nullptr));
153 
154   InstructionList instruction_list;
155   InstructionSP prev_insn;
156   uint32_t inst_to_choose = 0;
157 
158   Address addr = resolved_addr;
159 
160   for (uint32_t i = 1; i <= loop_count; i++) {
161     // Adjust the address to read from.
162     addr.Slide(-2);
163     uint32_t insn_size = 0;
164 
165     disasm_sp->ParseInstructions(target, addr,
166                                  {Disassembler::Limit::Bytes, i * 2}, nullptr);
167 
168     uint32_t num_insns = disasm_sp->GetInstructionList().GetSize();
169     if (num_insns) {
170       prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0);
171       insn_size = prev_insn->GetOpcode().GetByteSize();
172       if (i == 1 && insn_size == 2) {
173         // This looks like a valid 2-byte instruction (but it could be a part
174         // of upper 4 byte instruction).
175         instruction_list.Append(prev_insn);
176         inst_to_choose = 1;
177       }
178       else if (i == 2) {
179         // Here we may get one 4-byte instruction or two 2-byte instructions.
180         if (num_insns == 2) {
181           // Looks like there are two 2-byte instructions above our
182           // breakpoint target address. Now the upper 2-byte instruction is
183           // either a valid 2-byte instruction or could be a part of it's
184           // upper 4-byte instruction. In both cases we don't care because in
185           // this case lower 2-byte instruction is definitely a valid
186           // instruction and whatever i=1 iteration has found out is true.
187           inst_to_choose = 1;
188           break;
189         }
190         else if (insn_size == 4) {
191           // This instruction claims its a valid 4-byte instruction. But it
192           // could be a part of it's upper 4-byte instruction. Lets try
193           // scanning upper 2 bytes to verify this.
194           instruction_list.Append(prev_insn);
195           inst_to_choose = 2;
196         }
197       }
198       else if (i == 3) {
199         if (insn_size == 4)
200           // FIXME: We reached here that means instruction at [target - 4] has
201           // already claimed to be a 4-byte instruction, and now instruction
202           // at [target - 6] is also claiming that it's a 4-byte instruction.
203           // This can not be true. In this case we can not decide the valid
204           // previous instruction so we let lldb set the breakpoint at the
205           // address given by user.
206           inst_to_choose = 0;
207         else
208           // This is straight-forward
209           inst_to_choose = 2;
210         break;
211       }
212     }
213     else {
214       // Decode failed, bytes do not form a valid instruction. So whatever
215       // previous iteration has found out is true.
216       if (i > 1) {
217         inst_to_choose = i - 1;
218         break;
219       }
220     }
221   }
222 
223   // Check if we are able to find any valid instruction.
224   if (inst_to_choose) {
225     if (inst_to_choose > instruction_list.GetSize())
226       inst_to_choose--;
227     return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get();
228   }
229 
230   return nullptr;
231 }
232