ArchitectureMips.cpp revision 355940
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
21using namespace lldb_private;
22using namespace lldb;
23
24ConstString ArchitectureMips::GetPluginNameStatic() {
25  return ConstString("mips");
26}
27
28void ArchitectureMips::Initialize() {
29  PluginManager::RegisterPlugin(GetPluginNameStatic(),
30                                "Mips-specific algorithms",
31                                &ArchitectureMips::Create);
32}
33
34void ArchitectureMips::Terminate() {
35  PluginManager::UnregisterPlugin(&ArchitectureMips::Create);
36}
37
38std::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) {
39  return arch.IsMIPS() ?
40      std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr;
41}
42
43ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); }
44uint32_t ArchitectureMips::GetPluginVersion() { return 1; }
45
46addr_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
65addr_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
76lldb::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
138Instruction *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