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

source code of lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp