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