xref: /openbsd-src/gnu/llvm/lldb/source/Plugins/Architecture/Mips/ArchitectureMips.cpp (revision f6aab3d83b51b91c24247ad2c2573574de475a82)
1dda28197Spatrick //===-- ArchitectureMips.cpp ----------------------------------------------===//
2061da546Spatrick //
3061da546Spatrick // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4061da546Spatrick // See https://llvm.org/LICENSE.txt for license information.
5061da546Spatrick // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6061da546Spatrick //
7061da546Spatrick //===----------------------------------------------------------------------===//
8061da546Spatrick 
9061da546Spatrick #include "Plugins/Architecture/Mips/ArchitectureMips.h"
10061da546Spatrick #include "lldb/Core/Address.h"
11061da546Spatrick #include "lldb/Core/Disassembler.h"
12061da546Spatrick #include "lldb/Core/Module.h"
13061da546Spatrick #include "lldb/Core/PluginManager.h"
14061da546Spatrick #include "lldb/Symbol/Function.h"
15061da546Spatrick #include "lldb/Symbol/SymbolContext.h"
16061da546Spatrick #include "lldb/Target/SectionLoadList.h"
17061da546Spatrick #include "lldb/Target/Target.h"
18061da546Spatrick #include "lldb/Utility/ArchSpec.h"
19*f6aab3d8Srobert #include "lldb/Utility/LLDBLog.h"
20061da546Spatrick #include "lldb/Utility/Log.h"
21061da546Spatrick 
22061da546Spatrick using namespace lldb_private;
23061da546Spatrick using namespace lldb;
24061da546Spatrick 
LLDB_PLUGIN_DEFINE(ArchitectureMips)25dda28197Spatrick LLDB_PLUGIN_DEFINE(ArchitectureMips)
26dda28197Spatrick 
27061da546Spatrick void ArchitectureMips::Initialize() {
28061da546Spatrick   PluginManager::RegisterPlugin(GetPluginNameStatic(),
29061da546Spatrick                                 "Mips-specific algorithms",
30061da546Spatrick                                 &ArchitectureMips::Create);
31061da546Spatrick }
32061da546Spatrick 
Terminate()33061da546Spatrick void ArchitectureMips::Terminate() {
34061da546Spatrick   PluginManager::UnregisterPlugin(&ArchitectureMips::Create);
35061da546Spatrick }
36061da546Spatrick 
Create(const ArchSpec & arch)37061da546Spatrick std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) {
38061da546Spatrick   return arch.IsMIPS() ?
39061da546Spatrick       std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr;
40061da546Spatrick }
41061da546Spatrick 
GetCallableLoadAddress(addr_t code_addr,AddressClass addr_class) const42061da546Spatrick addr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr,
43061da546Spatrick                                                 AddressClass addr_class) const {
44061da546Spatrick   bool is_alternate_isa = false;
45061da546Spatrick 
46061da546Spatrick   switch (addr_class) {
47061da546Spatrick   case AddressClass::eData:
48061da546Spatrick   case AddressClass::eDebug:
49061da546Spatrick     return LLDB_INVALID_ADDRESS;
50061da546Spatrick   case AddressClass::eCodeAlternateISA:
51061da546Spatrick     is_alternate_isa = true;
52061da546Spatrick     break;
53061da546Spatrick   default: break;
54061da546Spatrick   }
55061da546Spatrick 
56061da546Spatrick   if ((code_addr & 2ull) || is_alternate_isa)
57061da546Spatrick     return code_addr | 1u;
58061da546Spatrick   return code_addr;
59061da546Spatrick }
60061da546Spatrick 
GetOpcodeLoadAddress(addr_t opcode_addr,AddressClass addr_class) const61061da546Spatrick addr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr,
62061da546Spatrick                                               AddressClass addr_class) const {
63061da546Spatrick   switch (addr_class) {
64061da546Spatrick   case AddressClass::eData:
65061da546Spatrick   case AddressClass::eDebug:
66061da546Spatrick     return LLDB_INVALID_ADDRESS;
67061da546Spatrick   default: break;
68061da546Spatrick   }
69061da546Spatrick   return opcode_addr & ~(1ull);
70061da546Spatrick }
71061da546Spatrick 
GetBreakableLoadAddress(lldb::addr_t addr,Target & target) const72061da546Spatrick lldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr,
73061da546Spatrick                                                        Target &target) const {
74061da546Spatrick 
75*f6aab3d8Srobert   Log *log = GetLog(LLDBLog::Breakpoints);
76061da546Spatrick 
77061da546Spatrick   Address resolved_addr;
78061da546Spatrick 
79061da546Spatrick   SectionLoadList &section_load_list = target.GetSectionLoadList();
80061da546Spatrick   if (section_load_list.IsEmpty())
81061da546Spatrick     // No sections are loaded, so we must assume we are not running yet and
82061da546Spatrick     // need to operate only on file address.
83061da546Spatrick     target.ResolveFileAddress(addr, resolved_addr);
84061da546Spatrick   else
85061da546Spatrick     target.ResolveLoadAddress(addr, resolved_addr);
86061da546Spatrick 
87061da546Spatrick   addr_t current_offset = 0;
88061da546Spatrick 
89061da546Spatrick   // Get the function boundaries to make sure we don't scan back before the
90061da546Spatrick   // beginning of the current function.
91061da546Spatrick   ModuleSP temp_addr_module_sp(resolved_addr.GetModule());
92061da546Spatrick   if (temp_addr_module_sp) {
93061da546Spatrick     SymbolContext sc;
94061da546Spatrick     SymbolContextItem resolve_scope =
95061da546Spatrick         eSymbolContextFunction | eSymbolContextSymbol;
96061da546Spatrick     temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr,
97061da546Spatrick       resolve_scope, sc);
98061da546Spatrick     Address sym_addr;
99061da546Spatrick     if (sc.function)
100061da546Spatrick       sym_addr = sc.function->GetAddressRange().GetBaseAddress();
101061da546Spatrick     else if (sc.symbol)
102061da546Spatrick       sym_addr = sc.symbol->GetAddress();
103061da546Spatrick 
104061da546Spatrick     addr_t function_start = sym_addr.GetLoadAddress(&target);
105061da546Spatrick     if (function_start == LLDB_INVALID_ADDRESS)
106061da546Spatrick       function_start = sym_addr.GetFileAddress();
107061da546Spatrick 
108061da546Spatrick     if (function_start)
109061da546Spatrick       current_offset = addr - function_start;
110061da546Spatrick   }
111061da546Spatrick 
112061da546Spatrick   // If breakpoint address is start of function then we dont have to do
113061da546Spatrick   // anything.
114061da546Spatrick   if (current_offset == 0)
115061da546Spatrick     return addr;
116061da546Spatrick 
117dda28197Spatrick   auto insn = GetInstructionAtAddress(target, current_offset, addr);
118061da546Spatrick 
119061da546Spatrick   if (nullptr == insn || !insn->HasDelaySlot())
120061da546Spatrick     return addr;
121061da546Spatrick 
122061da546Spatrick   // Adjust the breakable address
123061da546Spatrick   uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize();
124061da546Spatrick   LLDB_LOGF(log,
125061da546Spatrick             "Target::%s Breakpoint at 0x%8.8" PRIx64
126061da546Spatrick             " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n",
127061da546Spatrick             __FUNCTION__, addr, breakable_addr);
128061da546Spatrick 
129061da546Spatrick   return breakable_addr;
130061da546Spatrick }
131061da546Spatrick 
GetInstructionAtAddress(Target & target,const Address & resolved_addr,addr_t symbol_offset) const132061da546Spatrick Instruction *ArchitectureMips::GetInstructionAtAddress(
133dda28197Spatrick     Target &target, const Address &resolved_addr, addr_t symbol_offset) const {
134061da546Spatrick 
135061da546Spatrick   auto loop_count = symbol_offset / 2;
136061da546Spatrick 
137061da546Spatrick   uint32_t arch_flags = m_arch.GetFlags();
138061da546Spatrick   bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16;
139061da546Spatrick   bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips;
140061da546Spatrick 
141061da546Spatrick   if (loop_count > 3) {
142061da546Spatrick     // Scan previous 6 bytes
143061da546Spatrick     if (IsMips16 | IsMicromips)
144061da546Spatrick       loop_count = 3;
145061da546Spatrick     // For mips-only, instructions are always 4 bytes, so scan previous 4
146061da546Spatrick     // bytes only.
147061da546Spatrick     else
148061da546Spatrick       loop_count = 2;
149061da546Spatrick   }
150061da546Spatrick 
151061da546Spatrick   // Create Disassembler Instance
152061da546Spatrick   lldb::DisassemblerSP disasm_sp(
153061da546Spatrick     Disassembler::FindPlugin(m_arch, nullptr, nullptr));
154061da546Spatrick 
155061da546Spatrick   InstructionList instruction_list;
156061da546Spatrick   InstructionSP prev_insn;
157061da546Spatrick   uint32_t inst_to_choose = 0;
158061da546Spatrick 
159061da546Spatrick   Address addr = resolved_addr;
160061da546Spatrick 
161061da546Spatrick   for (uint32_t i = 1; i <= loop_count; i++) {
162061da546Spatrick     // Adjust the address to read from.
163061da546Spatrick     addr.Slide(-2);
164061da546Spatrick     uint32_t insn_size = 0;
165061da546Spatrick 
166dda28197Spatrick     disasm_sp->ParseInstructions(target, addr,
167be691f3bSpatrick                                  {Disassembler::Limit::Bytes, i * 2}, nullptr);
168061da546Spatrick 
169061da546Spatrick     uint32_t num_insns = disasm_sp->GetInstructionList().GetSize();
170061da546Spatrick     if (num_insns) {
171061da546Spatrick       prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0);
172061da546Spatrick       insn_size = prev_insn->GetOpcode().GetByteSize();
173061da546Spatrick       if (i == 1 && insn_size == 2) {
174061da546Spatrick         // This looks like a valid 2-byte instruction (but it could be a part
175061da546Spatrick         // of upper 4 byte instruction).
176061da546Spatrick         instruction_list.Append(prev_insn);
177061da546Spatrick         inst_to_choose = 1;
178061da546Spatrick       }
179061da546Spatrick       else if (i == 2) {
180061da546Spatrick         // Here we may get one 4-byte instruction or two 2-byte instructions.
181061da546Spatrick         if (num_insns == 2) {
182061da546Spatrick           // Looks like there are two 2-byte instructions above our
183061da546Spatrick           // breakpoint target address. Now the upper 2-byte instruction is
184061da546Spatrick           // either a valid 2-byte instruction or could be a part of it's
185061da546Spatrick           // upper 4-byte instruction. In both cases we don't care because in
186061da546Spatrick           // this case lower 2-byte instruction is definitely a valid
187061da546Spatrick           // instruction and whatever i=1 iteration has found out is true.
188061da546Spatrick           inst_to_choose = 1;
189061da546Spatrick           break;
190061da546Spatrick         }
191061da546Spatrick         else if (insn_size == 4) {
192061da546Spatrick           // This instruction claims its a valid 4-byte instruction. But it
193061da546Spatrick           // could be a part of it's upper 4-byte instruction. Lets try
194061da546Spatrick           // scanning upper 2 bytes to verify this.
195061da546Spatrick           instruction_list.Append(prev_insn);
196061da546Spatrick           inst_to_choose = 2;
197061da546Spatrick         }
198061da546Spatrick       }
199061da546Spatrick       else if (i == 3) {
200061da546Spatrick         if (insn_size == 4)
201061da546Spatrick           // FIXME: We reached here that means instruction at [target - 4] has
202061da546Spatrick           // already claimed to be a 4-byte instruction, and now instruction
203061da546Spatrick           // at [target - 6] is also claiming that it's a 4-byte instruction.
204061da546Spatrick           // This can not be true. In this case we can not decide the valid
205061da546Spatrick           // previous instruction so we let lldb set the breakpoint at the
206061da546Spatrick           // address given by user.
207061da546Spatrick           inst_to_choose = 0;
208061da546Spatrick         else
209061da546Spatrick           // This is straight-forward
210061da546Spatrick           inst_to_choose = 2;
211061da546Spatrick         break;
212061da546Spatrick       }
213061da546Spatrick     }
214061da546Spatrick     else {
215061da546Spatrick       // Decode failed, bytes do not form a valid instruction. So whatever
216061da546Spatrick       // previous iteration has found out is true.
217061da546Spatrick       if (i > 1) {
218061da546Spatrick         inst_to_choose = i - 1;
219061da546Spatrick         break;
220061da546Spatrick       }
221061da546Spatrick     }
222061da546Spatrick   }
223061da546Spatrick 
224061da546Spatrick   // Check if we are able to find any valid instruction.
225061da546Spatrick   if (inst_to_choose) {
226061da546Spatrick     if (inst_to_choose > instruction_list.GetSize())
227061da546Spatrick       inst_to_choose--;
228061da546Spatrick     return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get();
229061da546Spatrick   }
230061da546Spatrick 
231061da546Spatrick   return nullptr;
232061da546Spatrick }
233