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/Log.h"
20
21 using namespace lldb_private;
22 using namespace lldb;
23
LLDB_PLUGIN_DEFINE(ArchitectureMips)24 LLDB_PLUGIN_DEFINE(ArchitectureMips)
25
26 ConstString ArchitectureMips::GetPluginNameStatic() {
27 return ConstString("mips");
28 }
29
Initialize()30 void ArchitectureMips::Initialize() {
31 PluginManager::RegisterPlugin(GetPluginNameStatic(),
32 "Mips-specific algorithms",
33 &ArchitectureMips::Create);
34 }
35
Terminate()36 void ArchitectureMips::Terminate() {
37 PluginManager::UnregisterPlugin(&ArchitectureMips::Create);
38 }
39
Create(const ArchSpec & arch)40 std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) {
41 return arch.IsMIPS() ?
42 std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr;
43 }
44
GetPluginName()45 ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); }
GetPluginVersion()46 uint32_t ArchitectureMips::GetPluginVersion() { return 1; }
47
GetCallableLoadAddress(addr_t code_addr,AddressClass addr_class) const48 addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr,
49 AddressClass addr_class) const {
50 bool is_alternate_isa = false;
51
52 switch (addr_class) {
53 case AddressClass::eData:
54 case AddressClass::eDebug:
55 return LLDB_INVALID_ADDRESS;
56 case AddressClass::eCodeAlternateISA:
57 is_alternate_isa = true;
58 break;
59 default: break;
60 }
61
62 if ((code_addr & 2ull) || is_alternate_isa)
63 return code_addr | 1u;
64 return code_addr;
65 }
66
GetOpcodeLoadAddress(addr_t opcode_addr,AddressClass addr_class) const67 addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr,
68 AddressClass addr_class) const {
69 switch (addr_class) {
70 case AddressClass::eData:
71 case AddressClass::eDebug:
72 return LLDB_INVALID_ADDRESS;
73 default: break;
74 }
75 return opcode_addr & ~(1ull);
76 }
77
GetBreakableLoadAddress(lldb::addr_t addr,Target & target) const78 lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr,
79 Target &target) const {
80
81 Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS));
82
83 Address resolved_addr;
84
85 SectionLoadList §ion_load_list = target.GetSectionLoadList();
86 if (section_load_list.IsEmpty())
87 // No sections are loaded, so we must assume we are not running yet and
88 // need to operate only on file address.
89 target.ResolveFileAddress(addr, resolved_addr);
90 else
91 target.ResolveLoadAddress(addr, resolved_addr);
92
93 addr_t current_offset = 0;
94
95 // Get the function boundaries to make sure we don't scan back before the
96 // beginning of the current function.
97 ModuleSP temp_addr_module_sp(resolved_addr.GetModule());
98 if (temp_addr_module_sp) {
99 SymbolContext sc;
100 SymbolContextItem resolve_scope =
101 eSymbolContextFunction | eSymbolContextSymbol;
102 temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr,
103 resolve_scope, sc);
104 Address sym_addr;
105 if (sc.function)
106 sym_addr = sc.function->GetAddressRange().GetBaseAddress();
107 else if (sc.symbol)
108 sym_addr = sc.symbol->GetAddress();
109
110 addr_t function_start = sym_addr.GetLoadAddress(&target);
111 if (function_start == LLDB_INVALID_ADDRESS)
112 function_start = sym_addr.GetFileAddress();
113
114 if (function_start)
115 current_offset = addr - function_start;
116 }
117
118 // If breakpoint address is start of function then we dont have to do
119 // anything.
120 if (current_offset == 0)
121 return addr;
122
123 auto insn = GetInstructionAtAddress(target, 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 LLDB_LOGF(log,
131 "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
GetInstructionAtAddress(Target & target,const Address & resolved_addr,addr_t symbol_offset) const138 Instruction *ArchitectureMips::GetInstructionAtAddress(
139 Target &target, const Address &resolved_addr, addr_t symbol_offset) const {
140
141 auto loop_count = symbol_offset / 2;
142
143 uint32_t arch_flags = m_arch.GetFlags();
144 bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;
145 bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;
146
147 if (loop_count > 3) {
148 // Scan previous 6 bytes
149 if (IsMips16 | IsMicromips)
150 loop_count = 3;
151 // For mips-only, instructions are always 4 bytes, so scan previous 4
152 // bytes only.
153 else
154 loop_count = 2;
155 }
156
157 // Create Disassembler Instance
158 lldb::DisassemblerSP disasm_sp(
159 Disassembler::FindPlugin(m_arch, nullptr, nullptr));
160
161 InstructionList instruction_list;
162 InstructionSP prev_insn;
163 bool prefer_file_cache = true; // Read from file
164 uint32_t inst_to_choose = 0;
165
166 Address addr = resolved_addr;
167
168 for (uint32_t i = 1; i <= loop_count; i++) {
169 // Adjust the address to read from.
170 addr.Slide(-2);
171 uint32_t insn_size = 0;
172
173 disasm_sp->ParseInstructions(target, addr,
174 {Disassembler::Limit::Bytes, i * 2}, nullptr,
175 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