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