1343181Sdim//===-- ArchitectureMips.cpp -------------------------------------*- C++ -*-===// 2343181Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6343181Sdim// 7343181Sdim//===----------------------------------------------------------------------===// 8343181Sdim 9343181Sdim#include "Plugins/Architecture/Mips/ArchitectureMips.h" 10343181Sdim#include "lldb/Core/Address.h" 11343181Sdim#include "lldb/Core/Disassembler.h" 12343181Sdim#include "lldb/Core/Module.h" 13343181Sdim#include "lldb/Core/PluginManager.h" 14343181Sdim#include "lldb/Symbol/Function.h" 15343181Sdim#include "lldb/Symbol/SymbolContext.h" 16343181Sdim#include "lldb/Target/SectionLoadList.h" 17343181Sdim#include "lldb/Target/Target.h" 18343181Sdim#include "lldb/Utility/ArchSpec.h" 19343181Sdim#include "lldb/Utility/Log.h" 20343181Sdim 21343181Sdimusing namespace lldb_private; 22343181Sdimusing namespace lldb; 23343181Sdim 24343181SdimConstString ArchitectureMips::GetPluginNameStatic() { 25343181Sdim return ConstString("mips"); 26343181Sdim} 27343181Sdim 28343181Sdimvoid ArchitectureMips::Initialize() { 29343181Sdim PluginManager::RegisterPlugin(GetPluginNameStatic(), 30343181Sdim "Mips-specific algorithms", 31343181Sdim &ArchitectureMips::Create); 32343181Sdim} 33343181Sdim 34343181Sdimvoid ArchitectureMips::Terminate() { 35343181Sdim PluginManager::UnregisterPlugin(&ArchitectureMips::Create); 36343181Sdim} 37343181Sdim 38343181Sdimstd::unique_ptr<Architecture> ArchitectureMips::Create(const ArchSpec &arch) { 39343181Sdim return arch.IsMIPS() ? 40343181Sdim std::unique_ptr<Architecture>(new ArchitectureMips(arch)) : nullptr; 41343181Sdim} 42343181Sdim 43343181SdimConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); } 44343181Sdimuint32_t ArchitectureMips::GetPluginVersion() { return 1; } 45343181Sdim 46343181Sdimaddr_t ArchitectureMips::GetCallableLoadAddress(addr_t code_addr, 47343181Sdim AddressClass addr_class) const { 48343181Sdim bool is_alternate_isa = false; 49343181Sdim 50343181Sdim switch (addr_class) { 51343181Sdim case AddressClass::eData: 52343181Sdim case AddressClass::eDebug: 53343181Sdim return LLDB_INVALID_ADDRESS; 54343181Sdim case AddressClass::eCodeAlternateISA: 55343181Sdim is_alternate_isa = true; 56343181Sdim break; 57343181Sdim default: break; 58343181Sdim } 59343181Sdim 60343181Sdim if ((code_addr & 2ull) || is_alternate_isa) 61343181Sdim return code_addr | 1u; 62343181Sdim return code_addr; 63343181Sdim} 64343181Sdim 65343181Sdimaddr_t ArchitectureMips::GetOpcodeLoadAddress(addr_t opcode_addr, 66343181Sdim AddressClass addr_class) const { 67343181Sdim switch (addr_class) { 68343181Sdim case AddressClass::eData: 69343181Sdim case AddressClass::eDebug: 70343181Sdim return LLDB_INVALID_ADDRESS; 71343181Sdim default: break; 72343181Sdim } 73343181Sdim return opcode_addr & ~(1ull); 74343181Sdim} 75343181Sdim 76343181Sdimlldb::addr_t ArchitectureMips::GetBreakableLoadAddress(lldb::addr_t addr, 77343181Sdim Target &target) const { 78343181Sdim 79343181Sdim Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); 80343181Sdim 81343181Sdim Address resolved_addr; 82343181Sdim 83343181Sdim SectionLoadList §ion_load_list = target.GetSectionLoadList(); 84343181Sdim if (section_load_list.IsEmpty()) 85343181Sdim // No sections are loaded, so we must assume we are not running yet and 86343181Sdim // need to operate only on file address. 87343181Sdim target.ResolveFileAddress(addr, resolved_addr); 88343181Sdim else 89343181Sdim target.ResolveLoadAddress(addr, resolved_addr); 90343181Sdim 91343181Sdim addr_t current_offset = 0; 92343181Sdim 93343181Sdim // Get the function boundaries to make sure we don't scan back before the 94343181Sdim // beginning of the current function. 95343181Sdim ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); 96343181Sdim if (temp_addr_module_sp) { 97343181Sdim SymbolContext sc; 98343181Sdim SymbolContextItem resolve_scope = 99343181Sdim eSymbolContextFunction | eSymbolContextSymbol; 100343181Sdim temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, 101343181Sdim resolve_scope, sc); 102343181Sdim Address sym_addr; 103343181Sdim if (sc.function) 104343181Sdim sym_addr = sc.function->GetAddressRange().GetBaseAddress(); 105343181Sdim else if (sc.symbol) 106343181Sdim sym_addr = sc.symbol->GetAddress(); 107343181Sdim 108343181Sdim addr_t function_start = sym_addr.GetLoadAddress(&target); 109343181Sdim if (function_start == LLDB_INVALID_ADDRESS) 110343181Sdim function_start = sym_addr.GetFileAddress(); 111343181Sdim 112343181Sdim if (function_start) 113343181Sdim current_offset = addr - function_start; 114343181Sdim } 115343181Sdim 116343181Sdim // If breakpoint address is start of function then we dont have to do 117343181Sdim // anything. 118343181Sdim if (current_offset == 0) 119343181Sdim return addr; 120343181Sdim 121343181Sdim ExecutionContext ctx; 122343181Sdim target.CalculateExecutionContext(ctx); 123343181Sdim auto insn = GetInstructionAtAddress(ctx, current_offset, addr); 124343181Sdim 125343181Sdim if (nullptr == insn || !insn->HasDelaySlot()) 126343181Sdim return addr; 127343181Sdim 128343181Sdim // Adjust the breakable address 129343181Sdim uint64_t breakable_addr = addr - insn->GetOpcode().GetByteSize(); 130360784Sdim LLDB_LOGF(log, 131360784Sdim "Target::%s Breakpoint at 0x%8.8" PRIx64 132360784Sdim " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", 133360784Sdim __FUNCTION__, addr, breakable_addr); 134343181Sdim 135343181Sdim return breakable_addr; 136343181Sdim} 137343181Sdim 138343181SdimInstruction *ArchitectureMips::GetInstructionAtAddress( 139343181Sdim const ExecutionContext &exe_ctx, const Address &resolved_addr, 140343181Sdim addr_t symbol_offset) const { 141343181Sdim 142343181Sdim auto loop_count = symbol_offset / 2; 143343181Sdim 144343181Sdim uint32_t arch_flags = m_arch.GetFlags(); 145343181Sdim bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; 146343181Sdim bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; 147343181Sdim 148343181Sdim if (loop_count > 3) { 149343181Sdim // Scan previous 6 bytes 150343181Sdim if (IsMips16 | IsMicromips) 151343181Sdim loop_count = 3; 152343181Sdim // For mips-only, instructions are always 4 bytes, so scan previous 4 153343181Sdim // bytes only. 154343181Sdim else 155343181Sdim loop_count = 2; 156343181Sdim } 157343181Sdim 158343181Sdim // Create Disassembler Instance 159343181Sdim lldb::DisassemblerSP disasm_sp( 160343181Sdim Disassembler::FindPlugin(m_arch, nullptr, nullptr)); 161343181Sdim 162343181Sdim InstructionList instruction_list; 163343181Sdim InstructionSP prev_insn; 164343181Sdim bool prefer_file_cache = true; // Read from file 165343181Sdim uint32_t inst_to_choose = 0; 166343181Sdim 167343181Sdim Address addr = resolved_addr; 168343181Sdim 169343181Sdim for (uint32_t i = 1; i <= loop_count; i++) { 170343181Sdim // Adjust the address to read from. 171343181Sdim addr.Slide(-2); 172343181Sdim AddressRange range(addr, i * 2); 173343181Sdim uint32_t insn_size = 0; 174343181Sdim 175343181Sdim disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); 176343181Sdim 177343181Sdim uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); 178343181Sdim if (num_insns) { 179343181Sdim prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); 180343181Sdim insn_size = prev_insn->GetOpcode().GetByteSize(); 181343181Sdim if (i == 1 && insn_size == 2) { 182343181Sdim // This looks like a valid 2-byte instruction (but it could be a part 183343181Sdim // of upper 4 byte instruction). 184343181Sdim instruction_list.Append(prev_insn); 185343181Sdim inst_to_choose = 1; 186343181Sdim } 187343181Sdim else if (i == 2) { 188343181Sdim // Here we may get one 4-byte instruction or two 2-byte instructions. 189343181Sdim if (num_insns == 2) { 190343181Sdim // Looks like there are two 2-byte instructions above our 191343181Sdim // breakpoint target address. Now the upper 2-byte instruction is 192343181Sdim // either a valid 2-byte instruction or could be a part of it's 193343181Sdim // upper 4-byte instruction. In both cases we don't care because in 194343181Sdim // this case lower 2-byte instruction is definitely a valid 195343181Sdim // instruction and whatever i=1 iteration has found out is true. 196343181Sdim inst_to_choose = 1; 197343181Sdim break; 198343181Sdim } 199343181Sdim else if (insn_size == 4) { 200343181Sdim // This instruction claims its a valid 4-byte instruction. But it 201343181Sdim // could be a part of it's upper 4-byte instruction. Lets try 202343181Sdim // scanning upper 2 bytes to verify this. 203343181Sdim instruction_list.Append(prev_insn); 204343181Sdim inst_to_choose = 2; 205343181Sdim } 206343181Sdim } 207343181Sdim else if (i == 3) { 208343181Sdim if (insn_size == 4) 209343181Sdim // FIXME: We reached here that means instruction at [target - 4] has 210343181Sdim // already claimed to be a 4-byte instruction, and now instruction 211343181Sdim // at [target - 6] is also claiming that it's a 4-byte instruction. 212343181Sdim // This can not be true. In this case we can not decide the valid 213343181Sdim // previous instruction so we let lldb set the breakpoint at the 214343181Sdim // address given by user. 215343181Sdim inst_to_choose = 0; 216343181Sdim else 217343181Sdim // This is straight-forward 218343181Sdim inst_to_choose = 2; 219343181Sdim break; 220343181Sdim } 221343181Sdim } 222343181Sdim else { 223343181Sdim // Decode failed, bytes do not form a valid instruction. So whatever 224343181Sdim // previous iteration has found out is true. 225343181Sdim if (i > 1) { 226343181Sdim inst_to_choose = i - 1; 227343181Sdim break; 228343181Sdim } 229343181Sdim } 230343181Sdim } 231343181Sdim 232343181Sdim // Check if we are able to find any valid instruction. 233343181Sdim if (inst_to_choose) { 234343181Sdim if (inst_to_choose > instruction_list.GetSize()) 235343181Sdim inst_to_choose--; 236343181Sdim return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get(); 237343181Sdim } 238343181Sdim 239343181Sdim return nullptr; 240343181Sdim} 241