Index: include/lldb/Core/Architecture.h =================================================================== --- include/lldb/Core/Architecture.h +++ include/lldb/Core/Architecture.h @@ -67,7 +67,58 @@ virtual void AdjustBreakpointAddress(const Symbol &func, Address &addr) const {} + + //------------------------------------------------------------------ + /// Get \a load_addr as a callable code load address for this target + /// + /// Take \a load_addr and potentially add any address bits that are + /// needed to make the address callable. For ARM this can set bit + /// zero (if it already isn't) if \a load_addr is a thumb function. + /// If \a addr_class is set to AddressClass::eInvalid, then the address + /// adjustment will always happen. If it is set to an address class + /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be + /// returned. + //------------------------------------------------------------------ + static lldb::addr_t GetCallableLoadAddress(Target *target, + lldb::addr_t addr, AddressClass addr_class = AddressClass::eInvalid); + + //------------------------------------------------------------------ + /// Get \a load_addr as an opcode for this target. + /// + /// Take \a load_addr and potentially strip any address bits that are + /// needed to make the address point to an opcode. For ARM this can + /// clear bit zero (if it already isn't) if \a load_addr is a + /// thumb function and load_addr is in code. + /// If \a addr_class is set to AddressClass::eInvalid, then the address + /// adjustment will always happen. If it is set to an address class + /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be + /// returned. + //------------------------------------------------------------------ + static lldb::addr_t GetOpcodeLoadAddress(Target *target, + lldb::addr_t addr, AddressClass addr_class = AddressClass::eInvalid); + + // Get load_addr as breakable load address for this target. Take a addr and + // check if for any reason there is a better address than this to put a + // breakpoint on. If there is then return that address. For MIPS, if + // instruction at addr is a delay slot instruction then this method will find + // the address of its previous instruction and return that address. + static lldb::addr_t GetBreakableLoadAddress(Target *, lldb::addr_t addr); + private: + virtual lldb::addr_t DoGetCallableLoadAddress(lldb::addr_t addr, + bool is_alternate_isa) const { + return addr; + } + + virtual lldb::addr_t DoGetOpcodeLoadAddress(lldb::addr_t addr) const { + return addr; + } + + virtual lldb::addr_t DoGetBreakableLoadAddress(lldb::addr_t addr, + Target &) const { + return addr; + } + Architecture(const Architecture &) = delete; void operator=(const Architecture &) = delete; }; Index: include/lldb/Target/Target.h =================================================================== --- include/lldb/Target/Target.h +++ include/lldb/Target/Target.h @@ -726,44 +726,6 @@ std::vector &names, BreakpointIDList &new_bps); - //------------------------------------------------------------------ - /// Get \a load_addr as a callable code load address for this target - /// - /// Take \a load_addr and potentially add any address bits that are - /// needed to make the address callable. For ARM this can set bit - /// zero (if it already isn't) if \a load_addr is a thumb function. - /// If \a addr_class is set to AddressClass::eInvalid, then the address - /// adjustment will always happen. If it is set to an address class - /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be - /// returned. - //------------------------------------------------------------------ - lldb::addr_t GetCallableLoadAddress( - lldb::addr_t load_addr, - AddressClass addr_class = AddressClass::eInvalid) const; - - //------------------------------------------------------------------ - /// Get \a load_addr as an opcode for this target. - /// - /// Take \a load_addr and potentially strip any address bits that are - /// needed to make the address point to an opcode. For ARM this can - /// clear bit zero (if it already isn't) if \a load_addr is a - /// thumb function and load_addr is in code. - /// If \a addr_class is set to AddressClass::eInvalid, then the address - /// adjustment will always happen. If it is set to an address class - /// that doesn't have code in it, LLDB_INVALID_ADDRESS will be - /// returned. - //------------------------------------------------------------------ - lldb::addr_t GetOpcodeLoadAddress( - lldb::addr_t load_addr, - AddressClass addr_class = AddressClass::eInvalid) const; - - // Get load_addr as breakable load address for this target. Take a addr and - // check if for any reason there is a better address than this to put a - // breakpoint on. If there is then return that address. For MIPS, if - // instruction at addr is a delay slot instruction then this method will find - // the address of its previous instruction and return that address. - lldb::addr_t GetBreakableLoadAddress(lldb::addr_t addr); - void ModulesDidLoad(ModuleList &module_list); void ModulesDidUnload(ModuleList &module_list, bool delete_locations); Index: source/Core/Address.cpp =================================================================== --- source/Core/Address.cpp +++ source/Core/Address.cpp @@ -333,43 +333,39 @@ if (code_addr == LLDB_INVALID_ADDRESS) return code_addr; - if (target) - return target->GetCallableLoadAddress(code_addr, GetAddressClass()); - return code_addr; + Architecture::GetCallableLoadAddress(target, code_addr, GetAddressClass()); } bool Address::SetCallableLoadAddress(lldb::addr_t load_addr, Target *target) { - if (SetLoadAddress(load_addr, target)) { - if (target) - m_offset = target->GetCallableLoadAddress(m_offset, GetAddressClass()); - return true; - } - return false; + if (!SetLoadAddress(load_addr, target)) + return false; + + m_offset = Architecture::GetCallableLoadAddress( + target, m_offset, GetAddressClass()); + return true; } addr_t Address::GetOpcodeLoadAddress(Target *target, AddressClass addr_class) const { addr_t code_addr = GetLoadAddress(target); - if (code_addr != LLDB_INVALID_ADDRESS) { - if (addr_class == AddressClass::eInvalid) - addr_class = GetAddressClass(); - code_addr = target->GetOpcodeLoadAddress(code_addr, addr_class); - } - return code_addr; + if (code_addr == LLDB_INVALID_ADDRESS) { + return code_addr; + + if (addr_class == AddressClass::eInvalid) + addr_class = GetAddressClass(); + return Architecture::GetOpcodeLoadAddress(target, code_addr, addr_class); } bool Address::SetOpcodeLoadAddress(lldb::addr_t load_addr, Target *target, AddressClass addr_class, bool allow_section_end) { - if (SetLoadAddress(load_addr, target, allow_section_end)) { - if (target) { - if (addr_class == AddressClass::eInvalid) - addr_class = GetAddressClass(); - m_offset = target->GetOpcodeLoadAddress(m_offset, addr_class); - } - return true; - } - return false; + if (!SetLoadAddress(load_addr, target, allow_section_end)) + return false; + + if (addr_class == AddressClass::eInvalid) + addr_class = GetAddressClass(); + m_offset = Architecture::GetOpcodeLoadAddress(target, m_offset, addr_class); + return true; } bool Address::Dump(Stream *s, ExecutionContextScope *exe_scope, DumpStyle style, Index: source/Core/Architecture.cpp =================================================================== --- /dev/null +++ source/Core/Architecture.cpp @@ -0,0 +1,53 @@ +//===-- Architecture.cpp ---------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "lldb/Core/Architecture.h" +#include "lldb/Target/Target.h" + +namespace lldb_private { +lldb::addr_t Architecture::GetCallableLoadAddress(Target *target, + lldb::addr_t code_addr, AddressClass addr_class) { + bool alternate_isa = false; + + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + case AddressClass::eCodeAlternateISA: + alternate_isa = true; + break; + default: break; + } + + auto arch = target->GetArchitecturePlugin(); + return nullptr == arch || nullptr == target ? + code_addr : arch->DoGetCallableLoadAddress(code_addr, alternate_isa); +} + +lldb::addr_t Architecture::GetOpcodeLoadAddress(Target *target, + lldb::addr_t opcode_addr, AddressClass addr_class) { + switch (addr_class) { + case AddressClass::eData: + case AddressClass::eDebug: + return LLDB_INVALID_ADDRESS; + default: break; + } + + auto arch = target->GetArchitecturePlugin(); + return nullptr == arch || nullptr == target ? + opcode_addr : arch->DoGetOpcodeLoadAddress(opcode_addr); +} + +lldb::addr_t Architecture::GetBreakableLoadAddress(Target *target, + lldb::addr_t brk_addr) { + auto arch = target->GetArchitecturePlugin(); + return nullptr == arch || nullptr == target ? + brk_addr : arch->DoGetBreakableLoadAddress(brk_addr, *target); +} +} // namespace lldb_private \ No newline at end of file Index: source/Core/CMakeLists.txt =================================================================== --- source/Core/CMakeLists.txt +++ source/Core/CMakeLists.txt @@ -13,6 +13,7 @@ AddressResolver.cpp AddressResolverFileLine.cpp AddressResolverName.cpp + Architecture.cpp Broadcaster.cpp Communication.cpp Debugger.cpp Index: source/Plugins/Architecture/Arm/ArchitectureArm.h =================================================================== --- source/Plugins/Architecture/Arm/ArchitectureArm.h +++ source/Plugins/Architecture/Arm/ArchitectureArm.h @@ -26,6 +26,11 @@ void OverrideStopInfo(Thread &thread) const override; private: + lldb::addr_t DoGetCallableLoadAddress(lldb::addr_t load_addr, + bool is_alternate_isa) const override; + + lldb::addr_t DoGetOpcodeLoadAddress(lldb::addr_t load_addr) const override; + static std::unique_ptr Create(const ArchSpec &arch); ArchitectureArm() = default; }; Index: source/Plugins/Architecture/Arm/ArchitectureArm.cpp =================================================================== --- source/Plugins/Architecture/Arm/ArchitectureArm.cpp +++ source/Plugins/Architecture/Arm/ArchitectureArm.cpp @@ -126,3 +126,14 @@ } } } + +addr_t ArchitectureArm::DoGetCallableLoadAddress(addr_t code_addr, + bool is_alternate_isa) const { + if ((code_addr & 2u) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureArm::DoGetOpcodeLoadAddress(addr_t opcode_addr) const { + return opcode_addr & ~(1ull); +} \ No newline at end of file Index: source/Plugins/Architecture/CMakeLists.txt =================================================================== --- source/Plugins/Architecture/CMakeLists.txt +++ source/Plugins/Architecture/CMakeLists.txt @@ -1,2 +1,3 @@ add_subdirectory(Arm) +add_subdirectory(Mips) add_subdirectory(PPC64) Index: source/Plugins/Architecture/Mips/ArchitectureMips.h =================================================================== --- /dev/null +++ source/Plugins/Architecture/Mips/ArchitectureMips.h @@ -0,0 +1,51 @@ +//===-- ArchitectureMips.h ---------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#ifndef LLDB_PLUGIN_ARCHITECTURE_MIPS_H +#define LLDB_PLUGIN_ARCHITECTURE_MIPS_H + +#include "lldb/Core/Architecture.h" +#include "lldb/Utility/ArchSpec.h" + +namespace lldb_private { + +class ArchitectureMips : public Architecture { +public: + static ConstString GetPluginNameStatic(); + static void Initialize(); + static void Terminate(); + + ConstString GetPluginName() override; + uint32_t GetPluginVersion() override; + + void OverrideStopInfo(Thread &thread) const override {} + +private: + lldb::addr_t DoGetBreakableLoadAddress(lldb::addr_t addr, + Target &) const override; + + lldb::addr_t DoGetCallableLoadAddress(lldb::addr_t load_addr, + bool is_alternate_isa) const override; + + lldb::addr_t DoGetOpcodeLoadAddress(lldb::addr_t load_addr) const override; + + Instruction *GetInstructionAtAddress(const ExecutionContext &exe_ctx, + const Address &resolved_addr, + lldb::addr_t symbol_offset) const; + + + static std::unique_ptr Create(const ArchSpec &arch); + ArchitectureMips(const ArchSpec &arch) : m_arch(arch) {} + + ArchSpec m_arch; +}; + +} // namespace lldb_private + +#endif // LLDB_PLUGIN_ARCHITECTURE_MIPS_H Index: source/Plugins/Architecture/Mips/ArchitectureMips.cpp =================================================================== --- /dev/null +++ source/Plugins/Architecture/Mips/ArchitectureMips.cpp @@ -0,0 +1,221 @@ +//===-- ArchitectureMips.cpp -------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +#include "Plugins/Architecture/Mips/ArchitectureMips.h" +#include "lldb/Core/Address.h" +#include "lldb/Core/Disassembler.h" +#include "lldb/Core/Module.h" +#include "lldb/Core/PluginManager.h" +#include "lldb/Symbol/Function.h" +#include "lldb/Symbol/SymbolContext.h" +#include "lldb/Target/SectionLoadList.h" +#include "lldb/Target/Target.h" +#include "lldb/Utility/ArchSpec.h" +#include "lldb/Utility/Log.h" + +using namespace lldb_private; +using namespace lldb; + +ConstString ArchitectureMips::GetPluginNameStatic() { + return ConstString("mips"); +} + +void ArchitectureMips::Initialize() { + PluginManager::RegisterPlugin(GetPluginNameStatic(), + "Mips-specific algorithms", + &ArchitectureMips::Create); +} + +void ArchitectureMips::Terminate() { + PluginManager::UnregisterPlugin(&ArchitectureMips::Create); +} + +std::unique_ptr ArchitectureMips::Create(const ArchSpec &arch) { + return arch.IsMIPS() ? + std::unique_ptr(new ArchitectureMips(arch)) : nullptr; +} + +ConstString ArchitectureMips::GetPluginName() { return GetPluginNameStatic(); } +uint32_t ArchitectureMips::GetPluginVersion() { return 1; } + +addr_t ArchitectureMips::DoGetCallableLoadAddress(addr_t code_addr, + bool is_alternate_isa) const { + if ((code_addr & 2ull) || is_alternate_isa) + return code_addr | 1u; + return code_addr; +} + +addr_t ArchitectureMips::DoGetOpcodeLoadAddress(addr_t opcode_addr) const { + return opcode_addr & ~(1ull); +} + +lldb::addr_t ArchitectureMips::DoGetBreakableLoadAddress(lldb::addr_t addr, + Target &target) const { + + Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); + + Address resolved_addr; + + SectionLoadList §ion_load_list = target.GetSectionLoadList(); + if (section_load_list.IsEmpty()) + // No sections are loaded, so we must assume we are not running yet and + // need to operate only on file address. + target.ResolveFileAddress(addr, resolved_addr); + else + target.ResolveLoadAddress(addr, resolved_addr); + + addr_t current_offset = 0; + + // Get the function boundaries to make sure we don't scan back before the + // beginning of the current function. + ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); + if (temp_addr_module_sp) { + SymbolContext sc; + uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; + temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, + resolve_scope, sc); + Address sym_addr; + if (sc.function) + sym_addr = sc.function->GetAddressRange().GetBaseAddress(); + else if (sc.symbol) + sym_addr = sc.symbol->GetAddress(); + + addr_t function_start = sym_addr.GetLoadAddress(&target); + if (function_start == LLDB_INVALID_ADDRESS) + function_start = sym_addr.GetFileAddress(); + + if (function_start) + current_offset = addr - function_start; + } + + // If breakpoint address is start of function then we dont have to do + // anything. + if (current_offset == 0) + return addr; + + ExecutionContext ctx; + target.CalculateExecutionContext(ctx); + auto insn = GetInstructionAtAddress(ctx, current_offset, addr); + + if (nullptr == insn || !insn->HasDelaySlot()) + return addr; + + // Adjust the breakable address + auto breakable_addr = addr - insn->GetOpcode().GetByteSize(); + if (log) + log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64 + " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", + __FUNCTION__, addr, breakable_addr); + + return breakable_addr; +} + +Instruction *ArchitectureMips::GetInstructionAtAddress( + const ExecutionContext &exe_ctx, const Address &resolved_addr, + addr_t symbol_offset) const { + + auto loop_count = symbol_offset / 2; + + uint32_t arch_flags = m_arch.GetFlags(); + bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; + bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; + + if (loop_count > 3) { + // Scan previous 6 bytes + if (IsMips16 | IsMicromips) + loop_count = 3; + // For mips-only, instructions are always 4 bytes, so scan previous 4 + // bytes only. + else + loop_count = 2; + } + + // Create Disassembler Instance + lldb::DisassemblerSP disasm_sp( + Disassembler::FindPlugin(m_arch, nullptr, nullptr)); + + InstructionList instruction_list; + InstructionSP prev_insn; + bool prefer_file_cache = true; // Read from file + uint32_t inst_to_choose = 0; + + Address addr = resolved_addr; + + for (uint32_t i = 1; i <= loop_count; i++) { + // Adjust the address to read from. + addr.Slide(-2); + AddressRange range(addr, i * 2); + uint32_t insn_size = 0; + + disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); + + uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); + if (num_insns) { + prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); + insn_size = prev_insn->GetOpcode().GetByteSize(); + if (i == 1 && insn_size == 2) { + // This looks like a valid 2-byte instruction (but it could be a part + // of upper 4 byte instruction). + instruction_list.Append(prev_insn); + inst_to_choose = 1; + } + else if (i == 2) { + // Here we may get one 4-byte instruction or two 2-byte instructions. + if (num_insns == 2) { + // Looks like there are two 2-byte instructions above our + // breakpoint target address. Now the upper 2-byte instruction is + // either a valid 2-byte instruction or could be a part of it's + // upper 4-byte instruction. In both cases we don't care because in + // this case lower 2-byte instruction is definitely a valid + // instruction and whatever i=1 iteration has found out is true. + inst_to_choose = 1; + break; + } + else if (insn_size == 4) { + // This instruction claims its a valid 4-byte instruction. But it + // could be a part of it's upper 4-byte instruction. Lets try + // scanning upper 2 bytes to verify this. + instruction_list.Append(prev_insn); + inst_to_choose = 2; + } + } + else if (i == 3) { + if (insn_size == 4) + // FIXME: We reached here that means instruction at [target - 4] has + // already claimed to be a 4-byte instruction, and now instruction + // at [target - 6] is also claiming that it's a 4-byte instruction. + // This can not be true. In this case we can not decide the valid + // previous instruction so we let lldb set the breakpoint at the + // address given by user. + inst_to_choose = 0; + else + // This is straight-forward + inst_to_choose = 2; + break; + } + } + else { + // Decode failed, bytes do not form a valid instruction. So whatever + // previous iteration has found out is true. + if (i > 1) { + inst_to_choose = i - 1; + break; + } + } + } + + // Check if we are able to find any valid instruction. + if (inst_to_choose) { + if (inst_to_choose > instruction_list.GetSize()) + inst_to_choose--; + return instruction_list.GetInstructionAtIndex(inst_to_choose - 1).get(); + } + + return nullptr; +} Index: source/Plugins/Architecture/Mips/CMakeLists.txt =================================================================== --- /dev/null +++ source/Plugins/Architecture/Mips/CMakeLists.txt @@ -0,0 +1,10 @@ +add_lldb_library(lldbPluginArchitectureMips PLUGIN + ArchitectureMips.cpp + + LINK_LIBS + lldbCore + lldbTarget + lldbUtility + LINK_COMPONENTS + Support + ) Index: source/Target/RegisterContext.cpp =================================================================== --- source/Target/RegisterContext.cpp +++ source/Target/RegisterContext.cpp @@ -129,17 +129,12 @@ uint32_t reg = ConvertRegisterKindToRegisterNumber(eRegisterKindGeneric, LLDB_REGNUM_GENERIC_PC); uint64_t pc = ReadRegisterAsUnsigned(reg, fail_value); + if (pc == fail_value) + return pc; - if (pc != fail_value) { - TargetSP target_sp = m_thread.CalculateTarget(); - if (target_sp) { - Target *target = target_sp.get(); - if (target) - pc = target->GetOpcodeLoadAddress(pc, AddressClass::eCode); - } - } - - return pc; + TargetSP target_sp = m_thread.CalculateTarget(); + return Architecture::GetOpcodeLoadAddress(target_sp.get(), + pc, AddressClass::eCode); } bool RegisterContext::SetPC(uint64_t pc) { Index: source/Target/Target.cpp =================================================================== --- source/Target/Target.cpp +++ source/Target/Target.cpp @@ -373,15 +373,14 @@ BreakpointSP Target::CreateBreakpoint(lldb::addr_t addr, bool internal, bool hardware) { - Address so_addr; - // Check for any reason we want to move this breakpoint to other address. - addr = GetBreakableLoadAddress(addr); + addr = Architecture::GetBreakableLoadAddress(this, addr); // Attempt to resolve our load address if possible, though it is ok if it // doesn't resolve to section/offset. // Try and resolve as a load address if possible + Address so_addr; GetSectionLoadList().ResolveLoadAddress(addr, so_addr); if (!so_addr.IsValid()) { // The address didn't resolve, so just set this as an absolute address @@ -2349,253 +2348,6 @@ return address; } -lldb::addr_t Target::GetCallableLoadAddress(lldb::addr_t load_addr, - AddressClass addr_class) const { - addr_t code_addr = load_addr; - switch (m_arch.GetSpec().GetMachine()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; - - case AddressClass::eUnknown: - case AddressClass::eInvalid: - case AddressClass::eCode: - case AddressClass::eCodeAlternateISA: - case AddressClass::eRuntime: - if ((code_addr & 2ull) || (addr_class == AddressClass::eCodeAlternateISA)) - code_addr |= 1ull; - break; - } - break; - - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; - - case AddressClass::eUnknown: - case AddressClass::eInvalid: - case AddressClass::eCode: - case AddressClass::eCodeAlternateISA: - case AddressClass::eRuntime: - // Check if bit zero it no set? - if ((code_addr & 1ull) == 0) { - // Bit zero isn't set, check if the address is a multiple of 2? - if (code_addr & 2ull) { - // The address is a multiple of 2 so it must be thumb, set bit zero - code_addr |= 1ull; - } else if (addr_class == AddressClass::eCodeAlternateISA) { - // We checked the address and the address claims to be the alternate - // ISA which means thumb, so set bit zero. - code_addr |= 1ull; - } - } - break; - } - break; - - default: - break; - } - return code_addr; -} - -lldb::addr_t Target::GetOpcodeLoadAddress(lldb::addr_t load_addr, - AddressClass addr_class) const { - addr_t opcode_addr = load_addr; - switch (m_arch.GetSpec().GetMachine()) { - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: - case llvm::Triple::arm: - case llvm::Triple::thumb: - switch (addr_class) { - case AddressClass::eData: - case AddressClass::eDebug: - return LLDB_INVALID_ADDRESS; - - case AddressClass::eInvalid: - case AddressClass::eUnknown: - case AddressClass::eCode: - case AddressClass::eCodeAlternateISA: - case AddressClass::eRuntime: - opcode_addr &= ~(1ull); - break; - } - break; - - default: - break; - } - return opcode_addr; -} - -lldb::addr_t Target::GetBreakableLoadAddress(lldb::addr_t addr) { - addr_t breakable_addr = addr; - Log *log(lldb_private::GetLogIfAllCategoriesSet(LIBLLDB_LOG_BREAKPOINTS)); - - switch (m_arch.GetSpec().GetMachine()) { - default: - break; - case llvm::Triple::mips: - case llvm::Triple::mipsel: - case llvm::Triple::mips64: - case llvm::Triple::mips64el: { - addr_t function_start = 0; - addr_t current_offset = 0; - uint32_t loop_count = 0; - Address resolved_addr; - uint32_t arch_flags = m_arch.GetSpec().GetFlags(); - bool IsMips16 = arch_flags & ArchSpec::eMIPSAse_mips16; - bool IsMicromips = arch_flags & ArchSpec::eMIPSAse_micromips; - SectionLoadList §ion_load_list = GetSectionLoadList(); - - if (section_load_list.IsEmpty()) - // No sections are loaded, so we must assume we are not running yet and - // need to operate only on file address. - m_images.ResolveFileAddress(addr, resolved_addr); - else - section_load_list.ResolveLoadAddress(addr, resolved_addr); - - // Get the function boundaries to make sure we don't scan back before the - // beginning of the current function. - ModuleSP temp_addr_module_sp(resolved_addr.GetModule()); - if (temp_addr_module_sp) { - SymbolContext sc; - uint32_t resolve_scope = eSymbolContextFunction | eSymbolContextSymbol; - temp_addr_module_sp->ResolveSymbolContextForAddress(resolved_addr, - resolve_scope, sc); - Address sym_addr; - if (sc.function) - sym_addr = sc.function->GetAddressRange().GetBaseAddress(); - else if (sc.symbol) - sym_addr = sc.symbol->GetAddress(); - - function_start = sym_addr.GetLoadAddress(this); - if (function_start == LLDB_INVALID_ADDRESS) - function_start = sym_addr.GetFileAddress(); - - if (function_start) - current_offset = addr - function_start; - } - - // If breakpoint address is start of function then we dont have to do - // anything. - if (current_offset == 0) - return breakable_addr; - else - loop_count = current_offset / 2; - - if (loop_count > 3) { - // Scan previous 6 bytes - if (IsMips16 | IsMicromips) - loop_count = 3; - // For mips-only, instructions are always 4 bytes, so scan previous 4 - // bytes only. - else - loop_count = 2; - } - - // Create Disassembler Instance - lldb::DisassemblerSP disasm_sp( - Disassembler::FindPlugin(m_arch.GetSpec(), nullptr, nullptr)); - - ExecutionContext exe_ctx; - CalculateExecutionContext(exe_ctx); - InstructionList instruction_list; - InstructionSP prev_insn; - bool prefer_file_cache = true; // Read from file - uint32_t inst_to_choose = 0; - - for (uint32_t i = 1; i <= loop_count; i++) { - // Adjust the address to read from. - resolved_addr.Slide(-2); - AddressRange range(resolved_addr, i * 2); - uint32_t insn_size = 0; - - disasm_sp->ParseInstructions(&exe_ctx, range, nullptr, prefer_file_cache); - - uint32_t num_insns = disasm_sp->GetInstructionList().GetSize(); - if (num_insns) { - prev_insn = disasm_sp->GetInstructionList().GetInstructionAtIndex(0); - insn_size = prev_insn->GetOpcode().GetByteSize(); - if (i == 1 && insn_size == 2) { - // This looks like a valid 2-byte instruction (but it could be a part - // of upper 4 byte instruction). - instruction_list.Append(prev_insn); - inst_to_choose = 1; - } else if (i == 2) { - // Here we may get one 4-byte instruction or two 2-byte instructions. - if (num_insns == 2) { - // Looks like there are two 2-byte instructions above our - // breakpoint target address. Now the upper 2-byte instruction is - // either a valid 2-byte instruction or could be a part of it's - // upper 4-byte instruction. In both cases we don't care because in - // this case lower 2-byte instruction is definitely a valid - // instruction and whatever i=1 iteration has found out is true. - inst_to_choose = 1; - break; - } else if (insn_size == 4) { - // This instruction claims its a valid 4-byte instruction. But it - // could be a part of it's upper 4-byte instruction. Lets try - // scanning upper 2 bytes to verify this. - instruction_list.Append(prev_insn); - inst_to_choose = 2; - } - } else if (i == 3) { - if (insn_size == 4) - // FIXME: We reached here that means instruction at [target - 4] has - // already claimed to be a 4-byte instruction, and now instruction - // at [target - 6] is also claiming that it's a 4-byte instruction. - // This can not be true. In this case we can not decide the valid - // previous instruction so we let lldb set the breakpoint at the - // address given by user. - inst_to_choose = 0; - else - // This is straight-forward - inst_to_choose = 2; - break; - } - } else { - // Decode failed, bytes do not form a valid instruction. So whatever - // previous iteration has found out is true. - if (i > 1) { - inst_to_choose = i - 1; - break; - } - } - } - - // Check if we are able to find any valid instruction. - if (inst_to_choose) { - if (inst_to_choose > instruction_list.GetSize()) - inst_to_choose--; - prev_insn = instruction_list.GetInstructionAtIndex(inst_to_choose - 1); - - if (prev_insn->HasDelaySlot()) { - uint32_t shift_size = prev_insn->GetOpcode().GetByteSize(); - // Adjust the breakable address - breakable_addr = addr - shift_size; - if (log) - log->Printf("Target::%s Breakpoint at 0x%8.8" PRIx64 - " is adjusted to 0x%8.8" PRIx64 " due to delay slot\n", - __FUNCTION__, addr, breakable_addr); - } - } - break; - } - } - return breakable_addr; -} - SourceManager &Target::GetSourceManager() { if (!m_source_manager_ap) m_source_manager_ap.reset(new SourceManager(shared_from_this())); Index: source/Target/ThreadPlanRunToAddress.cpp =================================================================== --- source/Target/ThreadPlanRunToAddress.cpp +++ source/Target/ThreadPlanRunToAddress.cpp @@ -42,8 +42,8 @@ : ThreadPlan(ThreadPlan::eKindRunToAddress, "Run to address plan", thread, eVoteNoOpinion, eVoteNoOpinion), m_stop_others(stop_others), m_addresses(), m_break_ids() { - m_addresses.push_back( - m_thread.CalculateTarget()->GetOpcodeLoadAddress(address)); + Target &target = thread.GetProcess()->GetTarget(); + m_addresses.push_back(Architecture::GetOpcodeLoadAddress(&target, address)); SetInitialBreakpoints(); } @@ -56,9 +56,8 @@ // Convert all addresses into opcode addresses to make sure we set // breakpoints at the correct address. Target &target = thread.GetProcess()->GetTarget(); - std::vector::iterator pos, end = m_addresses.end(); - for (pos = m_addresses.begin(); pos != end; ++pos) - *pos = target.GetOpcodeLoadAddress(*pos); + for (auto &addr : m_addresses) + addr = Architecture::GetOpcodeLoadAddress(&target, addr); SetInitialBreakpoints(); }